@pulzar/core
Version:
Next-generation Node.js framework for ultra-fast web applications with zero-reflection DI, GraphQL, WebSockets, events, and edge runtime support
172 lines • 5.22 kB
JavaScript
import pino from "pino";
import { AsyncLocalStorage } from "async_hooks";
const requestContext = new AsyncLocalStorage();
// Create transport configuration based on environment
function createTransport() {
const isDev = process.env.NODE_ENV === "development";
const isTest = process.env.NODE_ENV === "test";
if (isTest) {
return {
target: "pino/file",
options: { destination: "/dev/null" },
};
}
if (isDev) {
return {
target: "pino-pretty",
options: {
colorize: true,
translateTime: "HH:MM:ss Z",
ignore: "pid,hostname",
messageFormat: "{msg}",
hideObject: false,
singleLine: false,
crlf: false,
},
};
}
// Production: JSON output with optional Loki transport
const transports = [
{
target: "pino/file",
options: { destination: 1 }, // stdout
},
];
// Add Loki transport if configured
if (process.env.LOKI_URL) {
transports.push({
target: "pino-loki",
options: {
batching: true,
interval: 5000,
host: process.env.LOKI_URL,
basicAuth: process.env.LOKI_AUTH
? {
username: process.env.LOKI_USERNAME || "",
password: process.env.LOKI_PASSWORD || "",
}
: undefined,
labels: {
service: process.env.SERVICE_NAME || "pulzar-app",
environment: process.env.NODE_ENV || "production",
},
},
});
}
return transports.length > 1 ? transports : transports[0];
}
// Default logger configuration
const defaultOptions = {
level: process.env.LOG_LEVEL || "info",
name: process.env.SERVICE_NAME || "pulzar-app",
transport: createTransport(),
timestamp: pino.stdTimeFunctions.isoTime,
base: {
env: process.env.NODE_ENV || "development",
version: process.env.SERVICE_VERSION || "1.0.0",
},
formatters: {
level: (label) => ({ level: label }),
log: (object) => {
const context = requestContext.getStore();
if (context) {
return { ...object, ...context };
}
return object;
},
},
serializers: {
err: pino.stdSerializers.err,
error: pino.stdSerializers.err,
req: pino.stdSerializers.req,
res: pino.stdSerializers.res,
},
redact: {
paths: [
"password",
"token",
"authorization",
"cookie",
"*.password",
"*.token",
"*.authorization",
"*.cookie",
],
remove: true,
},
};
// Create the main logger instance
export const logger = pino(defaultOptions);
// Context management functions
export function setRequestContext(context) {
requestContext.enterWith(context);
}
export function getRequestContext() {
return requestContext.getStore();
}
export function withRequestContext(context, fn) {
return requestContext.run(context, fn);
}
// Child logger factory
export function createChildLogger(bindings, options) {
const mergedOptions = { ...defaultOptions, ...options };
return pino(mergedOptions).child(bindings);
}
// Request logger for Fastify
export function createRequestLogger(requestId, userId) {
return logger.child({
requestId,
userId,
});
}
// Performance logger
export function logPerformance(operation, startTime, metadata) {
const duration = performance.now() - startTime;
logger.info({
operation,
duration: `${duration.toFixed(2)}ms`,
...metadata,
}, `Performance: ${operation} completed in ${duration.toFixed(2)}ms`);
}
// Error logger with stack trace
export function logError(error, context, message) {
logger.error({
err: error,
...context,
}, message || error.message);
}
// Structured logging helpers
export const log = {
trace: (obj, msg) => logger.trace(obj, msg),
debug: (obj, msg) => logger.debug(obj, msg),
info: (obj, msg) => logger.info(obj, msg),
warn: (obj, msg) => logger.warn(obj, msg),
error: (obj, msg) => logger.error(obj, msg),
fatal: (obj, msg) => logger.fatal(obj, msg),
// Simple message logging
message: {
trace: (msg) => logger.trace(msg),
debug: (msg) => logger.debug(msg),
info: (msg) => logger.info(msg),
warn: (msg) => logger.warn(msg),
error: (msg) => logger.error(msg),
fatal: (msg) => logger.fatal(msg),
},
};
// Graceful shutdown
export async function flushLogger() {
return new Promise((resolve, reject) => {
logger.flush((err) => {
if (err) {
reject(err);
}
else {
resolve();
}
});
});
}
// Export the pino instance directly for advanced usage
export { pino };
export default logger;
//# sourceMappingURL=logger.js.map