Die Oberfläche ist lokalisiert; Skill-Beschreibungen und -Dokumente werden per KI automatisch in Ihre Sprache übersetzt. Code, Befehle, Pfade und Fachbegriffe bleiben im Original, maßgeblich ist das Dokument des Autors.
Skills entdecken
Daten und Forschung · SKILL.md

pino

pino

Pino is a fast Node.js logger that writes structured JSON, one object per line. Use when a user asks to add structured logging, replace console.log, configure log levels, redact secrets from logs, log HTTP requests in Express or Fastify, pretty-print logs in development, or ship logs to Datadog, Loki or Elasticsearch.

Independent GitHub snapshot · Automated classification · Original documentation governs

Tterminalskills / skillsApache-2.0

Skill-Dokumentation

GitHub

name: pino description: >- Pino is a fast Node.js logger that writes structured JSON, one object per line. Use when a user asks to add structured logging, replace console.log, configure log levels, redact secrets from logs, log HTTP requests in Express or Fastify, pretty-print logs in development, or ship logs to Datadog, Loki or Elasticsearch. license: Apache-2.0 compatibility: 'Node.js 20+ (pino 10 is tested on 20 and newer), Express, Fastify, Next.js' metadata: author: terminal-skills version: 1.1.0 category: devops repository: https://github.com/pinojs/pino tags: - pino - logging - nodejs - structured - observability

Pino

Overview

Pino (current major version 10.x) is a low-overhead Node.js logger. Every call writes one line of JSON with a numeric level, a millisecond time, pid, hostname and your msg, which log aggregators (Datadog, Loki, Elasticsearch, CloudWatch) can parse without extra rules. Pino keeps work in the hot path small: formatting, pretty-printing and shipping are meant to happen outside the request path, in a worker-thread transport or in a separate process that reads stdout.

Companion packages: pino-http (request logging middleware, Express/Koa/Connect style), pino-pretty (human-readable output for development), pino-std-serializers (bundled; serializes err, req, res). Fastify has Pino built in: Fastify({ logger: true }).

Instructions

Step 1: Install

npm install pino pino-http
npm install -D pino-pretty

Step 2: Create one shared logger

// lib/logger.ts
import pino from "pino";

const isDev = process.env.NODE_ENV === "development";

export const logger = pino({
  level: process.env.LOG_LEVEL ?? "info",       // fatal, error, warn, info, debug, trace, silent
  base: { service: "billing-api", version: process.env.npm_package_version },
  redact: ["req.headers.authorization", "req.headers.cookie", "*.password", "*.apiKey"],
  // JSON on stdout in production; pretty text only in development
  transport: isDev ? { target: "pino-pretty", options: { colorize: true } } : undefined,
});

Usage: put the data object first, the message second.

logger.info({ port: 3000 }, "Server listening");
logger.warn({ latencyMs: 2500, endpoint: "/api/reports" }, "Slow request");
logger.error({ err, invoiceId: "inv_2041" }, "Payment capture failed");   // key must be "err"

An Error under the key err is serialized with type, message and stack. Logging it under another key (error, e) prints {} unless you add a serializer.

Step 3: Request logging with pino-http

import express from "express";
import pinoHttp from "pino-http";
import { logger } from "./lib/logger";

const app = express();
app.use(
  pinoHttp({
    logger,
    customLogLevel: (req, res, err) =>
      err || res.statusCode >= 500 ? "error" : res.statusCode >= 400 ? "warn" : "info",
    customSuccessMessage: (req, res) => `${req.method} ${req.url} ${res.statusCode}`,
  }),
);

app.get("/orders/:id", (req, res) => {
  req.log.info({ orderId: req.params.id }, "Loading order");   // child logger bound to this request
  res.json({ id: req.params.id });
});

Every request gets an id and a completion line with responseTime. req.log already carries the request id, so use it inside handlers instead of the global logger.

Step 4: Child loggers for context

const jobLog = logger.child({ jobId: "job_7781", queue: "invoices" });
jobLog.info("Started");                               // jobId and queue appear on every line
jobLog.info({ rows: 420 }, "Imported");
// {"level":30,"time":1790983327750,"service":"billing-api","jobId":"job_7781","queue":"invoices","rows":420,"msg":"Imported"}

Step 5: Levels as text, destinations, transports

  • Numeric levels (30, 50) are the default. To print "level":"info", use formatters: { level: (label) => ({ level: label }) }. This option cannot be combined with transport.targets (multiple targets): Pino throws option.transport.targets do not allow custom level formatters. Use a single target or map levels in your aggregator.
  • Send logs to several places with pino.transport({ targets: [...] }):
const transport = pino.transport({
  targets: [
    { target: "pino/file", level: "error", options: { destination: "./logs/errors.log", mkdir: true } },
    { target: "pino-pretty", level: "info", options: { colorize: false } },
  ],
});
const logger = pino(transport);
  • Transports run in a worker thread. For production, the simplest and most robust setup is plain JSON on stdout (pino.destination for a file), collected by the platform (Docker, Kubernetes, systemd) or piped to a separate process.
  • Check cost before building expensive log data: if (logger.isLevelEnabled("debug")) { ... }.

Examples

Example 1: Replace console.log in an Express API

User request: "Replace console.log with proper structured logging and make it quiet in tests."

Create lib/logger.ts as in Step 2 with level: process.env.LOG_LEVEL ?? "info", mount pinoHttp({ logger }), replace console.log("Started", port) with logger.info({ port }, "Started"), and run tests with LOG_LEVEL=silent npm test.

Result in production: {"level":30,"time":1790983316458,"service":"billing-api","port":3000,"msg":"Started"}; during tests nothing is printed.

Example 2: Keep secrets out of logs

User request: "Our request logs contain the Authorization header. Stop that."

const logger = pino({
  redact: { paths: ["req.headers.authorization", "req.headers.cookie", "*.password"], censor: "[Redacted]" },
});

With pino-http, the logged request now shows "authorization":"[Redacted]". Use remove: true inside the redact object to drop the keys entirely.

Guidelines

  • Log JSON in production, pretty text only in development; never ship pino-pretty output to an aggregator.
  • Data first, message second; do not concatenate values into the message string.
  • Use the key err for errors, and redact tokens, cookies and passwords with redact.
  • Create the logger once and import it; create child loggers per request or job.
  • Do not set formatters.level together with multi-target transports, and do not format timestamps in-process (it costs throughput); let the aggregator do it.
  • Buffered destinations (pino.destination({ sync: false })) can lose the last lines on a hard crash; keep the default synchronous stdout unless you have measured a need.
  • Log at the right level: info for business events, debug for development detail, error when someone should look.
Gespeicherte Skills