feat(inputs.win_eventlog): Add state-persistence capabilities (#12790)
This commit is contained in:
parent
7b2d48e041
commit
0e1b637414
|
|
@ -65,6 +65,10 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
|||
</QueryList>
|
||||
'''
|
||||
|
||||
## When true, event logs are read from the beginning; otherwise only future events
|
||||
## will be logged.
|
||||
# from_beginning = false
|
||||
|
||||
## System field names:
|
||||
## "Source", "EventID", "Version", "Level", "Task", "Opcode", "Keywords", "TimeCreated",
|
||||
## "EventRecordID", "ActivityID", "RelatedActivityID", "ProcessID", "ThreadID", "ProcessName",
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@
|
|||
</QueryList>
|
||||
'''
|
||||
|
||||
## When true, event logs are read from the beginning; otherwise only future events
|
||||
## will be logged.
|
||||
# from_beginning = false
|
||||
|
||||
## System field names:
|
||||
## "Source", "EventID", "Version", "Level", "Task", "Opcode", "Keywords", "TimeCreated",
|
||||
## "EventRecordID", "ActivityID", "RelatedActivityID", "ProcessID", "ThreadID", "ProcessName",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ type EvtSubscribeFlag uint32
|
|||
// EVT_SUBSCRIBE_FLAGS enumeration
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa385588(v=vs.85).aspx
|
||||
const (
|
||||
EvtSubscribeToFutureEvents EvtSubscribeFlag = 1
|
||||
EvtSubscribeToFutureEvents EvtSubscribeFlag = 1
|
||||
EvtSubscribeStartAtOldestRecord EvtSubscribeFlag = 2
|
||||
EvtSubscribeStartAfterBookmark EvtSubscribeFlag = 3
|
||||
)
|
||||
|
||||
// EvtRenderFlag uint32
|
||||
|
|
@ -32,9 +34,9 @@ type EvtRenderFlag uint32
|
|||
// EVT_RENDER_FLAGS enumeration
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa385563(v=vs.85).aspx
|
||||
const (
|
||||
//revive:disable:var-naming
|
||||
// Render the event as an XML string. For details on the contents of the
|
||||
// XML string, see the Event schema.
|
||||
EvtRenderEventXml EvtRenderFlag = 1
|
||||
//revive:enable:var-naming
|
||||
// Render bookmark
|
||||
EvtRenderBookmark EvtRenderFlag = 2
|
||||
)
|
||||
|
|
|
|||
|
|
@ -29,52 +29,102 @@ var sampleConfig string
|
|||
|
||||
// WinEventLog config
|
||||
type WinEventLog struct {
|
||||
Locale uint32 `toml:"locale"`
|
||||
EventlogName string `toml:"eventlog_name"`
|
||||
Query string `toml:"xpath_query"`
|
||||
ProcessUserData bool `toml:"process_userdata"`
|
||||
ProcessEventData bool `toml:"process_eventdata"`
|
||||
Separator string `toml:"separator"`
|
||||
OnlyFirstLineOfMessage bool `toml:"only_first_line_of_message"`
|
||||
TimeStampFromEvent bool `toml:"timestamp_from_event"`
|
||||
EventTags []string `toml:"event_tags"`
|
||||
EventFields []string `toml:"event_fields"`
|
||||
ExcludeFields []string `toml:"exclude_fields"`
|
||||
ExcludeEmpty []string `toml:"exclude_empty"`
|
||||
subscription EvtHandle
|
||||
buf []byte
|
||||
Log telegraf.Logger
|
||||
Locale uint32 `toml:"locale"`
|
||||
EventlogName string `toml:"eventlog_name"`
|
||||
Query string `toml:"xpath_query"`
|
||||
FromBeginning bool `toml:"from_beginning"`
|
||||
ProcessUserData bool `toml:"process_userdata"`
|
||||
ProcessEventData bool `toml:"process_eventdata"`
|
||||
Separator string `toml:"separator"`
|
||||
OnlyFirstLineOfMessage bool `toml:"only_first_line_of_message"`
|
||||
TimeStampFromEvent bool `toml:"timestamp_from_event"`
|
||||
EventTags []string `toml:"event_tags"`
|
||||
EventFields []string `toml:"event_fields"`
|
||||
ExcludeFields []string `toml:"exclude_fields"`
|
||||
ExcludeEmpty []string `toml:"exclude_empty"`
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
subscription EvtHandle
|
||||
subscriptionFlag EvtSubscribeFlag
|
||||
bookmark EvtHandle
|
||||
}
|
||||
|
||||
var bufferSize = 1 << 14
|
||||
const bufferSize = 1 << 14
|
||||
|
||||
func (*WinEventLog) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
// Gather Windows Event Log entries
|
||||
func (w *WinEventLog) Gather(acc telegraf.Accumulator) error {
|
||||
|
||||
var err error
|
||||
if w.subscription == 0 {
|
||||
w.subscription, err = w.evtSubscribe(w.EventlogName, w.Query)
|
||||
if err != nil {
|
||||
return fmt.Errorf("subscription of Windows Event Log failed: %w", err)
|
||||
}
|
||||
func (w *WinEventLog) Init() error {
|
||||
w.subscriptionFlag = EvtSubscribeToFutureEvents
|
||||
if w.FromBeginning {
|
||||
w.subscriptionFlag = EvtSubscribeStartAtOldestRecord
|
||||
}
|
||||
|
||||
bookmark, err := _EvtCreateBookmark(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.bookmark = bookmark
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WinEventLog) Start(_ telegraf.Accumulator) error {
|
||||
subscription, err := w.evtSubscribe()
|
||||
if err != nil {
|
||||
return fmt.Errorf("subscription of Windows Event Log failed: %w", err)
|
||||
}
|
||||
w.subscription = subscription
|
||||
w.Log.Debug("Subscription handle id:", w.subscription)
|
||||
|
||||
loop:
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WinEventLog) Stop() {
|
||||
_ = _EvtClose(w.subscription)
|
||||
}
|
||||
|
||||
func (w *WinEventLog) GetState() interface{} {
|
||||
bookmarkXML, err := w.renderBookmark(w.bookmark)
|
||||
if err != nil {
|
||||
w.Log.Errorf("State-persistence failed, cannot render bookmark: %w", err)
|
||||
return ""
|
||||
}
|
||||
return bookmarkXML
|
||||
}
|
||||
|
||||
func (w *WinEventLog) SetState(state interface{}) error {
|
||||
bookmarkXML, ok := state.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid type %T for state", state)
|
||||
}
|
||||
|
||||
ptr, err := syscall.UTF16PtrFromString(bookmarkXML)
|
||||
if err != nil {
|
||||
return fmt.Errorf("convertion to pointer failed: %w", err)
|
||||
}
|
||||
|
||||
bookmark, err := _EvtCreateBookmark(ptr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating bookmark failed: %w", err)
|
||||
}
|
||||
w.bookmark = bookmark
|
||||
w.subscriptionFlag = EvtSubscribeStartAfterBookmark
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Gather Windows Event Log entries
|
||||
func (w *WinEventLog) Gather(acc telegraf.Accumulator) error {
|
||||
for {
|
||||
events, err := w.fetchEvents(w.subscription)
|
||||
if err != nil {
|
||||
switch {
|
||||
case err == ERROR_NO_MORE_ITEMS:
|
||||
break loop
|
||||
case err != nil:
|
||||
w.Log.Errorf("Error getting events: %v", err)
|
||||
return err
|
||||
if err == ERROR_NO_MORE_ITEMS {
|
||||
break
|
||||
}
|
||||
w.Log.Errorf("Error getting events: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, event := range events {
|
||||
|
|
@ -244,27 +294,28 @@ func (w *WinEventLog) shouldExcludeEmptyField(field string, fieldType string, fi
|
|||
return false
|
||||
}
|
||||
|
||||
func (w *WinEventLog) evtSubscribe(logName, xquery string) (EvtHandle, error) {
|
||||
var logNamePtr, xqueryPtr *uint16
|
||||
|
||||
func (w *WinEventLog) evtSubscribe() (EvtHandle, error) {
|
||||
sigEvent, err := windows.CreateEvent(nil, 0, 0, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer windows.CloseHandle(sigEvent)
|
||||
|
||||
logNamePtr, err = syscall.UTF16PtrFromString(logName)
|
||||
logNamePtr, err := syscall.UTF16PtrFromString(w.EventlogName)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
xqueryPtr, err = syscall.UTF16PtrFromString(xquery)
|
||||
xqueryPtr, err := syscall.UTF16PtrFromString(w.Query)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
subsHandle, err := _EvtSubscribe(0, uintptr(sigEvent), logNamePtr, xqueryPtr,
|
||||
0, 0, 0, EvtSubscribeToFutureEvents)
|
||||
var bookmark EvtHandle
|
||||
if w.subscriptionFlag == EvtSubscribeStartAfterBookmark {
|
||||
bookmark = w.bookmark
|
||||
}
|
||||
subsHandle, err := _EvtSubscribe(0, uintptr(sigEvent), logNamePtr, xqueryPtr, bookmark, 0, 0, w.subscriptionFlag)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -299,34 +350,55 @@ func (w *WinEventLog) fetchEvents(subsHandle EvtHandle) ([]Event, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var evterr error
|
||||
for _, eventHandle := range eventHandles {
|
||||
if eventHandle != 0 {
|
||||
event, err := w.renderEvent(eventHandle)
|
||||
if err == nil {
|
||||
events = append(events, event)
|
||||
}
|
||||
if eventHandle == 0 {
|
||||
continue
|
||||
}
|
||||
if event, err := w.renderEvent(eventHandle); err == nil {
|
||||
events = append(events, event)
|
||||
}
|
||||
if err := _EvtUpdateBookmark(w.bookmark, eventHandle); err != nil && evterr == nil {
|
||||
evterr = err
|
||||
}
|
||||
|
||||
if err := _EvtClose(eventHandle); err != nil && evterr == nil {
|
||||
evterr = err
|
||||
}
|
||||
}
|
||||
return events, evterr
|
||||
}
|
||||
|
||||
func (w *WinEventLog) renderBookmark(bookmark EvtHandle) (string, error) {
|
||||
var bufferUsed, propertyCount uint32
|
||||
|
||||
buf := make([]byte, bufferSize)
|
||||
err := _EvtRender(0, bookmark, EvtRenderBookmark, uint32(len(buf)), &buf[0], &bufferUsed, &propertyCount)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for i := 0; i < len(eventHandles); i++ {
|
||||
err := _EvtClose(eventHandles[i])
|
||||
if err != nil {
|
||||
return events, err
|
||||
}
|
||||
x, err := DecodeUTF16(buf[:bufferUsed])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return events, nil
|
||||
if x[len(x)-1] == 0 {
|
||||
x = x[:len(x)-1]
|
||||
}
|
||||
return string(x), err
|
||||
}
|
||||
|
||||
func (w *WinEventLog) renderEvent(eventHandle EvtHandle) (Event, error) {
|
||||
var bufferUsed, propertyCount uint32
|
||||
|
||||
buf := make([]byte, bufferSize)
|
||||
event := Event{}
|
||||
err := _EvtRender(0, eventHandle, EvtRenderEventXml, uint32(len(w.buf)), &w.buf[0], &bufferUsed, &propertyCount)
|
||||
err := _EvtRender(0, eventHandle, EvtRenderEventXml, uint32(len(buf)), &buf[0], &bufferUsed, &propertyCount)
|
||||
if err != nil {
|
||||
return event, err
|
||||
}
|
||||
|
||||
eventXML, err := DecodeUTF16(w.buf[:bufferUsed])
|
||||
eventXML, err := DecodeUTF16(buf[:bufferUsed])
|
||||
if err != nil {
|
||||
return event, err
|
||||
}
|
||||
|
|
@ -483,7 +555,6 @@ func openPublisherMetadata(
|
|||
func init() {
|
||||
inputs.Add("win_eventlog", func() telegraf.Input {
|
||||
return &WinEventLog{
|
||||
buf: make([]byte, bufferSize),
|
||||
ProcessUserData: true,
|
||||
ProcessEventData: true,
|
||||
Separator: "_",
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ var (
|
|||
procEvtNext = modwevtapi.NewProc("EvtNext")
|
||||
procEvtFormatMessage = modwevtapi.NewProc("EvtFormatMessage")
|
||||
procEvtOpenPublisherMetadata = modwevtapi.NewProc("EvtOpenPublisherMetadata")
|
||||
procEvtCreateBookmark = modwevtapi.NewProc("EvtCreateBookmark")
|
||||
procEvtUpdateBookmark = modwevtapi.NewProc("EvtUpdateBookmark")
|
||||
)
|
||||
|
||||
func _EvtSubscribe(
|
||||
|
|
@ -231,3 +233,26 @@ func _EvtOpenPublisherMetadata(session EvtHandle, publisherIdentity *uint16, log
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func _EvtCreateBookmark(bookmarkXML *uint16) (EvtHandle, error) {
|
||||
r0, _, e1 := syscall.Syscall(procEvtCreateBookmark.Addr(), 1, uintptr(unsafe.Pointer(bookmarkXML)), 0, 0)
|
||||
handle := EvtHandle(r0)
|
||||
if handle != 0 {
|
||||
return handle, nil
|
||||
}
|
||||
if e1 != 0 {
|
||||
return handle, errnoErr(e1)
|
||||
}
|
||||
return handle, syscall.EINVAL
|
||||
}
|
||||
|
||||
func _EvtUpdateBookmark(bookmark, event EvtHandle) error {
|
||||
r0, _, e1 := syscall.Syscall(procEvtUpdateBookmark.Addr(), 2, uintptr(bookmark), uintptr(event), 0)
|
||||
if r0 != 0 {
|
||||
return nil
|
||||
}
|
||||
if e1 != 0 {
|
||||
return errnoErr(e1)
|
||||
}
|
||||
return syscall.EINVAL
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue