Generated banner for Golang Samber Slog
Generated logo for Golang Samber Slog

Golang Samber Slog

Samuel BertheCommunityCreated by samberDistributed by Samuel Berthe

  • Skill
  • Tool integration
  • Software development
  • MIT
  • Medium risk

From the author

Structured logging extensions for Golang using samber/slog-**** packages — multi-handler pipelines (slog-multi), log sampling (slog-sampling), attribute formatting (slog-formatter), HTTP middleware (slog-fiber, slog-gin, slog-chi, slog-echo), and backend routing (slog-datadog, slog-sentry, slog-loki, slog-syslog, slog-logstash, slog-graylog...). Apply when using or adopting slog, or when the codebase already imports any github.com/samber/slog-* package.
— the description by samber

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The samber/slog collection provides over 20 composable packages that extend the standard Go slog library. It includes tools for handler composition, log sampling, attribute formatting, HTTP middleware for common web frameworks, and various backend sinks for log delivery. The library follows a canonical pipeline model where records flow through sampling, formatting, and routing stages to reach their final destinations.

What it does

  • Composes multiple log handlers using fanout, routing, and failover patterns.
  • Controls log throughput via uniform, threshold, or absolute sampling strategies.
  • Transforms log attributes using formatters for PII masking, error handling, and data flattening.
  • Integrates with web frameworks like Gin, Echo, Fiber, and Chi to log HTTP requests.
  • Routes logs to various backends including Datadog, Sentry, Loki, Kafka, and others.
  • Provides middleware for injecting request-scoped attributes into log records.

When to use it

  • When you need to route logs to multiple destinations simultaneously.
  • When you need to reduce log volume using sampling strategies.
  • When you need to scrub PII or format attributes before logs leave your application.
  • When you need to integrate structured logging into Gin, Echo, Fiber, or Chi web applications.
  • When you need to send logs to external services like Datadog, Sentry, or Loki.

Advantages

  • Implements the standard slog.Handler interface for compatibility.
  • Supports complex pipeline architectures with modular components.
  • Provides consistent configuration patterns across different HTTP frameworks.
  • Includes built-in predicates for conditional log routing.
  • Offers specialized formatters for common tasks like error and IP address handling.

Usage examples

“How do I route error logs to Sentry while sending all logs to stdout?”
The agent provides a code snippet using slogmulti.Router to add a Sentry handler with a LevelIs(slog.LevelError) predicate alongside a standard JSON handler.
“How can I mask PII in my logs?”
The agent demonstrates using slogformatter.NewFormatterMiddleware with PIIFormatter to automatically mask sensitive fields before they reach the log handler.
“How do I add logging to my Gin router?”
The agent shows how to use sloggin.NewWithConfig to integrate structured logging into a Gin application, including options for filtering paths.
“How do I ensure logs are not lost when using Datadog?”
The agent explains the requirement to call the Stop method on the handler during application shutdown to flush buffered logs.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/samber/golang-samber-slog/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip golang-samber-slog.zip -d .agents/skills

Documentation by samber

Persona: You are a Go logging architect. You design log pipelines where every record flows through the right handlers — sampling drops noise early, formatters strip PII before records leave the process, and routers send errors to Sentry while info goes to Loki.

samber/slog-**** — Structured Logging Pipeline for Go

20+ composable slog.Handler packages for Go 1.21+. Three core pipeline libraries plus HTTP middlewares and backend sinks that all implement the standard slog.Handler interface.

Official resources:

This skill is not exhaustive — refer to library documentation and code examples for more information:

  • For Go package docs, symbols, versions, importers, and known vulnerabilities, → See samber/cc-skills-golang@golang-pkg-go-dev skill (godig), preferred over Context7 for Go package facts.

  • To navigate this library's usage in your own code (definitions, call sites, diagnostics), → See samber/cc-skills-golang@golang-gopls skill (gopls).

  • Context7 remains a fallback for docs not indexed on pkg.go.dev.

The Pipeline Model

Every samber/slog pipeline follows a canonical ordering. Records flow left to right — place sampling first to drop early and avoid wasting CPU on records that never reach a sink.

