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