Lombok(ish) wrapper which allows for simple pino logger creation as class member (or module variable) Also Implements NestJS interface.
- Installation
- Usage
- HTTP Middleware
- Level Changer
- Marking Sensitive Logs
- Default Configurations
- Acknowledgments
- License
npm i -s pino-lombokish
npm i -D @types/pino @types/pino-http pino-pretty
Note pino-pretty is disabled when NODE_ENV==='production'. If Users want to use pretty print in production then
- install pino-pretty as production dependency (
npm i -s pino-pretty
)- override logger config during init or set NODE_ENV !== 'production'
Important!
experimentalDecorators
,emitDecoratorMetadata
,strictPropertyInitialization
compilation options must be enabled in yourtsconfig.json
file.
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strictPropertyInitialization": false
}
}
// main.ts
import { LoggerFactory } from 'pino-lombokish';
LoggerFactory.forRoot({
level: 'info', // trace | debug | info | warn | error | fatal
name: 'YourAppName' // optional
});
import { foo }
// file.ts
import { LoggerFactory } from 'pino-lombokish';
const logger = LoggerFactory.createLogger();
logger.info('Will log "className": "file.ts" in Your Log');
// file.ts
import { LoggerFactory } from 'pino-lombokish';
const logger = LoggerFactory.createLogger('foo');
logger.info('Will log "className": "foo" in Your Log');
// foo.ts
import { Logger, AppLogger } from 'pino-lombokish';
export class Foo {
@Logger()
private logger: AppLogger;
@Logger()
private anotherLogger: any;
constructor() {
this.logger.info('Will log "className": "Foo" in Your log');
this.anotherLogger.info('Will log "className": "Foo" in Your log');
}
}
Creates Pino Http NodeJS/express middleware
import { LoggerFactory } from 'pino-lombokish';
import { LoggerOptions } from 'pino';
const config: LoggerOptions = {
level: 'debug',
name: 'YourApp'
};
LoggerFactory.forRoot(config);
// NOTE: Import other modules using Logger after calling LoggerFactory.forRoot()
import { Foo } from './foo';
import * as express from 'express';
const app = express();
app.use(LoggerFactory.createHttpLoggerMiddleware(config));
app.listen(3000);
Note HTTP Middleware class name is hard coded to 'http'
(To Get rid of Kubernetes Health check logs)
- HTTP Headers (via pino redact option)
- Authorization
- x-original-uri
- x-original-url
- sec-websocket-protocol
- HTTP URL Parameters (via pino http serializers option)
- access_token
import { LoggerOptions } from 'pino';
import { Options } from 'pino-http';
const pinoConfig: LoggerOptions = {
level: 'warn',
}
const pinoHttpOptions: Options: {
customLogLevel: customLogLevelFn,
serializers: { req: customReqSerializer }
}
app.use(LoggerFactory.createHttpLoggerMiddleware(pinoConfig, pinoHttpOptions));
pino-lombokish package implements Level Changer functionality which allows users to change logger level at runtime.
import { LoggerFactory, AppLogger, Logger } from 'pino-lombokish';
LoggerFactory.forRoot({
level: 'debug',
name: 'example',
changeConfig: {
path: './levels.json'
}
});
{
"level": "info", // mandatory
"levels": {
// optional if user wants to set level for specific class name
"example.ts": "warn",
"LevelChanger": "info",
"http": "info"
}
}
- If provided file does not exist Level Changer will check for its existence every 10s.
- Once the file is created Level Changer will subscribe to its changes
- When the file is removed Level Changer will start checking for its existence every 10s (again)
pino-lombokish package implements sensitive logging bindings.
This feature is not meant to redact logs.
- It is meant for log forwarders in PaaS systems (i.e splunk-forwader or fluentd).
- Log forwarders send logs to aggregators (i.e kibana)
- Log forwarders can be configured to look for specific properties in logs
- If property is present then send to specific aggregators only (i.e. aggregators which store sensitive logs only)
- If property is not present then send to all aggregators
LoggerFactory.forRoot({
sensitive: true
})
const logger = LoggerFactory.createLogger('withDefaultSensitiveBindings');
logger.sensitive.info('Will add { isSensitive: true } to log')
LoggerFactory.forRoot({
sensitive: {
sensitiveName: 'sensitiveLog',
sensitiveValue: 'yes'
}
})
const logger = LoggerFactory.createLogger('withUserSensitiveBindings');
logger.sensitive.info('Will add { sensitiveLog: "yes" } to log')
export const DEFAULT_LOGGER_CONFIG: pino.LoggerOptions = {
level: 'info',
prettyPrint: process.env.NODE_ENV !== 'production' ?
{ translateTime: true }
: false,
customLevels: {
log: pino.levels.values['info'],
verbose: pino.levels.values['info']
}
};
export const DEFAULT_MIDDLEWARE_CONFIG: pino.LoggerOptions = {
...DEFAULT_LOGGER_CONFIG,
redact: {
paths: [
'req.headers.authorization',
'req.headers["x-original-uri"]',
'req.headers["x-original-url"]',
'req.headers["sec-websocket-protocol"]'
]
}
};
const options: pinoHttp.Options = {
customLogLevel: logHealthAsTrace,
serializers: { req: redactAccessTokenFromPath }
};
export const DEFAULT_SENSITIVE_CONFIG = {
sensitiveName: 'isSensitive',
sensitiveValue: true
};
The MIT License Copyright (C) 2019 Motorola Solutions, Inc All rights reserved