record → [Sampling] → [Pipe: trace/PII] → [Router] → [Sinks]

Order matters: sampling before formatting saves CPU. Formatting before routing ensures all sinks receive clean attributes. Reversing this wastes work on records that get dropped.

Core Libraries

LibraryPurposeKey constructors
slog-multiHandler compositionFanout, Router, FirstMatch, Failover, Pool, Pipe
slog-samplingThroughput controlUniformSamplingOption, ThresholdSamplingOption, AbsoluteSamplingOption, CustomSamplingOption
slog-formatterAttribute transformsPIIFormatter, ErrorFormatter, FormatByType[T], FormatByKey, FlattenFormatterMiddleware

slog-multi — Handler Composition

Six composition patterns, each for a different routing need:

PatternBehaviorLatency impact
Fanout(handlers...)Broadcast to all handlers sequentiallySum of all handler latencies
Router().Add(h, predicate).Handler()Route to ALL matching handlersSum of matching handlers
Router().Add(...).FirstMatch().Handler()Route to FIRST match onlySingle handler latency
Failover()(handlers...)Try sequentially until one succeedsPrimary handler latency (happy path)
Pool()(handlers...)Load-balance: sends each record to ONE handlerSingle handler latency
Pipe(middlewares...).Handler(sink)Middleware chain before sinkMiddleware overhead + sink
// Route errors to Sentry, all logs to stdout
logger := slog.New(
    slogmulti.Router().
        Add(sentryHandler, slogmulti.LevelIs(slog.LevelError)).
        Add(slog.NewJSONHandler(os.Stdout, nil)).
        Handler(),
)

Built-in predicates: LevelIs, LevelIsNot, MessageIs, MessageIsNot, MessageContains, MessageNotContains, AttrValueIs, AttrKindIs.

For full code examples of every pattern, see Pipeline Patterns.

slog-sampling — Throughput Control

StrategyBehaviorBest for
UniformDrop fixed % of all recordsDev/staging noise reduction
ThresholdLog first N per interval, then sample at rate RProduction — preserves initial visibility
AbsoluteCap at N records per interval globallyHard cost control
CustomUser function returns sample rate per recordLevel-aware or time-aware rules

Sampling MUST be the outermost handler in the pipeline — placing it after formatting wastes CPU on records that get dropped.

// Threshold: log first 10 per 5s, then 10% — errors always pass through via Router
logger := slog.New(
    slogmulti.
        Pipe(slogsampling.ThresholdSamplingOption{
            Tick: 5 * time.Second, Threshold: 10, Rate: 0.1,
        }.NewMiddleware()).
        Handler(innerHandler),
)

Matchers group similar records for deduplication: MatchByLevel(), MatchByMessage(), MatchByLevelAndMessage() (default), MatchBySource(), MatchByAttribute(groups, key).

For strategy comparison and configuration details, see Sampling Strategies.

slog-formatter — Attribute Transformation

Apply as a Pipe middleware so all downstream handlers receive clean attributes.

logger := slog.New(
    slogmulti.Pipe(slogformatter.NewFormatterMiddleware(
        slogformatter.PIIFormatter("user"),          // mask PII fields
        slogformatter.ErrorFormatter("error"),       // structured error info
        slogformatter.IPAddressFormatter("client"),  // mask IP addresses
    )).Handler(slog.NewJSONHandler(os.Stdout, nil)),
)

Key formatters: PIIFormatter, ErrorFormatter, TimeFormatter, UnixTimestampFormatter, IPAddressFormatter, HTTPRequestFormatter, HTTPResponseFormatter. Generic formatters: FormatByType[T], FormatByKey, FormatByKind, FormatByGroup, FormatByGroupKey. Flatten nested attributes with FlattenFormatterMiddleware.

HTTP Middlewares

Consistent pattern across frameworks: router.Use(slogXXX.New(logger)).

Available: slog-gin, slog-echo, slog-fiber, slog-chi, slog-http (net/http).

All share a Config struct with: DefaultLevel, ClientErrorLevel, ServerErrorLevel, WithRequestBody, WithResponseBody, WithUserAgent, WithRequestID, WithTraceID, WithSpanID, Filters.

// Gin with filters — skip health checks
router.Use(sloggin.NewWithConfig(logger, sloggin.Config{
    DefaultLevel:     slog.LevelInfo,
    ClientErrorLevel: slog.LevelWarn,
    ServerErrorLevel: slog.LevelError,
    WithRequestBody:  true,
    Filters: []sloggin.Filter{
        sloggin.IgnorePath("/health", "/metrics"),
    },
}))

For framework-specific setup, see HTTP Middlewares.

Backend Sinks

All follow the Option{}.NewXxxHandler() constructor pattern.

CategoryPackages
Cloudslog-datadog, slog-sentry, slog-loki, slog-graylog
Messagingslog-kafka, slog-fluentd, slog-logstash, slog-nats
Notificationslog-slack, slog-telegram, slog-webhook
Storageslog-parquet
Bridgesslog-zap, slog-zerolog, slog-logrus

Batch handlers require graceful shutdown — slog-datadog, slog-loki, slog-kafka, and slog-parquet buffer records internally. Flush on shutdown (e.g., handler.Stop(ctx) for Datadog, lokiClient.Stop() for Loki, writer.Close() for Kafka) or buffered logs are lost.

For configuration examples and shutdown patterns, see Backend Handlers.

Common Mistakes

MistakeWhy it failsFix
Sampling after formattingWastes CPU formatting records that get droppedPlace sampling as outermost handler
Fanout to many synchronous handlersBlocks caller — latency is sum of all handlersUse Pool() for concurrent dispatch
Missing shutdown flush on batch handlersBuffered logs lost on shutdowndefer handler.Stop(ctx) (Datadog), defer lokiClient.Stop() (Loki), defer writer.Close() (Kafka)
Router without default/catch-all handlerUnmatched records silently droppedAdd a handler with no predicate as catch-all
AttrFromContext without HTTP middlewareContext has no request attributes to extractInstall slog-gin/echo/fiber/chi middleware first
Using Pipe with no middlewareNo-op wrapper adding per-record overheadRemove Pipe() if no middleware needed

Performance Warnings

  • Fanout latency = sum of all handler latencies (sequential). With 5 handlers at 10ms each, every log call costs 50ms. Use Pool() to reduce to max(latencies)

  • Pipe middleware adds per-record function call overhead — keep chains short (2-4 middlewares)

  • slog-formatter processes attributes sequentially — many formatters compound. For hot-path attribute formatting, prefer implementing slog.LogValuer on your types instead

  • Benchmark your pipeline with go test -bench before production deployment

Diagnose: measure per-record allocation and latency of your pipeline and identify which handler in the chain allocates most.

Best Practices

  1. Sample first, format second, route last — this canonical ordering minimizes wasted work and ensures all sinks see clean data

  2. Use Pipe for cross-cutting concerns — trace ID injection and PII scrubbing belong in middleware, not per-handler logic

  3. Test pipelines with slogmulti.NewHandleInlineHandler — assert on records reaching each stage without real sinks

  4. Use AttrFromContext to propagate request-scoped attributes from HTTP middleware to all handlers

  5. Prefer Router over Fanout when handlers need different record subsets — Router evaluates predicates and skips non-matching handlers

Cross-References

  • → See samber/cc-skills-golang@golang-observability skill for slog fundamentals (levels, context, handler setup, migration)

  • → See samber/cc-skills-golang@golang-error-handling skill for the log-or-return rule

  • → See samber/cc-skills-golang@golang-security skill for PII handling in logs

  • → See samber/cc-skills-golang@golang-samber-oops skill for structured error context with samber/oops

If you encounter a bug or unexpected behavior in any samber/slog-* package, open an issue at the relevant repository (e.g., slog-multi/issues, slog-sampling/issues).

Files

evals/evals.json

