install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/pino" ~/.claude/skills/comeonoliver-skillshub-pino && rm -rf "$T"
manifest:
skills/TerminalSkills/skills/pino/SKILL.mdsource content
Pino
Overview
Pino is the fastest Node.js logger — 5x faster than Winston. It outputs structured JSON logs by default, making them parseable by log aggregators (Datadog, Loki, ELK). Async logging ensures logging never blocks the event loop.
Instructions
Step 1: Basic Setup
// lib/logger.ts — Pino configuration import pino from 'pino' export const logger = pino({ level: process.env.LOG_LEVEL || 'info', transport: process.env.NODE_ENV === 'development' ? { target: 'pino-pretty', options: { colorize: true } } // pretty-print in dev : undefined, // JSON in production formatters: { level: (label) => ({ level: label }), // "level": "info" not "level": 30 }, base: { service: 'api', version: process.env.npm_package_version, }, }) // Usage logger.info('Server started') logger.info({ port: 3000, env: 'production' }, 'Server listening') logger.error({ err, userId: '123' }, 'Payment processing failed') logger.warn({ latencyMs: 2500, endpoint: '/api/reports' }, 'Slow request detected')
Step 2: Express Integration
// server.ts — Request logging middleware import express from 'express' import pinoHttp from 'pino-http' import { logger } from './lib/logger' const app = express() app.use(pinoHttp({ logger, autoLogging: true, customLogLevel: (req, res, err) => { if (res.statusCode >= 500 || err) return 'error' if (res.statusCode >= 400) return 'warn' return 'info' }, customSuccessMessage: (req, res) => `${req.method} ${req.url} ${res.statusCode}`, serializers: { req: (req) => ({ method: req.method, url: req.url, query: req.query, userAgent: req.headers['user-agent'], }), res: (res) => ({ statusCode: res.statusCode, }), }, }))
Step 3: Child Loggers
// Add context that persists across a request lifecycle function createRequestLogger(req) { return logger.child({ requestId: req.headers['x-request-id'] || crypto.randomUUID(), userId: req.user?.id, ip: req.ip, }) } // Every log from this logger includes requestId, userId, ip const reqLogger = createRequestLogger(req) reqLogger.info('Processing order') reqLogger.info({ orderId: 'ord_123', amount: 99.99 }, 'Order created') // Output: {"level":"info","requestId":"abc-123","userId":"user-456","orderId":"ord_123","amount":99.99,"msg":"Order created"}
Guidelines
- Always use structured JSON logging in production — not string interpolation.
- Context first, message second:
notlogger.info({ orderId }, 'Order created')
.logger.info('Order created for ' + orderId) - Use child loggers to add request context (requestId, userId) that propagates to all logs.
- Pino's async mode (
) prevents logging from blocking the event loop.pino({ transport }) - Use
only in development — JSON logs are for machines, not humans.pino-pretty