Overview
Production-grade logging using Fastify's built-in Pino. Includes request logging, redaction, and audit logging.
Features
- Multiple log levels
- Sensitive field redaction
- Pretty print in development
- Audit event logging
- Custom serializers
Installation
npx hanma add fastify-logger --framework fastify
Dependencies
fastify, pino-pretty
Code
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { pino } from "pino";
/**
* Logger configuration based on environment
*/
export function createLoggerConfig() {
const isDev = process.env.NODE_ENV === "development";
const level = process.env.LOG_LEVEL ?? (isDev ? "debug" : "info");
return {
level,
// Pretty print in development
transport: isDev
? {
target: "pino-pretty",
options: {
colorize: true,
translateTime: "HH:MM:ss Z",
ignore: "pid,hostname",
},
}
: undefined,
// Redact sensitive fields
redact: {
paths: [
"req.headers.authorization",
"req.headers.cookie",
"req.headers['x-api-key']",
"body.password",
"body.token",
"body.secret",
],
censor: "[REDACTED]",
},
// Custom serializers
serializers: {
req(request: FastifyRequest) {
return {
method: request.method,
url: request.url,
path: request.routeOptions?.url,
parameters: request.params,
headers: {
host: request.headers.host,
"user-agent": request.headers["user-agent"],
"content-type": request.headers["content-type"],
},
};
},
res(reply: FastifyReply) {
return {
statusCode: reply.statusCode,
};
},
},
};
}
/**
* Create a child logger for a specific service/module
*/
export function createServiceLogger(app: FastifyInstance, service: string) {
return app.log.child({ service });
}
/**
* Request logging hook - logs request and response
*/
export function registerRequestLogger(app: FastifyInstance): void {
app.addHook("onRequest", async (request) => {
request.log.info({ requestId: request.id }, "Request started");
});
app.addHook("onResponse", async (request, reply) => {
const responseTime = reply.elapsedTime;
request.log.info(
{
requestId: request.id,
statusCode: reply.statusCode,
responseTime: `${responseTime.toFixed(2)}ms`,
},
"Request completed"
);
});
app.addHook("onError", async (request, reply, error) => {
request.log.error(
{
requestId: request.id,
error: {
message: error.message,
stack: error.stack,
code: (error as any).code,
},
},
"Request failed"
);
});
}
/**
* Log audit events (for sensitive operations)
*/
export function logAudit(
app: FastifyInstance,
action: string,
details: {
userId?: string;
resource?: string;
resourceId?: string;
metadata?: Record<string, unknown>;
}
) {
app.log.info(
{
audit: true,
action,
...details,
timestamp: new Date().toISOString(),
},
`Audit: ${action}`
);
}
/**
* Standalone logger for use outside of request context
*/
export const logger = pino(createLoggerConfig());
// Convenience methods
export const log = {
debug: (msg: string, data?: object) => logger.debug(data, msg),
info: (msg: string, data?: object) => logger.info(data, msg),
warn: (msg: string, data?: object) => logger.warn(data, msg),
error: (msg: string, data?: object) => logger.error(data, msg),
fatal: (msg: string, data?: object) => logger.fatal(data, msg),
};
// Usage in Fastify:
// const app = Fastify({ logger: createLoggerConfig() });
// registerRequestLogger(app);
//
// Usage standalone:
// log.info("Application started", { port: 3000 });
Usage
import { createLoggerConfig, registerRequestLogger, log } from './middleware/logger';
const app = Fastify({ logger: createLoggerConfig() });
registerRequestLogger(app);
log.info('Application started', { port: 3000 });
Dependencies
fastifypino-pretty
Frequently Asked Questions
How do I install Pino Logger?
Run the following command:
npx hanma add fastify-logger --framework fastifyWhat dependencies are required?
This snippet requires: fastify, pino-pretty. Make sure to install them before using the snippet.
How do I use this snippet?
Copy the code and paste it into your project. The snippet will be saved to
src/middleware/logger.ts.Can I customize this snippet?
Yes! All snippets are copy-paste code that you own. Feel free to modify them to fit your needs.
Does this work with other frameworks?
This snippet is designed for the specific framework. Check the other framework pages for equivalent implementations.