logging-best-practices

v2026.09.24

Emit structured logs with Pino (levels, context-first signature, workflow-safe step wrapper). Use when adding logging to routes, libraries, or workflows.

GitHub
Install command
npx skhub add andrelandgraf/logging-best-practices
Markdown
SKILL.md

Logging Best Practices

Emit structured logs with Pino throughout the app.

Prerequisites

Complete these setup recipes first:

  • Pino Logging Setup

Logging

Import logger from @/lib/logging/logger. Pass a context object first, message second. For errors, put err in the context object.

import { logger } from "@/lib/logging/logger";

logger.info({ port: 3000 }, "Server started");
logger.warn({ endpoint: "/api/chat" }, "Rate limit reached");
logger.debug({ key: "user:123" }, "Cache miss");
logger.error({ err, userId: "123", endpoint: "/api/chat" }, "Request failed");

Levels

LevelWhen to Use
traceDetailed debugging (rarely used)
debugDevelopment troubleshooting
infoNormal operations, business events
warnRecoverable issues, deprecation warnings
errorFailures that need attention
fatalCritical failures, app cannot continue

Set the active threshold via LOG_LEVEL (defaults to info). Use warn in production.

LOG_LEVEL="debug"

In API Routes

Log on the way out with timing context.

import { logger } from "@/lib/logging/logger";

export async function POST(request: Request) {
  const start = Date.now();
  try {
    const result = await processRequest(request);
    logger.info(
      { duration: Date.now() - start, status: 200 },
      "Request completed",
    );
    return Response.json(result);
  } catch (err) {
    logger.error({ err, duration: Date.now() - start }, "Request failed");
    return Response.json({ error: "Internal error" }, { status: 500 });
  }
}

In Workflows

The workflow runtime can't import Node modules, so the logger can't be called directly. Wrap it in a "use step" function.

// src/workflows/chat/steps/logger.ts
import { logger } from "@/lib/logging/logger";

export async function log(
  level: "info" | "warn" | "error" | "debug",
  message: string,
  data?: Record<string, unknown>,
): Promise<void> {
  "use step";

  if (data) {
    logger[level](data, message);
  } else {
    logger[level](message);
  }
}
import { log } from "./steps/logger";

export async function chatWorkflow({ chatId }) {
  "use workflow";

  await log("info", "Workflow started", { chatId });
}

References

Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

Not specified

Source path

skills/logging-best-practices

Default branch

main

Latest commit

4449331

Tree SHA

1f78782