Migrated logging and google calendar files to use slog (#40541)

<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #40540 

# Checklist for submitter
- [ ] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
  - Changes present in previous PR

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually


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

* **Refactor**
* Switched the application logging to Go's standard slog with
context-aware logging, improving structured logs and observability
across services (status, audit, result, integrations).
* Replaced legacy logging implementations and updated runtime wiring to
propagate contextual loggers for more consistent, searchable log output.

* **Tests**
  * Updated test suites to use the new slog discard/logger setup.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Victor Lyuboslavsky
2026-02-26 12:48:54 -06:00
committed by GitHub
parent fd3cb6c1cc
commit 77eb458658
24 changed files with 121 additions and 130 deletions
+3 -3
View File
@@ -511,7 +511,7 @@ the way that the Fleet server works.
loggingConfig.KafkaREST.Topic = config.KafkaREST.StatusTopic
loggingConfig.Nats.Subject = config.Nats.StatusSubject
osquerydStatusLogger, err := logging.NewJSONLogger("status", loggingConfig, logger)
osquerydStatusLogger, err := logging.NewJSONLogger(cmd.Context(), "status", loggingConfig, logger.SlogLogger())
if err != nil {
initFatal(err, "initializing osqueryd status logging")
}
@@ -528,7 +528,7 @@ the way that the Fleet server works.
loggingConfig.KafkaREST.Topic = config.KafkaREST.ResultTopic
loggingConfig.Nats.Subject = config.Nats.ResultSubject
osquerydResultLogger, err := logging.NewJSONLogger("result", loggingConfig, logger)
osquerydResultLogger, err := logging.NewJSONLogger(cmd.Context(), "result", loggingConfig, logger.SlogLogger())
if err != nil {
initFatal(err, "initializing osqueryd result logging")
}
@@ -546,7 +546,7 @@ the way that the Fleet server works.
loggingConfig.KafkaREST.Topic = config.KafkaREST.AuditTopic
loggingConfig.Nats.Subject = config.Nats.AuditSubject
auditLogger, err = logging.NewJSONLogger("audit", loggingConfig, logger)
auditLogger, err = logging.NewJSONLogger(cmd.Context(), "audit", loggingConfig, logger.SlogLogger())
if err != nil {
initFatal(err, "initializing audit logging")
}
+3 -3
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
"os"
"regexp"
@@ -15,7 +16,6 @@ import (
"github.com/cenkalti/backoff/v4"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/google/uuid"
"golang.org/x/oauth2/google"
"golang.org/x/oauth2/jwt"
@@ -52,7 +52,7 @@ var (
type GoogleCalendarConfig struct {
Context context.Context
IntegrationConfig *fleet.GoogleCalendarIntegration
Logger *logging.Logger
Logger *slog.Logger
ServerURL string
// Should be nil for production
API GoogleCalendarAPI
@@ -107,7 +107,7 @@ type eventDetails struct {
type GoogleCalendarLowLevelAPI struct {
service *calendar.Service
logger *logging.Logger
logger *slog.Logger
serverURL string
}
@@ -2,6 +2,7 @@ package calendar
import (
"context"
"log/slog"
"net/http/httptest"
"os"
"testing"
@@ -9,7 +10,6 @@ import (
"github.com/fleetdm/fleet/v4/ee/server/calendar/load_test"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
@@ -62,7 +62,7 @@ func (s *googleCalendarIntegrationTestSuite) TestCreateGetDeleteEvent() {
"private_key": s.server.URL,
}},
},
Logger: logging.NewLogfmtLogger(os.Stdout),
Logger: slog.New(slog.NewTextHandler(os.Stdout, nil)),
}
gCal := NewGoogleCalendar(config)
err := gCal.Configure(userEmail)
@@ -129,7 +129,7 @@ func (s *googleCalendarIntegrationTestSuite) TestFillUpCalendar() {
"private_key": s.server.URL,
}},
},
Logger: logging.NewLogfmtLogger(os.Stdout),
Logger: slog.New(slog.NewTextHandler(os.Stdout, nil)),
}
gCal := NewGoogleCalendar(config)
err := gCal.Configure(userEmail)
+7 -6
View File
@@ -6,19 +6,20 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/fleetdm/fleet/v4/pkg/fleethttp"
"github.com/fleetdm/fleet/v4/server/platform/logging"
"google.golang.org/api/calendar/v3"
"google.golang.org/api/googleapi"
"io"
"log/slog"
"net/http"
"net/url"
"os"
"github.com/fleetdm/fleet/v4/pkg/fleethttp"
"google.golang.org/api/calendar/v3"
"google.golang.org/api/googleapi"
)
// GoogleCalendarLoadAPI is used for load testing.
type GoogleCalendarLoadAPI struct {
Logger *logging.Logger
Logger *slog.Logger
baseUrl string
userToImpersonate string
ctx context.Context
@@ -30,7 +31,7 @@ type GoogleCalendarLoadAPI struct {
func (lowLevelAPI *GoogleCalendarLoadAPI) Configure(ctx context.Context, _ string, privateKey string, userToImpersonate string,
serverURL string) error {
if lowLevelAPI.Logger == nil {
lowLevelAPI.Logger = logging.NewLogfmtLogger(os.Stderr).With("mock", "GoogleCalendarLoadAPI", "user", userToImpersonate)
lowLevelAPI.Logger = slog.New(slog.NewTextHandler(os.Stderr, nil)).With("mock", "GoogleCalendarLoadAPI", "user", userToImpersonate)
}
lowLevelAPI.baseUrl = privateKey
lowLevelAPI.userToImpersonate = userToImpersonate
+10 -10
View File
@@ -3,20 +3,20 @@ package calendar
import (
"context"
"errors"
"github.com/google/uuid"
"log/slog"
"net/http"
"os"
"strconv"
"sync"
"time"
"github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/google/uuid"
"google.golang.org/api/calendar/v3"
"google.golang.org/api/googleapi"
)
type GoogleCalendarMockAPI struct {
logger *logging.Logger
logger *slog.Logger
}
type channel struct {
@@ -36,14 +36,14 @@ const latency = 200 * time.Millisecond
// Configure creates a new Google Calendar service using the provided credentials.
func (lowLevelAPI *GoogleCalendarMockAPI) Configure(_ context.Context, _ string, _ string, userToImpersonate string, _ string) error {
if lowLevelAPI.logger == nil {
lowLevelAPI.logger = logging.NewLogfmtLogger(os.Stderr).With("mock", "GoogleCalendarMockAPI", "user", userToImpersonate)
lowLevelAPI.logger = slog.New(slog.NewTextHandler(os.Stderr, nil)).With("mock", "GoogleCalendarMockAPI", "user", userToImpersonate)
}
return nil
}
func (lowLevelAPI *GoogleCalendarMockAPI) GetSetting(name string) (*calendar.Setting, error) {
time.Sleep(latency)
lowLevelAPI.logger.Log("msg", "GetSetting", "name", name)
lowLevelAPI.logger.InfoContext(context.TODO(), "GetSetting", "name", name)
if name == "timezone" {
return &calendar.Setting{
Id: "timezone",
@@ -59,7 +59,7 @@ func (lowLevelAPI *GoogleCalendarMockAPI) CreateEvent(event *calendar.Event) (*c
defer mu.Unlock()
id += 1
event.Id = strconv.FormatUint(id, 10)
lowLevelAPI.logger.Log("msg", "CreateEvent", "id", event.Id, "start", event.Start.DateTime)
lowLevelAPI.logger.InfoContext(context.TODO(), "CreateEvent", "id", event.Id, "start", event.Start.DateTime)
mockEvents[event.Id] = event
return event, nil
}
@@ -68,7 +68,7 @@ func (lowLevelAPI *GoogleCalendarMockAPI) UpdateEvent(event *calendar.Event) (*c
time.Sleep(latency)
mu.Lock()
defer mu.Unlock()
lowLevelAPI.logger.Log("msg", "UpdateEvent", "id", event.Id, "start", event.Start.DateTime)
lowLevelAPI.logger.InfoContext(context.TODO(), "UpdateEvent", "id", event.Id, "start", event.Start.DateTime)
mockEvents[event.Id] = event
return event, nil
}
@@ -81,13 +81,13 @@ func (lowLevelAPI *GoogleCalendarMockAPI) GetEvent(id, _ string) (*calendar.Even
if !ok {
return nil, &googleapi.Error{Code: http.StatusNotFound}
}
lowLevelAPI.logger.Log("msg", "GetEvent", "id", id, "start", event.Start.DateTime)
lowLevelAPI.logger.InfoContext(context.TODO(), "GetEvent", "id", id, "start", event.Start.DateTime)
return event, nil
}
func (lowLevelAPI *GoogleCalendarMockAPI) ListEvents(string, string) (*calendar.Events, error) {
time.Sleep(latency)
lowLevelAPI.logger.Log("msg", "ListEvents")
lowLevelAPI.logger.InfoContext(context.TODO(), "ListEvents")
return &calendar.Events{}, nil
}
@@ -95,7 +95,7 @@ func (lowLevelAPI *GoogleCalendarMockAPI) DeleteEvent(id string) error {
time.Sleep(latency)
mu.Lock()
defer mu.Unlock()
lowLevelAPI.logger.Log("msg", "DeleteEvent", "id", id)
lowLevelAPI.logger.InfoContext(context.TODO(), "DeleteEvent", "id", id)
delete(mockEvents, id)
return nil
}
+2 -2
View File
@@ -3,6 +3,7 @@ package calendar
import (
"context"
"errors"
"log/slog"
"net/http"
"net/url"
"os"
@@ -10,7 +11,6 @@ import (
"time"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/api/calendar/v3"
@@ -26,7 +26,7 @@ const (
var (
baseCtx = context.Background()
logger = logging.NewLogfmtLogger(os.Stdout)
logger = slog.New(slog.NewTextHandler(os.Stdout, nil))
)
type MockGoogleCalendarLowLevelAPI struct {
+3 -3
View File
@@ -95,7 +95,7 @@ func (svc *Service) CalendarWebhook(ctx context.Context, eventUUID string, chann
GoogleCalendarIntegration: *googleCalendarIntegrationConfig,
ServerURL: appConfig.ServerSettings.ServerURL,
}
userCalendar := calendar.CreateUserCalendarFromConfig(ctx, localConfig, svc.logger)
userCalendar := calendar.CreateUserCalendarFromConfig(ctx, localConfig, svc.logger.SlogLogger())
// Authenticate request. We will use the channel ID for authentication.
svc.authz.SkipAuthorization(ctx)
@@ -231,7 +231,7 @@ func (svc *Service) processCalendarEvent(ctx context.Context, eventDetails *flee
return "", false, err
}
body, generatedTag = calendar.GenerateCalendarEventBody(ctx, svc.ds, team.Name, host, &sync.Map{}, conflict, svc.logger)
body, generatedTag = calendar.GenerateCalendarEventBody(ctx, svc.ds, team.Name, host, &sync.Map{}, conflict, svc.logger.SlogLogger())
return body, true, nil
}
@@ -443,7 +443,7 @@ func (svc *Service) processCalendarEventAsync(ctx context.Context, eventUUID str
GoogleCalendarIntegration: *googleCalendarIntegrationConfig,
ServerURL: appConfig.ServerSettings.ServerURL,
}
userCalendar := calendar.CreateUserCalendarFromConfig(ctx, localConfig, svc.logger)
userCalendar := calendar.CreateUserCalendarFromConfig(ctx, localConfig, svc.logger.SlogLogger())
err = svc.processCalendarEvent(ctx, eventDetails, googleCalendarIntegrationConfig, userCalendar)
if err != nil {
+6 -6
View File
@@ -245,7 +245,7 @@ func processCalendarFailingHosts(
}
}
userCalendar := calendar.CreateUserCalendarFromConfig(ctx, calendarConfig, logger)
userCalendar := calendar.CreateUserCalendarFromConfig(ctx, calendarConfig, logger.SlogLogger())
if err := userCalendar.Configure(host.Email); err != nil {
logger.ErrorContext(ctx, "configure user calendar", "err", err)
continue // continue with next host
@@ -392,7 +392,7 @@ func processFailingHostExistingCalendarEvent(
var newETag string
var genBodyFn fleet.CalendarGenBodyFn = func(conflict bool) (string, bool, error) {
var body string
body, generatedTag = calendar.GenerateCalendarEventBody(ctx, ds, orgName, host, policyIDtoPolicy, conflict, logger)
body, generatedTag = calendar.GenerateCalendarEventBody(ctx, ds, orgName, host, policyIDtoPolicy, conflict, logger.SlogLogger())
return body, true, nil
}
@@ -610,7 +610,7 @@ func attemptCreatingEventOnUserCalendar(
calendarEvent, err := userCalendar.CreateEvent(
preferredDate, func(conflict bool) (string, bool, error) {
var body string
body, generatedTag = calendar.GenerateCalendarEventBody(ctx, ds, orgName, host, policyIDtoPolicy, conflict, logger)
body, generatedTag = calendar.GenerateCalendarEventBody(ctx, ds, orgName, host, policyIDtoPolicy, conflict, logger.SlogLogger())
return body, true, nil
}, fleet.CalendarCreateEventOpts{},
)
@@ -704,7 +704,7 @@ func removeCalendarEventsFromPassingHosts(
logger.ErrorContext(ctx, "get calendar event from DB", "err", err)
continue
}
userCalendar := calendar.CreateUserCalendarFromConfig(ctx, calendarConfig, logger)
userCalendar := calendar.CreateUserCalendarFromConfig(ctx, calendarConfig, logger.SlogLogger())
if err := deleteCalendarEvent(ctx, ds, userCalendar, calendarEvent); err != nil {
logger.ErrorContext(ctx, "delete user calendar event", "err", err)
continue
@@ -774,7 +774,7 @@ func cronCalendarEventsCleanup(ctx context.Context, ds fleet.Datastore, logger *
GoogleCalendarIntegration: *appConfig.Integrations.GoogleCalendar[0],
ServerURL: appConfig.ServerSettings.ServerURL,
}
userCalendar = calendar.CreateUserCalendarFromConfig(ctx, calConfig, logger)
userCalendar = calendar.CreateUserCalendarFromConfig(ctx, calConfig, logger.SlogLogger())
}
// If global setting is disabled, we remove all calendar events from the DB
@@ -850,7 +850,7 @@ func deleteCalendarEventsInParallel(
for calEvent := range calendarEventCh {
var userCalendar fleet.UserCalendar
if calendarConfig != nil {
userCalendar = calendar.CreateUserCalendarFromConfig(ctx, calendarConfig, logger)
userCalendar = calendar.CreateUserCalendarFromConfig(ctx, calendarConfig, logger.SlogLogger())
}
if err := deleteCalendarEvent(ctx, ds, userCalendar, calEvent); err != nil {
logger.ErrorContext(ctx, "delete user calendar event", "err", err)
+3 -3
View File
@@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"io"
"log/slog"
"os"
"os/signal"
"sync"
@@ -14,7 +15,6 @@ import (
"github.com/fleetdm/fleet/v4/pkg/secure"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
)
@@ -28,7 +28,7 @@ type filesystemLogWriter struct {
// enableRotation is true
//
// The enableCompression argument is only used when enableRotation is true.
func NewFilesystemLogWriter(path string, appLogger *platformlogging.Logger, enableRotation, enableCompression bool, maxSize, maxAge, maxBackups int) (*filesystemLogWriter, error) {
func NewFilesystemLogWriter(ctx context.Context, path string, appLogger *slog.Logger, enableRotation, enableCompression bool, maxSize, maxAge, maxBackups int) (*filesystemLogWriter, error) {
// Fail early if the process does not have the necessary
// permissions to open the file at path.
file, err := openFile(path)
@@ -57,7 +57,7 @@ func NewFilesystemLogWriter(path string, appLogger *platformlogging.Logger, enab
for {
<-sig // block on signal
if err := fsLogger.Rotate(); err != nil {
appLogger.Log("err", err)
appLogger.ErrorContext(ctx, "log rotation error", "err", err)
}
}
}()
+6 -6
View File
@@ -6,21 +6,21 @@ import (
"encoding/json"
"errors"
"io/fs"
"log/slog"
"os"
"path/filepath"
"testing"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFilesystemLogger(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
tempPath := t.TempDir()
require.NoError(t, os.Chmod(tempPath, 0o755)) // nolint:gosec // G302
fileName := filepath.Join(tempPath, "filesystemLogWriter")
lgr, err := NewFilesystemLogWriter(fileName, platformlogging.NewNopLogger(), false, false, 500, 28, 3)
lgr, err := NewFilesystemLogWriter(ctx, fileName, slog.New(slog.DiscardHandler), false, false, 500, 28, 3)
require.Nil(t, err)
defer os.Remove(fileName)
@@ -73,7 +73,7 @@ func TestFilesystemLoggerPermission(t *testing.T) {
{name: "without-rotation", rotation: false},
} {
t.Run(tc.name, func(t *testing.T) {
_, err := NewFilesystemLogWriter(fileName, platformlogging.NewNopLogger(), tc.rotation, false, 500, 28, 3)
_, err := NewFilesystemLogWriter(t.Context(), fileName, slog.New(slog.DiscardHandler), tc.rotation, false, 500, 28, 3)
require.Error(t, err)
require.True(t, errors.Is(err, fs.ErrPermission), err)
})
@@ -83,7 +83,7 @@ func TestFilesystemLoggerPermission(t *testing.T) {
func BenchmarkFilesystemLogger(b *testing.B) {
ctx := context.Background()
fileName := filepath.Join(b.TempDir(), "filesystemLogWriter")
lgr, err := NewFilesystemLogWriter(fileName, platformlogging.NewNopLogger(), false, false, 500, 28, 3)
lgr, err := NewFilesystemLogWriter(ctx, fileName, slog.New(slog.DiscardHandler), false, false, 500, 28, 3)
if err != nil {
b.Fatal("new failed ", err)
}
@@ -119,7 +119,7 @@ func BenchmarkLumberjackWithCompression(b *testing.B) {
func benchLumberjack(b *testing.B, compression bool) {
ctx := context.Background()
fileName := filepath.Join(b.TempDir(), "lumberjack")
lgr, err := NewFilesystemLogWriter(fileName, platformlogging.NewNopLogger(), true, compression, 500, 28, 3)
lgr, err := NewFilesystemLogWriter(ctx, fileName, slog.New(slog.DiscardHandler), true, compression, 500, 28, 3)
if err != nil {
b.Fatal("new failed ", err)
}
+4 -6
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"math"
"time"
@@ -15,8 +16,6 @@ import (
"github.com/aws/aws-sdk-go-v2/service/firehose/types"
"github.com/fleetdm/fleet/v4/server/aws_common"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/go-kit/log/level"
)
const (
@@ -38,10 +37,10 @@ type FirehoseAPI interface {
type firehoseLogWriter struct {
client FirehoseAPI
stream string
logger *platformlogging.Logger
logger *slog.Logger
}
func NewFirehoseLogWriter(region, endpointURL, id, secret, stsAssumeRoleArn, stsExternalID, stream string, logger *platformlogging.Logger) (*firehoseLogWriter, error) {
func NewFirehoseLogWriter(region, endpointURL, id, secret, stsAssumeRoleArn, stsExternalID, stream string, logger *slog.Logger) (*firehoseLogWriter, error) {
var opts []func(*aws_config.LoadOptions) error
// The service endpoint is deprecated, but we still set it
@@ -121,8 +120,7 @@ func (f *firehoseLogWriter) Write(ctx context.Context, logs []json.RawMessage) e
// the beginning bytes of the log should help the Fleet admin
// diagnose the query generating huge results.
if len(log) > firehoseMaxSizeOfRecord {
level.Info(f.logger).Log(
"msg", "dropping log over 1MB Firehose limit",
f.logger.InfoContext(ctx, "dropping log over 1MB Firehose limit",
"size", len(log),
"log", string(log[:100])+"...",
)
+2 -2
View File
@@ -4,13 +4,13 @@ import (
"context"
"encoding/json"
"errors"
"log/slog"
"testing"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/firehose"
"github.com/aws/aws-sdk-go-v2/service/firehose/types"
"github.com/fleetdm/fleet/v4/server/logging/mock"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/stretchr/testify/assert"
)
@@ -31,7 +31,7 @@ func makeFirehoseWriterWithMock(client FirehoseAPI, stream string) *firehoseLogW
return &firehoseLogWriter{
client: client,
stream: stream,
logger: platformlogging.NewNopLogger(),
logger: slog.New(slog.DiscardHandler),
}
}
+4 -6
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"math"
"math/rand"
"time"
@@ -17,8 +18,6 @@ import (
smithy "github.com/aws/smithy-go"
"github.com/fleetdm/fleet/v4/server/aws_common"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/go-kit/log/level"
)
const (
@@ -40,11 +39,11 @@ type KinesisAPI interface {
type kinesisLogWriter struct {
client KinesisAPI
stream string
logger *platformlogging.Logger
logger *slog.Logger
rand *rand.Rand
}
func NewKinesisLogWriter(region, endpointURL, id, secret, stsAssumeRoleArn, stsExternalID, stream string, logger *platformlogging.Logger) (*kinesisLogWriter, error) {
func NewKinesisLogWriter(region, endpointURL, id, secret, stsAssumeRoleArn, stsExternalID, stream string, logger *slog.Logger) (*kinesisLogWriter, error) {
var opts []func(*aws_config.LoadOptions) error
// The service endpoint is deprecated, but we still set it
@@ -131,8 +130,7 @@ func (k *kinesisLogWriter) Write(ctx context.Context, logs []json.RawMessage) er
// the beginning bytes of the log should help the Fleet admin
// diagnose the query generating huge results.
if len(log)+len(partitionKey) > kinesisMaxSizeOfRecord {
level.Info(k.logger).Log(
"msg", "dropping log over 1MB Kinesis limit",
k.logger.InfoContext(ctx, "dropping log over 1MB Kinesis limit",
"size", len(log),
"log", string(log[:100])+"...",
)
+2 -2
View File
@@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"errors"
"log/slog"
"math/rand"
"testing"
"time"
@@ -13,7 +14,6 @@ import (
"github.com/aws/aws-sdk-go-v2/service/kinesis"
"github.com/aws/aws-sdk-go-v2/service/kinesis/types"
"github.com/fleetdm/fleet/v4/server/logging/mock"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/stretchr/testify/assert"
)
@@ -21,7 +21,7 @@ func makeKinesisWriterWithMock(client KinesisAPI, stream string) *kinesisLogWrit
return &kinesisLogWriter{
client: client,
stream: stream,
logger: platformlogging.NewNopLogger(),
logger: slog.New(slog.DiscardHandler),
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
}
}
+4 -6
View File
@@ -4,14 +4,13 @@ import (
"context"
"encoding/json"
"fmt"
"log/slog"
aws_config "github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/lambda"
"github.com/aws/aws-sdk-go-v2/service/lambda/types"
"github.com/fleetdm/fleet/v4/server/aws_common"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/go-kit/log/level"
)
const (
@@ -30,10 +29,10 @@ type LambdaAPI interface {
type lambdaLogWriter struct {
client LambdaAPI
functionName string
logger *platformlogging.Logger
logger *slog.Logger
}
func NewLambdaLogWriter(region, id, secret, stsAssumeRoleArn, stsExternalID, functionName string, logger *platformlogging.Logger) (*lambdaLogWriter, error) {
func NewLambdaLogWriter(region, id, secret, stsAssumeRoleArn, stsExternalID, functionName string, logger *slog.Logger) (*lambdaLogWriter, error) {
var opts []func(*aws_config.LoadOptions) error
// Only provide static credentials if we have them
@@ -97,8 +96,7 @@ func (f *lambdaLogWriter) Write(ctx context.Context, logs []json.RawMessage) err
// that are too big for Lambda. This behavior is consistent
// with other logging plugins.
if len(log) > lambdaMaxSizeOfPayload {
level.Info(f.logger).Log(
"msg", "dropping log over 6MB Lambda limit",
f.logger.InfoContext(ctx, "dropping log over 6MB Lambda limit",
"size", len(log),
"log", string(log[:100])+"...",
)
+2 -2
View File
@@ -3,13 +3,13 @@ package logging
import (
"context"
"errors"
"log/slog"
"testing"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/lambda"
"github.com/aws/aws-sdk-go-v2/service/lambda/types"
"github.com/fleetdm/fleet/v4/server/logging/mock"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/fleetdm/fleet/v4/server/test"
"github.com/stretchr/testify/assert"
tmock "github.com/stretchr/testify/mock"
@@ -19,7 +19,7 @@ func makeLambdaWriterWithMock(client LambdaAPI, functionName string) *lambdaLogW
return &lambdaLogWriter{
client: client,
functionName: functionName,
logger: platformlogging.NewNopLogger(),
logger: slog.New(slog.DiscardHandler),
}
}
+7 -7
View File
@@ -2,12 +2,12 @@
package logging
import (
"context"
"fmt"
"log/slog"
"time"
"github.com/fleetdm/fleet/v4/server/fleet"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/go-kit/log/level"
)
type FilesystemConfig struct {
@@ -101,17 +101,15 @@ type Config struct {
Nats NatsConfig
}
func NewJSONLogger(name string, config Config, logger *platformlogging.Logger) (fleet.JSONLogger, error) {
func NewJSONLogger(ctx context.Context, name string, config Config, logger *slog.Logger) (fleet.JSONLogger, error) {
switch config.Plugin {
case "":
// Allow "" to mean filesystem for backwards compatibility
level.Info(logger).Log(
"msg",
fmt.Sprintf("plugin for %s not explicitly specified. Assuming 'filesystem'", name),
)
logger.InfoContext(ctx, fmt.Sprintf("plugin for %s not explicitly specified. Assuming 'filesystem'", name))
fallthrough
case "filesystem":
writer, err := NewFilesystemLogWriter(
ctx,
config.Filesystem.LogFile,
logger,
config.Filesystem.EnableLogRotation,
@@ -176,6 +174,7 @@ func NewJSONLogger(name string, config Config, logger *platformlogging.Logger) (
return fleet.JSONLogger(writer), nil
case "pubsub":
writer, err := NewPubSubLogWriter(
ctx,
config.PubSub.Project,
config.PubSub.Topic,
config.PubSub.AddAttributes,
@@ -204,6 +203,7 @@ func NewJSONLogger(name string, config Config, logger *platformlogging.Logger) (
return fleet.JSONLogger(writer), nil
case "nats":
writer, err := NewNatsLogWriter(
ctx,
config.Nats.Server,
config.Nats.Subject,
config.Nats.CredFile,
+8 -15
View File
@@ -7,6 +7,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"reflect"
"strconv"
"strings"
@@ -15,8 +16,6 @@ import (
"github.com/expr-lang/expr"
"github.com/expr-lang/expr/ast"
"github.com/expr-lang/expr/vm"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/go-kit/log/level"
"github.com/golang/snappy"
"github.com/klauspost/compress/zstd"
"github.com/nats-io/nats.go"
@@ -68,7 +67,7 @@ var compressionOk = map[string]bool{
}
// NewNatsLogWriter creates a new NATS log writer.
func NewNatsLogWriter(server, subject, credFile, nkeyFile, tlsClientCrtFile, tlsClientKeyFile, tlsCACrtFile, compression string, jetstream bool, timeout time.Duration, logger *platformlogging.Logger) (*natsLogWriter, error) {
func NewNatsLogWriter(ctx context.Context, server, subject, credFile, nkeyFile, tlsClientCrtFile, tlsClientKeyFile, tlsCACrtFile, compression string, jetstream bool, timeout time.Duration, logger *slog.Logger) (*natsLogWriter, error) {
// Ensure the NATS server is set.
if server == "" {
return nil, errors.New("nats server missing")
@@ -94,8 +93,7 @@ func NewNatsLogWriter(server, subject, credFile, nkeyFile, tlsClientCrtFile, tls
// Is a credentials file set?
if credFile != "" {
level.Debug(logger).Log(
"msg", "using credentials file",
logger.DebugContext(ctx, "using credentials file",
"file", credFile,
)
@@ -104,8 +102,7 @@ func NewNatsLogWriter(server, subject, credFile, nkeyFile, tlsClientCrtFile, tls
// Is a NKey seed file set?
if nkeyFile != "" {
level.Debug(logger).Log(
"msg", "using NKey file",
logger.DebugContext(ctx, "using NKey file",
"file", nkeyFile,
)
@@ -119,8 +116,7 @@ func NewNatsLogWriter(server, subject, credFile, nkeyFile, tlsClientCrtFile, tls
// Is a TLS client certificate and key set?
if tlsClientCrtFile != "" && tlsClientKeyFile != "" {
level.Debug(logger).Log(
"msg", "using TLS client certificate and key files",
logger.DebugContext(ctx, "using TLS client certificate and key files",
"crt", tlsClientCrtFile,
"key", tlsClientKeyFile,
)
@@ -130,16 +126,14 @@ func NewNatsLogWriter(server, subject, credFile, nkeyFile, tlsClientCrtFile, tls
// Is a CA certificate set?
if tlsCACrtFile != "" {
level.Debug(logger).Log(
"msg", "using CA certificate file",
logger.DebugContext(ctx, "using CA certificate file",
"file", tlsCACrtFile,
)
opts = append(opts, nats.RootCAs(tlsCACrtFile))
}
level.Debug(logger).Log(
"msg", "connecting to NATS server",
logger.DebugContext(ctx, "connecting to NATS server",
"server", server,
)
@@ -149,8 +143,7 @@ func NewNatsLogWriter(server, subject, credFile, nkeyFile, tlsClientCrtFile, tls
return nil, fmt.Errorf("failed to connect to nats server: %w", err)
}
level.Debug(logger).Log(
"msg", "connected to NATS server",
logger.DebugContext(ctx, "connected to NATS server",
"server", server,
)
+23 -12
View File
@@ -6,11 +6,11 @@ import (
"encoding/json"
"fmt"
"io"
"log/slog"
"sync"
"testing"
"time"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/golang/snappy"
"github.com/klauspost/compress/zstd"
"github.com/nats-io/nats-server/v2/server"
@@ -189,6 +189,7 @@ func TestNatsLogWriter(t *testing.T) {
// Create the NATS log writer, specifying that the logs should be
// published directly to the NATS subject, without using JetStream.
writer, err := NewNatsLogWriter(
t.Context(),
ns.ClientURL(),
natsTestDirectSubject,
"",
@@ -199,7 +200,7 @@ func TestNatsLogWriter(t *testing.T) {
"",
false,
natsTestTimeout,
platformlogging.NewNopLogger(),
slog.New(slog.DiscardHandler),
)
require.NoError(t, err)
@@ -231,6 +232,7 @@ func TestNatsLogWriter(t *testing.T) {
// Create the NATS log writer with a template subject that requires
// parsing the JSON to route the message.
writer, err := NewNatsLogWriter(
t.Context(),
ns.ClientURL(),
natsTestDirectSubject+".invalid.{log.name}",
"",
@@ -241,7 +243,7 @@ func TestNatsLogWriter(t *testing.T) {
"",
false,
natsTestTimeout,
platformlogging.NewNopLogger(),
slog.New(slog.DiscardHandler),
)
require.NoError(t, err)
@@ -284,6 +286,7 @@ func TestNatsLogWriter(t *testing.T) {
// Create the NATS log writer, specifying that the logs should be
// published to the JetStream stream.
writer, err := NewNatsLogWriter(
t.Context(),
ns.ClientURL(),
natsTestStreamSubject,
"",
@@ -294,7 +297,7 @@ func TestNatsLogWriter(t *testing.T) {
"",
true,
natsTestTimeout,
platformlogging.NewNopLogger(),
slog.New(slog.DiscardHandler),
)
require.NoError(t, err)
@@ -338,6 +341,7 @@ func TestNatsLogWriter(t *testing.T) {
// Create the NATS log writer with a template subject that requires
// parsing the JSON to route the message.
writer, err := NewNatsLogWriter(
t.Context(),
ns.ClientURL(),
natsTestStreamSubject+".invalid.{log.name}",
"",
@@ -348,7 +352,7 @@ func TestNatsLogWriter(t *testing.T) {
"",
true,
natsTestTimeout,
platformlogging.NewNopLogger(),
slog.New(slog.DiscardHandler),
)
require.NoError(t, err)
@@ -411,6 +415,7 @@ func TestNatsLogWriter(t *testing.T) {
// Create the NATS log writer with gzip compression enabled.
writer, err := NewNatsLogWriter(
t.Context(),
ns.ClientURL(),
natsTestDirectSubject+".gzip",
"",
@@ -421,7 +426,7 @@ func TestNatsLogWriter(t *testing.T) {
"gzip",
false,
natsTestTimeout,
platformlogging.NewNopLogger(),
slog.New(slog.DiscardHandler),
)
require.NoError(t, err)
@@ -456,6 +461,7 @@ func TestNatsLogWriter(t *testing.T) {
// Create the NATS log writer with gzip compression enabled.
writer, err := NewNatsLogWriter(
t.Context(),
ns.ClientURL(),
natsTestStreamSubject+".gzip",
"",
@@ -466,7 +472,7 @@ func TestNatsLogWriter(t *testing.T) {
"gzip",
true,
natsTestTimeout,
platformlogging.NewNopLogger(),
slog.New(slog.DiscardHandler),
)
require.NoError(t, err)
@@ -538,6 +544,7 @@ func TestNatsLogWriter(t *testing.T) {
// Create the NATS log writer with snappy compression enabled.
writer, err := NewNatsLogWriter(
t.Context(),
ns.ClientURL(),
natsTestDirectSubject+".snappy",
"",
@@ -548,7 +555,7 @@ func TestNatsLogWriter(t *testing.T) {
"snappy",
false,
natsTestTimeout,
platformlogging.NewNopLogger(),
slog.New(slog.DiscardHandler),
)
require.NoError(t, err)
@@ -604,6 +611,7 @@ func TestNatsLogWriter(t *testing.T) {
// Create the NATS log writer with zstd compression enabled.
writer, err := NewNatsLogWriter(
t.Context(),
ns.ClientURL(),
natsTestDirectSubject+".zstd",
"",
@@ -614,7 +622,7 @@ func TestNatsLogWriter(t *testing.T) {
"zstd",
false,
natsTestTimeout,
platformlogging.NewNopLogger(),
slog.New(slog.DiscardHandler),
)
require.NoError(t, err)
@@ -649,6 +657,7 @@ func TestNatsLogWriter(t *testing.T) {
// Create the NATS log writer with snappy compression enabled.
writer, err := NewNatsLogWriter(
t.Context(),
ns.ClientURL(),
natsTestStreamSubject+".snappy",
"",
@@ -659,7 +668,7 @@ func TestNatsLogWriter(t *testing.T) {
"snappy",
true,
natsTestTimeout,
platformlogging.NewNopLogger(),
slog.New(slog.DiscardHandler),
)
require.NoError(t, err)
@@ -711,6 +720,7 @@ func TestNatsLogWriter(t *testing.T) {
// Create the NATS log writer with zstd compression enabled.
writer, err := NewNatsLogWriter(
t.Context(),
ns.ClientURL(),
natsTestStreamSubject+".zstd",
"",
@@ -721,7 +731,7 @@ func TestNatsLogWriter(t *testing.T) {
"zstd",
true,
natsTestTimeout,
platformlogging.NewNopLogger(),
slog.New(slog.DiscardHandler),
)
require.NoError(t, err)
@@ -764,6 +774,7 @@ func TestNatsLogWriter(t *testing.T) {
// Attempt to create a NATS log writer with an invalid compression
// algorithm.
_, err := NewNatsLogWriter(
t.Context(),
ns.ClientURL(),
natsTestDirectSubject,
"",
@@ -774,7 +785,7 @@ func TestNatsLogWriter(t *testing.T) {
"invalid",
false,
natsTestTimeout,
platformlogging.NewNopLogger(),
slog.New(slog.DiscardHandler),
)
// Ensure an error is returned.
+5 -10
View File
@@ -4,17 +4,16 @@ import (
"context"
"encoding/json"
"fmt"
"log/slog"
"time"
"cloud.google.com/go/pubsub"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/go-kit/log/level"
)
type pubSubLogWriter struct {
topic *pubsub.Topic
logger *platformlogging.Logger
logger *slog.Logger
addAttributes bool
}
@@ -24,9 +23,7 @@ type PubSubAttributes struct {
Decorations map[string]string `json:"decorations"`
}
func NewPubSubLogWriter(projectId string, topicName string, addAttributes bool, logger *platformlogging.Logger) (*pubSubLogWriter, error) {
ctx := context.Background()
func NewPubSubLogWriter(ctx context.Context, projectId string, topicName string, addAttributes bool, logger *slog.Logger) (*pubSubLogWriter, error) {
client, err := pubsub.NewClient(ctx, projectId)
if err != nil {
return nil, fmt.Errorf("create pubsub client: %w", err)
@@ -34,8 +31,7 @@ func NewPubSubLogWriter(projectId string, topicName string, addAttributes bool,
topic := client.Topic(topicName)
level.Info(logger).Log(
"msg", "GCP PubSub writer configured",
logger.InfoContext(ctx, "GCP PubSub writer configured",
"project", projectId,
"topic", topicName,
"add_attributes", addAttributes,
@@ -82,8 +78,7 @@ func (w *pubSubLogWriter) Write(ctx context.Context, logs []json.RawMessage) err
}
if len(data)+estimateAttributeSize(attributes) > pubsub.MaxPublishRequestBytes {
level.Info(w.logger).Log(
"msg", "dropping log over 10MB PubSub limit",
w.logger.InfoContext(ctx, "dropping log over 10MB PubSub limit",
"size", len(data),
"log", string(log[:100])+"...",
)
+6 -9
View File
@@ -5,19 +5,18 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"time"
"github.com/fleetdm/fleet/v4/server"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/go-kit/kit/log/level"
)
type webhookLogWriter struct {
url string
logger *platformlogging.Logger
logger *slog.Logger
}
func NewWebhookLogWriter(webhookURL string, logger *platformlogging.Logger) (*webhookLogWriter, error) {
func NewWebhookLogWriter(webhookURL string, logger *slog.Logger) (*webhookLogWriter, error) {
if webhookURL == "" {
return nil, errors.New("webhook URL missing")
}
@@ -40,14 +39,12 @@ func (w *webhookLogWriter) Write(ctx context.Context, logs []json.RawMessage) er
Details: logs,
}
level.Debug(w.logger).Log(
"msg", "sending webhook request",
w.logger.DebugContext(ctx, "sending webhook request",
"url", server.MaskSecretURLParams(w.url),
)
if err := server.PostJSONWithTimeout(ctx, w.url, payload, w.logger.SlogLogger()); err != nil {
level.Error(w.logger).Log(
"msg", fmt.Sprintf("failed to send automation webhook to %s", server.MaskSecretURLParams(w.url)),
if err := server.PostJSONWithTimeout(ctx, w.url, payload, w.logger); err != nil {
w.logger.ErrorContext(ctx, fmt.Sprintf("failed to send automation webhook to %s", server.MaskSecretURLParams(w.url)),
"err", server.MaskURLError(err).Error(),
)
}
+3 -3
View File
@@ -3,18 +3,18 @@ package logging
import (
"context"
"encoding/json"
"log/slog"
"net/http"
"net/http/httptest"
"testing"
"time"
platformlogging "github.com/fleetdm/fleet/v4/server/platform/logging"
"github.com/stretchr/testify/require"
)
func TestWebhookSubmission(t *testing.T) {
ctx := context.Background()
logger := platformlogging.NewNopLogger()
logger := slog.New(slog.DiscardHandler)
var body struct {
Timestamp time.Time `json:"timestamp"`
Details []json.RawMessage `json:"details"`
@@ -42,7 +42,7 @@ func TestWebhookSubmission(t *testing.T) {
func TestWebhookFailure(t *testing.T) {
ctx := context.Background()
logger := platformlogging.NewNopLogger()
logger := slog.New(slog.DiscardHandler)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "bad", http.StatusBadRequest)
}))
+4 -4
View File
@@ -6,6 +6,7 @@ import (
"context"
"crypto/sha256"
"fmt"
"log/slog"
"strconv"
"strings"
"sync"
@@ -14,7 +15,6 @@ import (
"github.com/fleetdm/fleet/v4/ee/server/calendar"
"github.com/fleetdm/fleet/v4/server/config"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/platform/logging"
)
const (
@@ -56,7 +56,7 @@ type PolicyLiteWithMeta struct {
mu sync.Mutex
}
func CreateUserCalendarFromConfig(ctx context.Context, config *Config, logger *logging.Logger) fleet.UserCalendar {
func CreateUserCalendarFromConfig(ctx context.Context, config *Config, logger *slog.Logger) fleet.UserCalendar {
googleCalendarConfig := calendar.GoogleCalendarConfig{
Context: ctx,
IntegrationConfig: &config.GoogleCalendarIntegration,
@@ -67,7 +67,7 @@ func CreateUserCalendarFromConfig(ctx context.Context, config *Config, logger *l
}
func GenerateCalendarEventBody(ctx context.Context, ds fleet.Datastore, orgName string, host fleet.HostPolicyMembershipData,
policyIDtoPolicy *sync.Map, conflict bool, logger *logging.Logger,
policyIDtoPolicy *sync.Map, conflict bool, logger *slog.Logger,
) (body string, tag string) {
description, resolution, tag := getCalendarEventDescriptionAndResolution(ctx, ds, orgName, host, policyIDtoPolicy, logger)
@@ -88,7 +88,7 @@ Please leave your device on and connected to power.
}
func getCalendarEventDescriptionAndResolution(ctx context.Context, ds fleet.Datastore, orgName string, host fleet.HostPolicyMembershipData,
policyIDtoPolicy *sync.Map, logger *logging.Logger,
policyIDtoPolicy *sync.Map, logger *slog.Logger,
) (description string, resolution string, tag string) {
getDefaultDescription := func() string {
return fmt.Sprintf(`%s %s`, orgName, fleet.CalendarDefaultDescription)
+1 -1
View File
@@ -79,7 +79,7 @@ func newTestService(t *testing.T, ds fleet.Datastore, rs fleet.QueryResultStore,
func newTestServiceWithConfig(t *testing.T, ds fleet.Datastore, fleetConfig config.FleetConfig, rs fleet.QueryResultStore, lq fleet.LiveQueryStore, opts ...*TestServerOpts) (fleet.Service, context.Context) {
lic := &fleet.LicenseInfo{Tier: fleet.TierFree}
logger := platformlogging.NewNopLogger()
writer, err := logging.NewFilesystemLogWriter(fleetConfig.Filesystem.StatusLogFile, logger, fleetConfig.Filesystem.EnableLogRotation,
writer, err := logging.NewFilesystemLogWriter(t.Context(), fleetConfig.Filesystem.StatusLogFile, logger.SlogLogger(), fleetConfig.Filesystem.EnableLogRotation,
fleetConfig.Filesystem.EnableLogCompression, 500, 28, 3)
require.NoError(t, err)