Skip to content

Commit

Permalink
Add support for changing over bookmark paths using the legacy bookmak…
Browse files Browse the repository at this point in the history
… path (#6653)

* Add support for changing over bookmark paths using the legacy bookmark path

* PR feedback

* simplify
  • Loading branch information
mattdurham authored Mar 26, 2024
1 parent 586fcb9 commit 59e7451
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 30 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 17 additions & 13 deletions docs/sources/flow/reference/components/loki.source.windowsevent.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,30 @@ 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.
> You can define `xpath_query` in [short or xml form](https://docs.microsoft.com/en-us/windows/win32/wes/consuming-events).
> 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

Expand Down
1 change: 1 addition & 0 deletions internal/component/loki/source/windowsevent/arguments.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
44 changes: 44 additions & 0 deletions internal/component/loki/source/windowsevent/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package windowsevent

import (
"context"
"os"
"path/filepath"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -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)
}
44 changes: 32 additions & 12 deletions internal/component/loki/source/windowsevent/component_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -13,6 +12,7 @@ loki.source.windowsevent "fun" {
host = "localhost",
job = "windows",
}
legacy_bookmark_path = "C:/Users/username/Desktop/bookmark.txt"
}

loki.write "default" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ 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
exclude_event_message = true
use_incoming_timestamp = true
forward_to = [loki.relabel.fun.receiver]
labels = {}
legacy_bookmark_path = "C:/Users/username/Desktop/bookmark.txt"
}

loki.write "default" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand Down Expand Up @@ -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" {
Expand Down

0 comments on commit 59e7451

Please sign in to comment.