diff --git a/append_lifecycle.go b/append_lifecycle.go index e8ce5890..bd3a6da7 100644 --- a/append_lifecycle.go +++ b/append_lifecycle.go @@ -282,6 +282,7 @@ func NewAppender(ctx context.Context, d Driver, opts *AppendOptions) (*Appender, if opts == nil { return nil, nil, nil, errors.New("opts cannot be nil") } + slog.InfoContext(ctx, "Creating new appender", slog.Any("options", opts)) if err := opts.valid(); err != nil { return nil, nil, nil, err } @@ -973,3 +974,55 @@ func (o *AppendOptions) WithShutdownTimeout(timeout time.Duration) *AppendOption o.shutdownTimeout = timeout return o } + +// LogValue implements slog.LogValuer to allow safe serialization of AppendOptions. +func (o *AppendOptions) LogValue() slog.Value { + if o == nil { + return slog.Value{} + } + + attrs := []slog.Attr{ + slog.Duration("batchMaxAge", o.batchMaxAge), + slog.Uint64("batchMaxSize", uint64(o.batchMaxSize)), + slog.Uint64("pushbackMaxOutstanding", uint64(o.pushbackMaxOutstanding)), + slog.Uint64("maxEntrySize", uint64(o.maxEntrySize)), + slog.Duration("checkpointInterval", o.checkpointInterval), + slog.Duration("checkpointRepublishInterval", o.checkpointRepublishInterval), + slog.Duration("garbageCollectionInterval", o.garbageCollectionInterval), + slog.Duration("shutdownTimeout", o.shutdownTimeout), + } + + if o.primarySigner != nil { + attrs = append(attrs, slog.String("primarySigner", o.primarySigner.Name())) + } + + if len(o.additionalSigners) > 0 { + names := make([]string, len(o.additionalSigners)) + for i, s := range o.additionalSigners { + names[i] = s.Name() + } + attrs = append(attrs, slog.Any("additionalSigners", names)) + } + + if len(o.witnesses.Components) > 0 { + endpoints := o.witnesses.Endpoints() + urls := make([]string, 0, len(endpoints)) + for u := range endpoints { + urls = append(urls, u) + } + attrs = append(attrs, slog.Group("witnesses", + slog.Int("threshold", o.witnesses.N), + slog.Any("endpoints", urls), + )) + } + + if len(o.followers) > 0 { + names := make([]string, len(o.followers)) + for i, f := range o.followers { + names[i] = f.Name() + } + attrs = append(attrs, slog.Any("followers", names)) + } + + return slog.GroupValue(attrs...) +} diff --git a/cmd/conformance/aws/main.go b/cmd/conformance/aws/main.go index 52a7393d..e4901b64 100644 --- a/cmd/conformance/aws/main.go +++ b/cmd/conformance/aws/main.go @@ -55,6 +55,7 @@ var ( publishInterval = flag.Duration("publish_interval", 3*time.Second, "How frequently to publish updated checkpoints") traceFraction = flag.Float64("trace_fraction", 0, "Fraction of open-telemetry span traces to sample") slogLevel = flag.Int("slog_level", 0, "The cut-off threshold for structured logging. Default is 0 (INFO). See https://pkg.go.dev/log/slog#Level for other levels.") + logFormat = flag.String("log_format", "text", "The format of the logs: text or json.") additionalSigners = []string{} antispamEnable = flag.Bool("antispam", false, "EXPERIMENTAL: Set to true to enable persistent antispam storage") @@ -71,7 +72,14 @@ func init() { func main() { flag.Parse() ctx := context.Background() - slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.Level(*slogLevel)}))) + var handler slog.Handler + switch *logFormat { + case "json": + handler = slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.Level(*slogLevel)}) + default: + handler = slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.Level(*slogLevel)}) + } + slog.SetDefault(slog.New(handler)) shutdownOTel := initOTel(ctx, *traceFraction) defer shutdownOTel(ctx) diff --git a/cmd/conformance/gcp/main.go b/cmd/conformance/gcp/main.go index 82ccd86e..a3382464 100644 --- a/cmd/conformance/gcp/main.go +++ b/cmd/conformance/gcp/main.go @@ -44,6 +44,7 @@ var ( projectID = flag.String("project", "", "GCP Project ID for Cloud Logging traces (optional)") additionalSigners = []string{} slogLevel = flag.Int("slog_level", 0, "The cut-off threshold for structured logging. Default is 0 (INFO). See https://pkg.go.dev/log/slog#Level for other levels.") + logFormat = flag.String("log_format", "json", "The format of the logs: text or json.") ) func init() { @@ -57,7 +58,13 @@ func main() { flag.Parse() ctx := context.Background() - handler := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.Level(*slogLevel)}) + var handler slog.Handler + switch *logFormat { + case "text": + handler = slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.Level(*slogLevel)}) + default: + handler = slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.Level(*slogLevel)}) + } slog.SetDefault(slog.New(logger.NewGCPContextHandler(handler, *projectID))) shutdownOTel := initOTel(ctx, *traceFraction) diff --git a/cmd/conformance/posix/README.md b/cmd/conformance/posix/README.md index 0faf6182..6dbf465e 100644 --- a/cmd/conformance/posix/README.md +++ b/cmd/conformance/posix/README.md @@ -19,7 +19,7 @@ Then, start the personality: ```shell go run ./cmd/conformance/posix \ --storage_dir=${LOG_DIR} \ - --listen=:2025 \ + --listen=:2025 ``` ## Add entries to the log diff --git a/cmd/conformance/posix/main.go b/cmd/conformance/posix/main.go index bf5f9d14..99f3fe50 100644 --- a/cmd/conformance/posix/main.go +++ b/cmd/conformance/posix/main.go @@ -44,6 +44,7 @@ var ( persistentAntispam = flag.Bool("antispam", false, "EXPERIMENTAL: Set to true to enable Badger-based persistent antispam storage") additionalPrivateKeyFiles = []string{} slogLevel = flag.Int("slog_level", 0, "The cut-off threshold for structured logging. Default is 0 (INFO). See https://pkg.go.dev/log/slog#Level for other levels.") + logFormat = flag.String("log_format", "text", "The format of the logs: text or json.") ) func init() { @@ -63,7 +64,14 @@ func addCacheHeaders(value string, fs http.Handler) http.HandlerFunc { func main() { flag.Parse() ctx := context.Background() - slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.Level(*slogLevel)}))) + var handler slog.Handler + switch *logFormat { + case "json": + handler = slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.Level(*slogLevel)}) + default: + handler = slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.Level(*slogLevel)}) + } + slog.SetDefault(slog.New(handler)) // Gather the info needed for reading/writing checkpoints s, a := getSignersOrDie()