fleet/server/platform/logging/topic_handler.go
Scott Gress 772fb12cf5
Add more deprecation logs and mute by default (#40305)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #40122

# Details

* Adds deprecation warnings to `fleetctl apply`
* Adds alias conflict errors (i.e. using both new and deprecated keys in
the same spec) to `fleetctl apply`
* Adds logic around all deprecated field warnings to check the topic
first
* Disables deprecation warnings by default for `fleet serve`, `fleetctl
gitops` and `fleetctl apply`
* Enables deprecation warnings for dogfood via env var

To turn on warnings:
* In `fleet serve`, use either
`--logging_enable_topics=deprecated-field-names` or the
`FLEET_LOGGING_ENABLE_TOPICS=deprecated-field-names` env var
* In `fleetctl gitops` / `fleetctl apply` use either
`--enable-log-topics=deprecated-field-names` or
`FLEET_ENABLE_LOG_TOPICS=deprecated-field-names`

# 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

tested in `fleetctl apply`, `fleet serve` and `fleet gitops` that
warnings are suppressed by default and added when the appropriate env
var or CLI option is used
2026-02-23 23:09:08 -06:00

65 lines
2.1 KiB
Go

package logging
import (
"context"
"log/slog"
)
const logTopicAttrKey = "log_topic"
// TopicFilterHandler is a slog.Handler that filters log records based on
// the log_topic found in the log record's attributes, or on the handler
// itself if set using `WithAttrs`.
type TopicFilterHandler struct {
base slog.Handler
topic string
}
// NewTopicFilterHandler wraps base with topic-aware filtering.
func NewTopicFilterHandler(base slog.Handler) *TopicFilterHandler {
return &TopicFilterHandler{base: base}
}
// Enabled reports whether the handler handles records at the given level.
func (h *TopicFilterHandler) Enabled(ctx context.Context, level slog.Level) bool {
return h.base.Enabled(ctx, level)
}
// Handle processes the log record. It performs a defensive re-check of the
// topic before delegating to the base handler.
func (h *TopicFilterHandler) Handle(ctx context.Context, r slog.Record) error {
topic := h.topic
// Override any log_topic attribute on the handler with one from the record's attributes, if present.
r.Attrs(func(a slog.Attr) bool {
if a.Key == logTopicAttrKey {
topic = a.Value.String()
return false
}
return true
})
// Don't log if there's a disabled topic either on the handler or the record.
if topic != "" && !TopicEnabled(topic) {
return nil
}
return h.base.Handle(ctx, r)
}
// WithAttrs returns a new TopicFilterHandler wrapping the base with added attributes.
func (h *TopicFilterHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
// Check if the new attributes include a log_topic that should override the handler's current topic.
for _, a := range attrs {
if a.Key == logTopicAttrKey {
return &TopicFilterHandler{base: h.base.WithAttrs(attrs), topic: a.Value.String()}
}
}
return &TopicFilterHandler{base: h.base.WithAttrs(attrs), topic: h.topic}
}
// WithGroup returns a new TopicFilterHandler wrapping the base with the given group.
func (h *TopicFilterHandler) WithGroup(name string) slog.Handler {
return &TopicFilterHandler{base: h.base.WithGroup(name), topic: h.topic}
}
// Ensure TopicFilterHandler implements slog.Handler at compile time.
var _ slog.Handler = (*TopicFilterHandler)(nil)