Refactor collectors

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke
2023-11-04 20:51:35 +01:00
parent 569f5450cd
commit 0711268d3c
207 changed files with 15220 additions and 13648 deletions

View File

@@ -0,0 +1,124 @@
//go:build windows
// +build windows
// Package eventlog provides a Logger that writes to Windows Event Log.
package eventlog
import (
"bytes"
"fmt"
"io"
"sync"
"syscall"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"golang.org/x/sys/windows"
goeventlog "golang.org/x/sys/windows/svc/eventlog"
)
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)
)
type Priority struct {
etype int
}
// NewEventLogLogger returns a new Logger which writes to Windows EventLog in event log format.
// The body of the log message is the formatted output from the Logger returned
// by newLogger.
func NewEventLogLogger(w *goeventlog.Log, newLogger func(io.Writer) log.Logger) log.Logger {
l := &eventlogLogger{
w: w,
newLogger: newLogger,
prioritySelector: defaultPrioritySelector,
bufPool: sync.Pool{New: func() interface{} {
return &loggerBuf{}
}},
}
return l
}
type eventlogLogger struct {
w *goeventlog.Log
newLogger func(io.Writer) log.Logger
prioritySelector PrioritySelector
bufPool sync.Pool
}
func (l *eventlogLogger) Log(keyvals ...interface{}) error {
priority := l.prioritySelector(keyvals...)
lb := l.getLoggerBuf()
defer l.putLoggerBuf(lb)
if err := lb.logger.Log(keyvals...); err != nil {
return err
}
// golang.org/x/sys/windows/svc/eventlog does not provide func which allows to send more than one string.
// See: https://github.com/golang/go/issues/59780
msg, err := syscall.UTF16PtrFromString(lb.buf.String())
if err != nil {
return fmt.Errorf("error convert string to UTF-16: %v", err)
}
ss := []*uint16{msg, nil, nil, nil, nil, nil, nil, nil, nil}
return windows.ReportEvent(l.w.Handle, uint16(priority.etype), 0, neLogOemCode, 0, 9, 0, &ss[0], nil)
}
type loggerBuf struct {
buf *bytes.Buffer
logger log.Logger
}
func (l *eventlogLogger) getLoggerBuf() *loggerBuf {
lb := l.bufPool.Get().(*loggerBuf)
if lb.buf == nil {
lb.buf = &bytes.Buffer{}
lb.logger = l.newLogger(lb.buf)
} else {
lb.buf.Reset()
}
return lb
}
func (l *eventlogLogger) putLoggerBuf(lb *loggerBuf) {
l.bufPool.Put(lb)
}
// PrioritySelector inspects the list of keyvals and selects an eventlog priority.
type PrioritySelector func(keyvals ...interface{}) Priority
// defaultPrioritySelector convert a kit/log level into a Windows Eventlog level
func defaultPrioritySelector(keyvals ...interface{}) Priority {
l := len(keyvals)
eType := windows.EVENTLOG_SUCCESS
for i := 0; i < l; i += 2 {
if keyvals[i] == level.Key() {
var val interface{}
if i+1 < l {
val = keyvals[i+1]
}
if v, ok := val.(level.Value); ok {
switch v {
case level.ErrorValue():
eType = windows.EVENTLOG_ERROR_TYPE
case level.WarnValue():
eType = windows.EVENTLOG_WARNING_TYPE
case level.InfoValue():
eType = windows.EVENTLOG_INFORMATION_TYPE
}
}
}
}
return Priority{etype: eType}
}

43
pkg/log/flag/flag.go Normal file
View File

@@ -0,0 +1,43 @@
// Copyright 2017 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package flag
import (
"github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/pkg/log"
"github.com/prometheus/common/promlog"
promlogflag "github.com/prometheus/common/promlog/flag"
)
// FileFlagName is the canonical flag name to configure the log file
const FileFlagName = "log.file"
// FileFlagHelp is the help description for the log.file flag.
const FileFlagHelp = "Output file of log messages. One of [stdout, stderr, eventlog, <path to log file>]"
// AddFlags adds the flags used by this package to the Kingpin application.
// To use the default Kingpin application, call AddFlags(kingpin.CommandLine)
func AddFlags(a *kingpin.Application, config *log.Config) {
config.Level = &promlog.AllowedLevel{}
a.Flag(promlogflag.LevelFlagName, promlogflag.LevelFlagHelp).
Default("info").SetValue(config.Level)
config.File = &log.AllowedFile{}
a.Flag(FileFlagName, FileFlagHelp).
Default("stderr").SetValue(config.File)
config.Format = &promlog.AllowedFormat{}
a.Flag(promlogflag.FormatFlagName, promlogflag.FormatFlagHelp).
Default("logfmt").SetValue(config.Format)
}

93
pkg/log/logger.go Normal file
View File

@@ -0,0 +1,93 @@
package log
import (
"errors"
"fmt"
"io"
"os"
"github.com/go-kit/log"
"github.com/prometheus-community/windows_exporter/pkg/log/eventlog"
"github.com/prometheus/common/promlog"
goeventlog "golang.org/x/sys/windows/svc/eventlog"
)
// AllowedFile is a settable identifier for the output file that the logger can have.
type AllowedFile struct {
s string
w io.Writer
}
func (f *AllowedFile) String() string {
return f.s
}
// Set updates the value of the allowed format.
func (f *AllowedFile) Set(s string) error {
f.s = s
switch s {
case "stdout":
f.w = os.Stdout
case "stderr":
f.w = os.Stderr
case "eventlog":
f.w = nil
default:
file, err := os.OpenFile(s, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0200)
if err != nil {
return err
}
f.w = file
}
return nil
}
// Config is a struct containing configurable settings for the logger
type Config struct {
promlog.Config
File *AllowedFile
}
func New(config *Config) (log.Logger, error) {
if config.File == nil {
return nil, errors.New("log file undefined")
}
if config.Format == nil {
return nil, errors.New("log format undefined")
}
var (
l log.Logger
loggerFunc func(io.Writer) log.Logger
)
switch config.Format.String() {
case "json":
loggerFunc = log.NewJSONLogger
case "logfmt":
loggerFunc = log.NewLogfmtLogger
default:
return nil, fmt.Errorf("unsupported log.format %q", config.Format.String())
}
if config.File.s == "eventlog" {
w, err := goeventlog.Open("windows_exporter")
if err != nil {
return nil, err
}
l = eventlog.NewEventLogLogger(w, loggerFunc)
} else if config.File.w == nil {
panic("logger: file writer is nil")
} else {
l = loggerFunc(log.NewSyncWriter(config.File.w))
}
promlogConfig := promlog.Config{
Format: config.Format,
Level: config.Level,
}
return promlog.NewWithLogger(l, &promlogConfig), nil
}