Skip to main content

outfitter-logging

Patterns for @outfitter/logging including structured logging, sinks, redaction, and child loggers. Use when configuring logging, adding redaction, creating sinks, or when "logger", "structured logging", "redaction", "log level", or "@outfitter/logging" are mentioned.

Quellinformationen

Repository
outfitter-dev/outfitter
Letzte Quellaktivität
24. Februar 2026 um 23:09
Erkannte Sprache von SKILL.md
Englisch
Sterne
6
Forks
1

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
outfitter-logging
version
0.1.0
description
Patterns for @outfitter/logging including structured logging, sinks, redaction, and child loggers. Use when configuring logging, adding redaction, creating sinks, or when "logger", "structured logging", "redaction", "log level", or "@outfitter/logging" are mentioned.
allowed-tools
Read Write Edit Glob Grep
# Logging Patterns Deep dive into @outfitter/logging patterns. ## Creating a Logger ```typescript import { createLogger, createConsoleSink } from "@outfitter/logging"; const logger = createLogger({ name: "my-app", level: "info", sinks: [createConsoleSink()], redaction: { enabled: true }, }); ``` ## Log Levels | Level | Method | Use For | | ------- | ---------------- | ---------------------------- | | `trace` | `logger.trace()` | Very detailed debugging | | `debug` | `logger.debug()` | Development debugging | | `info` | `logger.info()` | Normal operations | | `warn` | `logger.warn()` | Unexpected but handled | | `error` | `logger.error()` | Failures requiring attention | | `fatal` | `logger.fatal()` | Unrecoverable failures | Level hierarchy: `trace` < `debug` < `info` < `warn` < `error` < `fatal` Setting level to `info` hides `trace` and `debug`. ## Structured Logging Always use metadata objects: ```typescript // GOOD: Structured metadata logger.info("User created", { userId: user.id, email: user.email, duration: performance.now() - start, }); // BAD: String concatenation logger.info("User " + user.name + " created in " + duration + "ms"); ``` ## Child Loggers Add context that persists across calls: ```typescript import { createChildLogger } from "@outfitter/logging"; const requestLogger = createChildLogger(logger, { requestId: ctx.requestId, handler: "createUser", }); // All logs include requestId and handler requestLogger.info("Processing"); // Has requestId, handler requestLogger.debug("Validated input"); // Has requestId, handler requestLogger.info("User created", { userId }); // Has requestId, handler, userId ``` ## Redaction ### Enable Redaction ```typescript const logger = createLogger({ name: "my-app", level: "info", sinks: [createConsoleSink()], redaction: { enabled: true }, }); logger.info("Config", { apiKey: "secret-123", // Logged as "[REDACTED]" password: "hunter2", // Logged as "[REDACTED]" email: "user@example.com", // Not redacted }); ``` ### Default Redaction Patterns Automatically redacted: - `password`, `pwd` - `apiKey`, `api_key` - `secret`, `secretKey` - `token`, `accessToken` - `auth`, `authorization` - `key` (when containing sensitive data) - `credential`, `credentials` ### Custom Patterns ```typescript const logger = createLogger({ name: "my-app", redaction: { enabled: true, patterns: ["password", "apiKey", "myCustomSecret", "internalToken"], }, }); ``` ### Deep Redaction Nested values are also redacted: ```typescript logger.info("Request", { headers: { authorization: "Bearer token", // Redacted }, body: { user: { password: "secret", // Redacted }, }, }); ``` ## Sinks ### Console Sink ```typescript import { createConsoleSink } from "@outfitter/logging"; const consoleSink = createConsoleSink({ colorize: true, // ANSI colors prettyPrint: true, // Formatted output timestampFormat: "iso", // ISO 8601 timestamps }); ``` ### File Sink ```typescript import { createFileSink } from "@outfitter/logging"; const fileSink = createFileSink({ path: "/var/log/myapp/app.log", maxSize: 10 * 1024 * 1024, // 10MB maxFiles: 5, // Keep 5 rotated files }); ``` ### Multiple Sinks ```typescript const logger = createLogger({ name: "my-app", level: "debug", sinks: [ createConsoleSink({ level: "info" }), // Console: info+ createFileSink({ // File: debug+ path: "/var/log/myapp/debug.log", level: "debug", }), ], }); ``` ### Custom Sink ```typescript const customSink = { log: (record) => { // Send to external service externalService.send({ level: record.level, message: record.message, metadata: record.metadata, timestamp: record.timestamp, }); }, }; const logger = createLogger({ name: "my-app", sinks: [customSink], }); ``` ## Environment Configuration ```typescript const logger = createLogger({ name: "my-app", level: process.env.LOG_LEVEL || "info", sinks: [ createConsoleSink({ colorize: process.stdout.isTTY, prettyPrint: process.env.NODE_ENV !== "production", }), ], }); ``` ## Handler Context Integration ```typescript import { createContext } from "@outfitter/contracts"; import { createLogger, createChildLogger } from "@outfitter/logging"; const baseLogger = createLogger({ name: "my-app", level: "info" }); export function createHandlerContext() { const ctx = createContext({ logger: baseLogger }); // Child logger with requestId return { ...ctx, logger: createChildLogger(baseLogger, { requestId: ctx.requestId }), }; } // In handler const myHandler: Handler<Input, Output, Error> = async (input, ctx) => { ctx.logger.info("Processing", { input }); // Includes requestId // ... }; ``` ## Performance ### Conditional Logging ```typescript // Level check before expensive operations if (logger.isEnabled("debug")) { const expensiveData = computeDebugInfo(); logger.debug("Debug info", { data: expensiveData }); } ``` ### Lazy Evaluation ```typescript logger.debug("State", () => ({ // Only computed if debug level is enabled memory: process.memoryUsage(), connections: getActiveConnections(), })); ``` ## Best Practices 1. **Structured metadata** — Always use objects, not string concatenation 2. **Child loggers** — Add request context that persists 3. **Enable redaction** — Prevent secrets from leaking 4. **Level per environment** — Debug in dev, info in prod 5. **Request IDs** — Include for tracing across handlers 6. **Lazy evaluation** — Avoid expensive computations at disabled levels ## Related Skills - `stack:patterns` — Context creation - `stack:outfitter-daemon` — Daemon logging - `stack:debug` — Troubleshooting logging
Auf GitHub ansehen