diff --git a/CHANGELOG.md b/CHANGELOG.md index d9e5763e426d..02d1b094fc09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ Main (unreleased) - Increased the alert interval and renamed the `ClusterSplitBrain` alert to `ClusterNodeCountMismatch` in the Grafana Agent Mixin to better match the alert conditions. (@thampiotr) +- Add conversion from static to flow mode for `loki.source.windowsevent` via `legacy_bookmark_path`. (@mattdurham) + ### Features - Added a new CLI flag `--stability.level` which defines the minimum stability diff --git a/docs/sources/flow/reference/components/loki.source.windowsevent.md b/docs/sources/flow/reference/components/loki.source.windowsevent.md index 522e9e683e54..58bc3431bd9b 100644 --- a/docs/sources/flow/reference/components/loki.source.windowsevent.md +++ b/docs/sources/flow/reference/components/loki.source.windowsevent.md @@ -32,19 +32,20 @@ log entries to the list of receivers passed in `forward_to`. `loki.source.windowsevent` supports the following arguments: -Name | Type | Description | Default | Required ------------------------- |----------------------|--------------------------------------------------------------------------------|----------------------------| -------- -`locale` | `number` | Locale ID for event rendering. 0 default is Windows Locale. | `0` | no -`eventlog_name` | `string` | Event log to read from. | | See below. -`xpath_query` | `string` | Event log to read from. | `"*"` | See below. -`bookmark_path` | `string` | Keeps position in event log. | `"DATA_PATH/bookmark.xml"` | no -`poll_interval` | `duration` | How often to poll the event log. | `"3s"` | no -`exclude_event_data` | `bool` | Exclude event data. | `false` | no -`exclude_user_data` | `bool` | Exclude user data. | `false` | no -`exclude_event_message` | `bool` | Exclude the human-friendly event message. | `false` | no -`use_incoming_timestamp` | `bool` | When false, assigns the current timestamp to the log when it was processed. | `false` | no -`forward_to` | `list(LogsReceiver)` | List of receivers to send log entries to. | | yes -`labels` | `map(string)` | The labels to associate with incoming logs. | | no +Name | Type | Description | Default | Required +------------------------ |----------------------|-----------------------------------------------------------------------------|----------------------------| -------- +`locale` | `number` | Locale ID for event rendering. 0 default is Windows Locale. | `0` | no +`eventlog_name` | `string` | Event log to read from. | | See below. +`xpath_query` | `string` | Event log to read from. | `"*"` | See below. +`bookmark_path` | `string` | Keeps position in event log. | `"DATA_PATH/bookmark.xml"` | no +`poll_interval` | `duration` | How often to poll the event log. | `"3s"` | no +`exclude_event_data` | `bool` | Exclude event data. | `false` | no +`exclude_user_data` | `bool` | Exclude user data. | `false` | no +`exclude_event_message` | `bool` | Exclude the human-friendly event message. | `false` | no +`use_incoming_timestamp` | `bool` | When false, assigns the current timestamp to the log when it was processed. | `false` | no +`forward_to` | `list(LogsReceiver)` | List of receivers to send log entries to. | | yes +`labels` | `map(string)` | The labels to associate with incoming logs. | | no +`legacy_bookmark_path` | `string` | The location of the Grafana Agent Static bookmark path. | `` | no > **NOTE**: `eventlog_name` is required if `xpath_query` does not specify the event log. @@ -52,6 +53,9 @@ Name | Type | Description > When using the XML form you can specify `event_log` in the `xpath_query`. > If using short form, you must define `eventlog_name`. +{{< admonition type="note" >}} +`legacy_bookmark_path` is used to convert the Grafana Agent Static to a {{< param "PRODUCT_NAME" >}} bookmark, if `bookmark_path` does not exist. +{{< /admonition >}} ## Component health diff --git a/internal/component/loki/source/windowsevent/arguments.go b/internal/component/loki/source/windowsevent/arguments.go index 8c26ed1e1ee3..61e6e6956fc8 100644 --- a/internal/component/loki/source/windowsevent/arguments.go +++ b/internal/component/loki/source/windowsevent/arguments.go @@ -24,6 +24,7 @@ type Arguments struct { UseIncomingTimestamp bool `river:"use_incoming_timestamp,attr,optional"` ForwardTo []loki.LogsReceiver `river:"forward_to,attr"` Labels map[string]string `river:"labels,attr,optional"` + LegacyBookmarkPath string `river:"legacy_bookmark_path,attr,optional"` } func defaultArgs() Arguments { diff --git a/internal/component/loki/source/windowsevent/component_test.go b/internal/component/loki/source/windowsevent/component_test.go index 49488e0313bd..f0559b91d0a3 100644 --- a/internal/component/loki/source/windowsevent/component_test.go +++ b/internal/component/loki/source/windowsevent/component_test.go @@ -4,6 +4,8 @@ package windowsevent import ( "context" + "os" + "path/filepath" "strings" "testing" "time" @@ -69,3 +71,45 @@ func TestEventLogger(t *testing.T) { cancelFunc() require.True(t, found) } + +func TestLegacyBookmarkConversion(t *testing.T) { + + bookmarkText := `<BookmarkList> + <Bookmark Channel='Application' RecordId='415060' IsCurrent='true'/> +</BookmarkList>` + var loggerName = "agent_test" + //Setup Windows Event log with the log source name and logging levels + _ = eventlog.InstallAsEventCreate(loggerName, eventlog.Info|eventlog.Warning|eventlog.Error) + dataPath := t.TempDir() + legacyPath := filepath.Join(t.TempDir(), "legacy.xml") + err := os.WriteFile(legacyPath, []byte(bookmarkText), 644) + require.NoError(t, err) + rec := loki.NewLogsReceiver() + c, err := New(component.Options{ + ID: "loki.source.windowsevent.test", + Logger: util.TestFlowLogger(t), + DataPath: dataPath, + OnStateChange: func(e component.Exports) { + + }, + Registerer: prometheus.DefaultRegisterer, + Tracer: nil, + }, Arguments{ + Locale: 0, + EventLogName: "Application", + XPathQuery: "*", + BookmarkPath: "", + PollInterval: 10 * time.Millisecond, + ExcludeEventData: false, + ExcludeUserdata: false, + ExcludeEventMessage: false, + UseIncomingTimestamp: false, + ForwardTo: []loki.LogsReceiver{rec}, + Labels: map[string]string{"job": "windows"}, + LegacyBookmarkPath: legacyPath, + }) + require.NoError(t, err) + dd, _ := os.ReadFile(c.args.BookmarkPath) + // The New function will convert via calling update. + require.True(t, string(dd) == bookmarkText) +} diff --git a/internal/component/loki/source/windowsevent/component_windows.go b/internal/component/loki/source/windowsevent/component_windows.go index 58a4a6223417..e94fcd6a2a58 100644 --- a/internal/component/loki/source/windowsevent/component_windows.go +++ b/internal/component/loki/source/windowsevent/component_windows.go @@ -110,18 +110,9 @@ func (c *Component) Update(args component.Arguments) error { newArgs.BookmarkPath = path.Join(c.opts.DataPath, "bookmark.xml") } - // Create the bookmark file and parent folders if they don't exist. - _, err := os.Stat(newArgs.BookmarkPath) - if os.IsNotExist(err) { - err := os.MkdirAll(path.Dir(newArgs.BookmarkPath), 644) - if err != nil { - return err - } - f, err := os.Create(newArgs.BookmarkPath) - if err != nil { - return err - } - _ = f.Close() + err := createBookmark(newArgs) + if err != nil { + return err } winTarget, err := NewTarget(c.opts.Logger, c.handle, nil, convertConfig(newArgs)) @@ -142,6 +133,35 @@ func (c *Component) Update(args component.Arguments) error { return nil } +// createBookmark will create bookmark for saving the positions file. +// If LegacyBookMark is specified and the BookmarkPath doesnt exist it will copy over the legacy bookmark to the new path. +func createBookmark(args Arguments) error { + _, err := os.Stat(args.BookmarkPath) + // If the bookmark path does not exist then we should check to see if + if os.IsNotExist(err) { + err = os.MkdirAll(path.Dir(args.BookmarkPath), 644) + if err != nil { + return err + } + // Check to see if we need to convert the legacy bookmark to a new one. + // This will only trigger if the new bookmark path does not exist and legacy does. + _, legacyErr := os.Stat(args.LegacyBookmarkPath) + if legacyErr == nil { + bb, readErr := os.ReadFile(args.LegacyBookmarkPath) + if readErr == nil { + _ = os.WriteFile(args.BookmarkPath, bb, 644) + } + } else { + f, err := os.Create(args.BookmarkPath) + if err != nil { + return err + } + _ = f.Close() + } + } + return nil +} + func convertConfig(arg Arguments) *scrapeconfig.WindowsEventsTargetConfig { return &scrapeconfig.WindowsEventsTargetConfig{ Locale: uint32(arg.Locale), diff --git a/internal/converter/internal/promtailconvert/internal/build/windows_events.go b/internal/converter/internal/promtailconvert/internal/build/windows_events.go index e1784535b3fe..d67113d17150 100644 --- a/internal/converter/internal/promtailconvert/internal/build/windows_events.go +++ b/internal/converter/internal/promtailconvert/internal/build/windows_events.go @@ -15,7 +15,7 @@ func (s *ScrapeConfigBuilder) AppendWindowsEventsConfig() { Locale: int(winCfg.Locale), EventLogName: winCfg.EventlogName, XPathQuery: winCfg.Query, - BookmarkPath: winCfg.BookmarkPath, + LegacyBookmarkPath: winCfg.BookmarkPath, PollInterval: winCfg.PollInterval, ExcludeEventData: winCfg.ExcludeEventData, ExcludeUserdata: winCfg.ExcludeUserData, diff --git a/internal/converter/internal/promtailconvert/testdata/windowsevents.river b/internal/converter/internal/promtailconvert/testdata/windowsevents.river index 640ef93d8080..2aef42887759 100644 --- a/internal/converter/internal/promtailconvert/testdata/windowsevents.river +++ b/internal/converter/internal/promtailconvert/testdata/windowsevents.river @@ -2,7 +2,6 @@ loki.source.windowsevent "fun" { locale = 1033 eventlog_name = "Application" xpath_query = "Event/System[EventID=1000]" - bookmark_path = "C:/Users/username/Desktop/bookmark.txt" poll_interval = "10s" exclude_event_data = true exclude_user_data = true @@ -13,6 +12,7 @@ loki.source.windowsevent "fun" { host = "localhost", job = "windows", } + legacy_bookmark_path = "C:/Users/username/Desktop/bookmark.txt" } loki.write "default" { diff --git a/internal/converter/internal/promtailconvert/testdata/windowsevents_relabel.river b/internal/converter/internal/promtailconvert/testdata/windowsevents_relabel.river index 39d28dea7a67..c35203273fc5 100644 --- a/internal/converter/internal/promtailconvert/testdata/windowsevents_relabel.river +++ b/internal/converter/internal/promtailconvert/testdata/windowsevents_relabel.river @@ -11,7 +11,6 @@ loki.source.windowsevent "fun" { locale = 1033 eventlog_name = "Application" xpath_query = "Event/System[EventID=1000]" - bookmark_path = "C:/Users/username/Desktop/bookmark.txt" poll_interval = "10s" exclude_event_data = true exclude_user_data = true @@ -19,6 +18,7 @@ loki.source.windowsevent "fun" { use_incoming_timestamp = true forward_to = [loki.relabel.fun.receiver] labels = {} + legacy_bookmark_path = "C:/Users/username/Desktop/bookmark.txt" } loki.write "default" { diff --git a/internal/converter/internal/staticconvert/testdata/sanitize.river b/internal/converter/internal/staticconvert/testdata/sanitize.river index 7b2bf9ef8ffb..193657f9a2c6 100644 --- a/internal/converter/internal/staticconvert/testdata/sanitize.river +++ b/internal/converter/internal/staticconvert/testdata/sanitize.river @@ -42,13 +42,13 @@ loki.relabel "logs_integrations_integrations_windows_exporter_application" { loki.source.windowsevent "logs_integrations_integrations_windows_exporter_application" { eventlog_name = "Application" xpath_query = "" - bookmark_path = "C:\\grafana_test\\Grafana Agent\\bookmarks.xml" poll_interval = "0s" use_incoming_timestamp = true forward_to = [loki.relabel.logs_integrations_integrations_windows_exporter_application.receiver] labels = { job = "integrations/windows_exporter", } + legacy_bookmark_path = "C:\\grafana_test\\Grafana Agent\\bookmarks.xml" } loki.process "logs_integrations_integrations_windows_exporter_system" { @@ -79,13 +79,13 @@ loki.relabel "logs_integrations_integrations_windows_exporter_system" { loki.source.windowsevent "logs_integrations_integrations_windows_exporter_system" { eventlog_name = "System" xpath_query = "" - bookmark_path = "C:\\grafana_test\\Grafana Agent\\bookmarks.xml" poll_interval = "0s" use_incoming_timestamp = true forward_to = [loki.relabel.logs_integrations_integrations_windows_exporter_system.receiver] labels = { job = "integrations/windows_exporter", } + legacy_bookmark_path = "C:\\grafana_test\\Grafana Agent\\bookmarks.xml" } loki.write "logs_integrations" {