Skip to content

Commit

Permalink
feat: windows_exporter uses own event log source to correctly format …
Browse files Browse the repository at this point in the history
…messages. (#1873)

Signed-off-by: Jan-Otto Kröpke <[email protected]>
Signed-off-by: Jan-Otto Kröpke <[email protected]>
  • Loading branch information
jkroepke authored Feb 10, 2025
1 parent f07aceb commit 285c4cc
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 40 deletions.
16 changes: 8 additions & 8 deletions cmd/windows_exporter/0_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,23 +126,23 @@ func (s *windowsExporterService) Execute(_ []string, r <-chan svc.ChangeRequest,

// logToEventToLog logs a message to the Windows event log.
func logToEventToLog(eType uint16, msg string) error {
eventLog, err := eventlog.Open("windows_exporter")
eventLog, err := eventlog.Open(serviceName)
if err != nil {
return fmt.Errorf("failed to open event log: %w", err)
}
defer func(eventLog *eventlog.Log) {
_ = eventLog.Close()
}(eventLog)

p, err := windows.UTF16PtrFromString(msg)
if err != nil {
return fmt.Errorf("error convert string to UTF-16: %w", err)
switch eType {
case windows.EVENTLOG_ERROR_TYPE:
err = eventLog.Error(102, msg)
case windows.EVENTLOG_WARNING_TYPE:
err = eventLog.Warning(101, msg)
case windows.EVENTLOG_INFORMATION_TYPE:
err = eventLog.Info(100, msg)
}

zero := uint16(0)
ss := []*uint16{p, &zero, &zero, &zero, &zero, &zero, &zero, &zero, &zero}

err = windows.ReportEvent(eventLog.Handle, eType, 0, 3299, 0, 9, 0, &ss[0], nil)
if err != nil {
return fmt.Errorf("error report event: %w", err)
}
Expand Down
6 changes: 6 additions & 0 deletions installer/files.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
<ServiceDependency Id="wmiApSrv" />
</ServiceInstall>
<ServiceControl Id="ServiceStateControl" Name="windows_exporter" Remove="uninstall" Start="install" Stop="both"/>
<!-- The "Name" field must match the argument to eventlog.Open() -->
<util:EventSource Log="Application" Name="windows_exporter"
EventMessageFile="%SystemRoot%\System32\EventCreate.exe"
SupportsErrors="yes"
SupportsInformationals="yes"
SupportsWarnings="yes"/>
</Component>
<Component Id="CreateTextfileDirectory" Directory="textfile_inputs" Guid="d03ef58a-9cbf-4165-ad39-d143e9b27e14">
<CreateFolder />
Expand Down
46 changes: 17 additions & 29 deletions internal/log/eventlog/eventlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,53 +17,41 @@
package eventlog

import (
"bytes"
"fmt"
"io"
"regexp"
"strings"

"golang.org/x/sys/windows"
)

const (
// NeLogOemCode is a generic error log entry for OEMs to use to
// elog errors from OEM value added services.
// See: https://github.com/microsoft/win32metadata/blob/2f3c5282ce1024a712aeccd90d3aa50bf7a49e27/generation/WinSDK/RecompiledIdlHeaders/um/LMErrlog.h#L824-L845
NeLogOemCode = uint32(3299)
"golang.org/x/sys/windows/svc/eventlog"
)

// Interface guard.
var _ io.Writer = (*Writer)(nil)

//nolint:gochecknoglobals
var EmptyStringUTF16 uint16
var reStripTimeAndLevel = regexp.MustCompile(`^time=\S+ level=\S+ `)

type Writer struct {
handle windows.Handle
handle *eventlog.Log
}

// NewEventLogWriter returns a new Writer which writes to Windows EventLog.
func NewEventLogWriter(handle windows.Handle) *Writer {
// NewEventLogWriter returns a new Writer, which writes to Windows EventLog.
func NewEventLogWriter(handle *eventlog.Log) *Writer {
return &Writer{handle: handle}
}

func (w *Writer) Write(p []byte) (int, error) {
var eType uint16
var err error

msg := strings.TrimSpace(string(p))
eventLogMsg := reStripTimeAndLevel.ReplaceAllString(msg, "")

switch {
case bytes.Contains(p, []byte(" level=error")) || bytes.Contains(p, []byte(`"level":"error"`)):
eType = windows.EVENTLOG_ERROR_TYPE
case bytes.Contains(p, []byte(" level=warn")) || bytes.Contains(p, []byte(`"level":"warn"`)):
eType = windows.EVENTLOG_WARNING_TYPE
case strings.Contains(msg, " level=ERROR") || strings.Contains(msg, `"level":"error"`):
err = w.handle.Error(102, eventLogMsg)
case strings.Contains(msg, " level=WARN") || strings.Contains(msg, `"level":"warn"`):
err = w.handle.Warning(101, eventLogMsg)
default:
eType = windows.EVENTLOG_INFORMATION_TYPE
err = w.handle.Info(100, eventLogMsg)
}

msg, err := windows.UTF16PtrFromString(string(p))
if err != nil {
return 0, fmt.Errorf("error convert string to UTF-16: %w", err)
}

ss := []*uint16{msg, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16}

return len(p), windows.ReportEvent(w.handle, eType, 0, NeLogOemCode, 0, 9, 0, &ss[0], nil)
return len(p), err
}
6 changes: 3 additions & 3 deletions internal/log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (

"github.com/prometheus-community/windows_exporter/internal/log/eventlog"
"github.com/prometheus/common/promslog"
"golang.org/x/sys/windows"
wineventlog "golang.org/x/sys/windows/svc/eventlog"
)

// AllowedFile is a settable identifier for the output file that the logger can have.
Expand All @@ -51,12 +51,12 @@ func (f *AllowedFile) Set(s string) error {
case "stderr":
f.w = os.Stderr
case "eventlog":
handle, err := windows.RegisterEventSource(nil, windows.StringToUTF16Ptr("windows_exporter"))
eventLog, err := wineventlog.Open("windows_exporter")
if err != nil {
return fmt.Errorf("failed to open event log: %w", err)
}

f.w = eventlog.NewEventLogWriter(handle)
f.w = eventlog.NewEventLogWriter(eventLog)
default:
file, err := os.OpenFile(s, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o200)
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions internal/pdh/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ func NewCollectorWithReflection(resultType CounterType, object string, instances
continue
}

if bufLen == 0 {
errs = append(errs, errors.New("GetCounterInfo: buffer length is zero"))

continue
}

buf := make([]byte, bufLen)
if ret := GetCounterInfo(counterHandle, 0, &bufLen, &buf[0]); ret != ErrorSuccess {
errs = append(errs, fmt.Errorf("GetCounterInfo: %w", NewPdhError(ret)))
Expand Down

0 comments on commit 285c4cc

Please sign in to comment.