[
  {
    "id": 1,
    "name": "pipeline-ordering",
    "description": "Tests whether the model places sampling first in the pipeline (before formatting)",
    "prompt": "Set up a slog pipeline in Go using samber/slog libraries with PII scrubbing (mask email fields), error routing to Sentry, and log sampling at 10%. Show the complete handler composition using slog-multi, slog-sampling, and slog-formatter.",
    "trap": "Without the skill, the model places sampling last (after formatting) or in the middle, wasting CPU on records that get dropped",
    "assertions": [
      {"id": "1.1", "text": "Sampling is the outermost/first handler in the pipeline (applied before formatting)"},
      {"id": "1.2", "text": "Uses slog-sampling library (slogsampling) for sampling, not custom code"},
      {"id": "1.3", "text": "Uses slog-formatter for PII scrubbing (PIIFormatter or FormatByKey)"},
      {"id": "1.4", "text": "Uses slogmulti.Router or Fanout for routing to Sentry"},
      {"id": "1.5", "text": "Explains or demonstrates why sampling should be first (avoid wasted CPU on dropped records)"}
    ]
  },
  {
    "id": 2,
    "name": "router-firstmatch-vs-router-all-matches",
    "description": "Tests whether the model distinguishes Router (all matching) from Router+FirstMatch (first match only)",
    "prompt": "I have a slog-multi Router with two rules: (1) ERROR and above → PagerDuty, (2) WARN and above → Slack. My problem: ERROR logs are going to BOTH PagerDuty AND Slack. I only want errors in PagerDuty, not duplicated in Slack. How do I fix this with slog-multi?",
    "trap": "Without the skill, the model adds a LevelIs(slog.LevelWarn) predicate to the Slack handler thinking that fixes it — but WARN and above includes ERROR, so errors still reach Slack. The correct fix is Router().Add(...).FirstMatch() so routing stops at the first matching handler.",
    "assertions": [
      {"id": "2.1", "text": "Identifies that the default Router sends to ALL matching handlers (both Slack and PagerDuty match for ERROR)"},
      {"id": "2.2", "text": "Recommends using .FirstMatch() on the Router to stop at the first matching handler"},
      {"id": "2.3", "text": "Does NOT suggest just changing Slack's predicate to LevelIs(slog.LevelWarn) as the complete fix (errors still match WARN-and-above)"},
      {"id": "2.4", "text": "Shows the correct Router().Add(pagerduty, LevelIs(ERROR)).Add(slack, LevelIs(WARN)).FirstMatch().Handler() pattern"},
      {"id": "2.5", "text": "Explains the semantic difference: Router routes to ALL matches, FirstMatch routes to FIRST match only"}
    ]
  },
  {
    "id": 3,
    "name": "missing-close-batch",
    "description": "Tests whether the model remembers to call Close() on batch handlers",
    "prompt": "Set up slog to send logs to Datadog using samber/slog-datadog in a Go HTTP server with graceful shutdown. Show the complete main() function.",
    "trap": "Without the skill, the model forgets to close the handler on shutdown, causing buffered logs to be lost",
    "assertions": [
      {"id": "3.1", "text": "Calls handler.Stop(ctx) or defer handler.Stop(ctx) for the Datadog handler (not Close)"},
      {"id": "3.2", "text": "Uses Option{}.NewDatadogHandler() constructor pattern"},
      {"id": "3.3", "text": "Close happens during graceful shutdown (signal handling or defer in main)"},
      {"id": "3.4", "text": "Mentions or demonstrates that Datadog handler batches logs (data loss risk without Close)"},
      {"id": "3.5", "text": "Import path is github.com/samber/slog-datadog/v2 or later"}
    ]
  },
  {
    "id": 4,
    "name": "sampling-matcher-grouping",
    "description": "Tests whether the model understands slog-sampling Matchers for deduplication grouping",
    "prompt": "I've set up ThresholdSamplingOption in my Go service: log the first 10 per 5s, then sample at 10%. It works, but I notice that 'user not found' (DEBUG) and 'cache miss' (DEBUG) are being counted together in the same bucket. After 10 total DEBUG logs from both messages, both get sampled. I want each distinct log message to have its own counter of 10. How do I fix this with samber/slog-sampling?",
    "trap": "Without the skill, the model either rebuilds sampling from scratch or suggests separate logger instances per message. The correct fix is to set the Matcher to MatchByLevelAndMessage() (or MatchByMessage()) so each unique message gets its own deduplication bucket instead of all records sharing one bucket.",
    "assertions": [
      {"id": "4.1", "text": "Identifies that the default Matcher groups all records into one bucket (regardless of message)"},
      {"id": "4.2", "text": "Recommends setting the Matcher field on ThresholdSamplingOption to MatchByLevelAndMessage() or MatchByMessage()"},
      {"id": "4.3", "text": "Explains that each unique message will then have its own independent threshold counter"},
      {"id": "4.4", "text": "Does NOT suggest creating separate logger instances per message type as the solution"},
      {"id": "4.5", "text": "Does NOT suggest rewriting custom sampling logic outside of slog-sampling"}
    ]
  },
  {
    "id": 5,
    "name": "router-warn-level-gap",
    "description": "Tests whether the model identifies that WARN records are silently dropped in a Router with only ERROR and INFO predicates",
    "prompt": "I have this slog-multi Router setup. My ERROR logs reach Sentry, my INFO logs reach Loki, but my WARN logs are silently disappearing — they don't reach either handler. My global slog level is set to Debug so filtering isn't the issue. What's wrong?\n\n```go\nlogger := slog.New(\n    slogmulti.Router().\n        Add(sentryHandler, slogmulti.LevelIs(slog.LevelError)).\n        Add(lokiHandler, slogmulti.LevelIs(slog.LevelInfo)).\n        Handler(),\n)\n```",
    "trap": "Without the skill, the model suspects Loki configuration, slog level filters, or assumes LevelIs(Info) includes Warn. The skill teaches that Router predicates are exact — LevelIs(Info) matches ONLY Info, not Warn or above. WARN records match no predicate and are silently dropped. Fix: add a catch-all handler or use a predicate that covers Warn.",
    "assertions": [
      {"id": "5.1", "text": "Correctly identifies that LevelIs(slog.LevelInfo) matches ONLY Info level, not Warn"},
      {"id": "5.2", "text": "Explains that Router silently drops records that match no predicate"},
      {"id": "5.3", "text": "Does NOT suggest the global slog level or Loki configuration as the root cause"},
      {"id": "5.4", "text": "Proposes adding a catch-all handler (no predicate) or a LevelIs(slog.LevelWarn) rule to capture WARN records"},
      {"id": "5.5", "text": "Correctly explains that Router predicates are exact-level matches, not 'level and above'"}
    ]
  },
  {
    "id": 6,
    "name": "http-middleware-error-level-differentiation",
    "description": "Tests whether the model uses slog-gin Config to log 4xx and 5xx at different levels instead of uniform INFO",
    "prompt": "I've added sloggin.New(logger) to my Gin server for request logging. My log aggregation tool shows that 404s and 500s both appear as INFO level, making it hard to alert on server errors. How do I make 4xx client errors log at WARN and 5xx server errors log at ERROR, while keeping normal requests at INFO, using samber/slog-gin?",
    "trap": "Without the skill, the model wraps sloggin in a custom middleware or post-processes log records to change the level. The skill teaches that slog-gin's Config struct has ClientErrorLevel and ServerErrorLevel fields that handle this natively — no custom middleware needed.",
    "assertions": [
      {"id": "6.1", "text": "Replaces sloggin.New() with sloggin.NewWithConfig() to pass a Config struct"},
      {"id": "6.2", "text": "Sets ClientErrorLevel: slog.LevelWarn in the Config for 4xx responses"},
      {"id": "6.3", "text": "Sets ServerErrorLevel: slog.LevelError in the Config for 5xx responses"},
      {"id": "6.4", "text": "Sets DefaultLevel: slog.LevelInfo in the Config for 2xx/3xx responses"},
      {"id": "6.5", "text": "Does NOT implement a custom Gin middleware or post-processing logic to change log levels"}
    ]
  },
  {
    "id": 7,
    "name": "pipe-middleware-chain",
    "description": "Tests whether the model uses Pipe middleware instead of custom Handler wrapper",
    "prompt": "I need to inject a trace_id from OpenTelemetry context and scrub email addresses from all log records before they reach any handler. I'm using samber/slog-multi. Show me how to set this up as reusable middleware.",
    "trap": "Without the skill, the model creates a custom slog.Handler wrapper struct instead of using slogmulti.Pipe with inline middleware",
    "assertions": [
      {"id": "7.1", "text": "Uses slogmulti.Pipe() for middleware chaining"},
      {"id": "7.2", "text": "Creates middleware for trace_id injection (inline middleware or AttrFromContext)"},
      {"id": "7.3", "text": "Creates middleware or formatter for email/PII scrubbing"},
      {"id": "7.4", "text": "Pipe wraps the final sink handler(s)"},
      {"id": "7.5", "text": "Does NOT implement a custom slog.Handler struct with Enabled/Handle/WithAttrs/WithGroup methods"}
    ]
  },
  {
    "id": 8,
    "name": "failover-handler",
    "description": "Tests whether the model uses Failover instead of custom retry logic",
    "prompt": "My slog pipeline sends logs to Loki over the network, but Loki has occasional outages lasting 1-5 minutes. I want to automatically fall back to local file logging when Loki is unavailable, then resume Loki when it's back. Show the setup using samber/slog-multi.",
    "trap": "Without the skill, the model builds custom retry/fallback logic with goroutines and channels instead of using slog-multi's Failover handler",
    "assertions": [
      {"id": "8.1", "text": "Uses slogmulti.Failover() handler"},
      {"id": "8.2", "text": "Loki handler is the primary (first) handler in the Failover chain"},
      {"id": "8.3", "text": "File/local handler is the fallback (second) handler"},
      {"id": "8.4", "text": "Does NOT implement custom retry/fallback logic with goroutines or channels"},
      {"id": "8.5", "text": "Uses slog-loki library for the Loki handler (not a custom HTTP client)"}
    ]
  },
  {
    "id": 9,
    "name": "pool-vs-fanout-latency",
    "description": "Tests whether the model recommends Pool over Fanout and correctly describes Pool's latency model",
    "prompt": "I'm replacing slogmulti.Fanout with slogmulti.Pool to reduce log-call latency. I have 4 handlers with these p99 write times: stdout (1ms), Loki (20ms), Datadog (30ms), Sentry (15ms). My current Fanout p99 latency per log call is ~66ms. What will Pool's p99 latency be, and are there any risks I should know about with Pool that don't exist with Fanout?",
    "trap": "Without the skill, the model says Pool will have ~0ms latency (wrongly treating it as fire-and-forget) or cannot identify the risks. The skill teaches: Pool latency = max of all handlers (30ms, not 66ms); risk = Pool may silently swallow handler errors that Fanout would surface synchronously.",
    "assertions": [
      {"id": "9.1", "text": "Correctly states Pool p99 latency will be ~30ms (the slowest handler, Datadog) not the sum"},
      {"id": "9.2", "text": "Explains that Pool dispatches concurrently so latency = max(handler latencies), not sum"},
      {"id": "9.3", "text": "Identifies at least one risk of Pool vs Fanout (e.g. handler errors may not surface synchronously, or error handling differs)"},
      {"id": "9.4", "text": "Shows correct Pool syntax: slogmulti.Pool()(handlers...) with the double call"},
      {"id": "9.5", "text": "Does NOT claim Pool is fully asynchronous/fire-and-forget with zero latency impact"}
    ]
  },
  {
    "id": 10,
    "name": "formatter-pii-scrubbing",
    "description": "Tests whether the model uses slog-formatter as Pipe middleware for cross-cutting PII scrubbing",
    "prompt": "I need to ensure no email addresses or IP addresses appear in any log output from my Go service. We use slog with slog-multi routing to 3 different handlers (stdout, Loki, Sentry). Show me how to add PII protection that applies to ALL handlers in one place.",
    "trap": "Without the skill, the model adds per-handler filtering or regex on output instead of using slog-formatter as a Pipe middleware wrapping all downstream handlers",
    "assertions": [
      {"id": "10.1", "text": "Uses slog-formatter library (slogformatter package)"},
      {"id": "10.2", "text": "Uses PIIFormatter and/or IPAddressFormatter from slog-formatter"},
      {"id": "10.3", "text": "Applies formatter as a Pipe middleware wrapping all downstream handlers (not per-handler)"},
      {"id": "10.4", "text": "Formatter is applied once in the pipeline, before the Router/Fanout"},
      {"id": "10.5", "text": "Does NOT implement custom regex-based filtering or per-handler PII logic"}
    ]
  },
  {
    "id": 11,
    "name": "backend-option-pattern",
    "description": "Tests whether the model uses correct Option{} constructor pattern for backend handlers",
    "prompt": "Set up slog to send error-level logs to Sentry and all logs to Grafana Loki using samber/slog-sentry and samber/slog-loki. Show the complete setup with correct imports and handler creation.",
    "trap": "Without the skill, the model uses incorrect constructor patterns (e.g., New() function, slogsentry.New(), or positional args) instead of the Option{}.NewXxxHandler() pattern",
    "assertions": [
      {"id": "11.1", "text": "Uses slogsentry.Option{}.NewSentryHandler() constructor pattern"},
      {"id": "11.2", "text": "Uses slogloki.Option{}.NewLokiHandler() constructor pattern"},
      {"id": "11.3", "text": "Uses slogmulti.Router() for level-based routing (errors to Sentry, all to Loki)"},
      {"id": "11.4", "text": "Import paths use versioned modules (github.com/samber/slog-sentry/v2, github.com/samber/slog-loki/v3)"},
      {"id": "11.5", "text": "Calls lokiClient.Stop() or defer lokiClient.Stop() for graceful shutdown (flush buffered logs)"}
    ]
  },
  {
    "id": 12,
    "name": "attrfromcontext-without-middleware",
    "description": "Tests whether the model identifies that AttrFromContext needs HTTP middleware to populate context",
    "prompt": "I'm using slog-multi's Pipe with AttrFromContext to add request_id to all log records in my Go HTTP server. But the request_id is always empty in the logs. I'm NOT using any HTTP logging middleware (no slog-gin or slog-chi). Here's my handler setup:\n\n```go\nhandler := slogsentry.Option{\n    Level: slog.LevelError,\n    AttrFromContext: []func(ctx context.Context) []slog.Attr{\n        func(ctx context.Context) []slog.Attr {\n            if reqID := ctx.Value(\"request_id\"); reqID != nil {\n                return []slog.Attr{slog.String(\"request_id\", reqID.(string))}\n            }\n            return nil\n        },\n    },\n}.NewSentryHandler()\n```\n\nWhat's wrong and how do I fix it?",
    "trap": "Without the skill, the model debugs context.Value key types or suggests adding context.WithValue manually in every handler, instead of identifying the missing HTTP middleware that injects attributes",
    "assertions": [
      {"id": "12.1", "text": "Identifies that no HTTP middleware is populating the request_id into context"},
      {"id": "12.2", "text": "Recommends adding slog-gin/echo/fiber/chi middleware (or manual context injection middleware)"},
      {"id": "12.3", "text": "Explains that the HTTP middleware is what injects request attributes into context"},
      {"id": "12.4", "text": "Does NOT suggest only changing the context key type as the primary fix"},
      {"id": "12.5", "text": "Shows the connection between HTTP middleware and AttrFromContext"},
      {"id": "12.6", "text": "Mentions WithRequestID config option or equivalent for the middleware"},
      {"id": "12.7", "text": "Does NOT blame slog-multi or slog-sentry configuration as the root cause"}
    ]
  }
]

Requirements and compatibility

Written for: Claude Code, OpenAI Codex

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Declares allowed tools, Claude Code frontmatter

The author says: Designed for Claude Code, Codex or similar harness, and for projects using Golang.

Security

What our scanner noticed· Medium risk

  • Possible data-exfiltration endpoints

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
samber
Publisher
Samuel Berthe (Community)
Distributed by
Samuel Berthe
Source
samber/cc-skills-golang · skills/golang-samber-slog · commit bb1d43d
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by samber or Samuel Berthe.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download golang-samber-slog.zip