fleet/server/platform/logging/topic_handler_test.go
Scott Gress 421dc67e0c
Add ability to enable/disable logs by topic (#40126)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #40124 

# Details

Implements the proposal in
https://docs.google.com/document/d/16qe6oVLKK25nA9GEIPR9Gw_IJ342_wlJRdnWEMmWdas/edit?tab=t.0#heading=h.nlw4agv1xs3g

Allows doing e.g.
```go
logger.WarnContext(logCtx, "The `team_id` param is deprecated, use `fleet_id` instead", "log_topic", "deprecated-field-names")
```
or
```go
if logging.TopicEnabled("deprecated-api-params") {
  logging.WithLevel(ctx, slog.LevelWarn)
  logging.WithExtras(
    ctx, 
    "deprecated_param", 
    queryTagValue,
    "deprecation_warning", 
    fmt.Sprintf("'%s' is deprecated, use '%s'", queryTagValue, renameTo),
  )
}
```

Topics can be disabled at the app level, and enabled/disabled at the
command-line level.

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [X] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing

- [X] Added/updated automated tests
- [X] QA'd all new/changed functionality manually
No logs have this in prod yet, but I added some manually in a branch and
verified that I could enable/disable them via CLI options and env vars,
including enabling topics that were disabled on the server. Tested for
both server and `fleetctl gitops`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Added per-topic logging control to enable or disable logging for
specific topics via configuration and CLI flags.
* Added context-aware logging methods (ErrorContext, WarnContext,
InfoContext, DebugContext) to support contextual logging.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-20 17:22:50 -06:00

85 lines
2.4 KiB
Go

package logging
import (
"bytes"
"context"
"log/slog"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func newTopicTestLogger(buf *bytes.Buffer) *slog.Logger {
handler := slog.NewTextHandler(buf, &slog.HandlerOptions{Level: slog.LevelInfo})
handler2 := NewTopicFilterHandler(handler)
return slog.New(handler2)
}
func TestTopicHandler_NoTopic(t *testing.T) {
t.Cleanup(ResetTopics)
var buf bytes.Buffer
logger := newTopicTestLogger(&buf)
logger.InfoContext(context.Background(), "hello")
assert.Contains(t, buf.String(), "hello")
}
func TestTopicHandler_DisabledTopicByAttr(t *testing.T) {
t.Cleanup(ResetTopics)
var buf bytes.Buffer
logger := newTopicTestLogger(&buf)
DisableTopic("my-topic")
logger.InfoContext(context.Background(), "should not appear", "log_topic", "my-topic")
assert.Empty(t, buf.String())
}
func TestTopicHandler_DisabledTopicByWithAttr(t *testing.T) {
t.Cleanup(ResetTopics)
var buf bytes.Buffer
logger := newTopicTestLogger(&buf)
DisableTopic("my-topic")
logger = logger.With("log_topic", "my-topic")
logger.InfoContext(context.Background(), "should not appear")
assert.Empty(t, buf.String())
// Test overriding the handler topic with a different per-log topic.
logger.InfoContext(context.Background(), "should appear", "log_topic", "other-topic")
assert.Contains(t, buf.String(), "should appear")
}
func TestTopicHandler_RespectsBaseLevel(t *testing.T) {
t.Cleanup(ResetTopics)
var buf bytes.Buffer
// Base handler at Info level — Debug messages should be dropped regardless of topic.
handler := slog.NewTextHandler(&buf, &slog.HandlerOptions{Level: slog.LevelInfo})
logger := slog.New(NewTopicFilterHandler(handler))
logger.DebugContext(context.Background(), "debug message")
assert.Empty(t, buf.String())
}
func TestTopicHandler_WithAttrsPassesThrough(t *testing.T) {
t.Cleanup(ResetTopics)
var buf bytes.Buffer
logger := newTopicTestLogger(&buf)
logger = logger.With("key", "value")
logger.InfoContext(context.Background(), "with attrs")
output := buf.String()
assert.Contains(t, output, "with attrs")
assert.Contains(t, output, "key=value")
}
func TestTopicHandler_WithGroupPassesThrough(t *testing.T) {
t.Cleanup(ResetTopics)
var buf bytes.Buffer
logger := newTopicTestLogger(&buf)
logger = logger.WithGroup("grp")
logger.InfoContext(context.Background(), "with group", "k", "v")
output := buf.String()
require.Contains(t, output, "grp.k=v")
}