Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nestjs-pino

Package Overview
Dependencies
Maintainers
1
Versions
1332
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nestjs-pino - npm Package Compare versions

Comparing version 0.2.1 to 0.3.0

__tests__/levels.spec.ts

42

dist/index.d.ts

@@ -1,2 +0,4 @@

import { LoggerService, DynamicModule, NestModule, MiddlewareConsumer } from "@nestjs/common";
import { LoggerService, DynamicModule } from "@nestjs/common";
import { ModuleMetadata } from "@nestjs/common/interfaces";
import pinoHttp from "pino-http";
import pino, { LoggerOptions, DestinationStream } from "pino";

@@ -6,26 +8,22 @@ declare type PassedLogger = {

};
declare type Params = [] | [PassedLogger] | [LoggerOptions | DestinationStream] | [LoggerOptions, DestinationStream];
export declare type Params = null | pinoHttp.Options | DestinationStream | [pinoHttp.Options, DestinationStream];
export interface LoggerModuleAsyncOptions extends Pick<ModuleMetadata, "imports" | "providers"> {
useFactory: (...args: any[]) => Params;
inject?: any[];
}
export declare class Logger implements LoggerService {
verbose(msg: string, ...args: any[]): void;
verbose(obj: object, msg?: string, ...args: any[]): void;
debug(msg: string, ...args: any[]): void;
debug(obj: object, msg?: string, ...args: any[]): void;
log(msg: string, ...args: any[]): void;
log(obj: object, msg?: string, ...args: any[]): void;
warn(msg: string, ...args: any[]): void;
warn(obj: object, msg?: string, ...args: any[]): void;
error(msg: string, ...args: any[]): void;
error(obj: object, msg?: string, ...args: any[]): void;
private readonly outOfContext;
constructor(options: Params);
verbose(message: any, context?: string, ...args: any[]): void;
debug(message: any, context?: string, ...args: any[]): void;
log(message: any, context?: string, ...args: any[]): void;
warn(message: any, context?: string, ...args: any[]): void;
error(message: any, trace?: string, context?: string, ...args: any[]): void;
private readonly logger;
}
export declare class LoggerModule implements NestModule {
static forRoot(...params: Params): DynamicModule;
configure(consumer: MiddlewareConsumer): void;
export declare class LoggerModule {
static forRoot(opts?: PassedLogger | LoggerOptions | DestinationStream): DynamicModule;
static forRoot(opts: LoggerOptions, stream: DestinationStream): DynamicModule;
static forRootAsync(options: LoggerModuleAsyncOptions): DynamicModule;
}
declare global {
namespace Express {
interface Request {
log: pino.Logger;
}
}
}
export {};

@@ -8,77 +8,160 @@ "use strict";

};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var LoggerModule_1;
var LoggerModule_1, LoggerCoreModule_1;
Object.defineProperty(exports, "__esModule", { value: true });
"use strict";
const common_1 = require("@nestjs/common");
const express_pino_logger_1 = __importDefault(require("express-pino-logger"));
const pino_http_1 = __importDefault(require("pino-http"));
const pino_1 = __importDefault(require("pino"));
const express_ctx_1 = require("express-ctx");
let outOfContextLogger;
const loggerKey = "logger";
let rootParams;
const LOGGER_KEY = "logger";
const OPTIONS_PROVIDER_TOKEN = "pino-options";
let Logger = class Logger {
verbose(...params) {
return (express_ctx_1.getValue(loggerKey) || outOfContextLogger).trace(...params);
constructor(options) {
if (Array.isArray(options)) {
this.outOfContext = pino_1.default(...options);
}
else if (isPassedLogger(options)) {
this.outOfContext = options.logger;
}
else {
this.outOfContext = pino_1.default(options || undefined);
}
}
debug(...params) {
return (express_ctx_1.getValue(loggerKey) || outOfContextLogger).debug(...params);
verbose(message, context, ...args) {
if (context) {
this.logger.trace({ context }, message, ...args);
}
else {
this.logger.trace(message);
}
}
log(...params) {
return (express_ctx_1.getValue(loggerKey) || outOfContextLogger).info(...params);
debug(message, context, ...args) {
if (context) {
this.logger.debug({ context }, message, ...args);
}
else {
this.logger.debug(message);
}
}
warn(...params) {
return (express_ctx_1.getValue(loggerKey) || outOfContextLogger).warn(...params);
log(message, context, ...args) {
if (context) {
this.logger.info({ context }, message, ...args);
}
else {
this.logger.info(message);
}
}
error(...params) {
return (express_ctx_1.getValue(loggerKey) || outOfContextLogger).error(...params);
warn(message, context, ...args) {
if (context) {
this.logger.warn({ context }, message, ...args);
}
else {
this.logger.warn(message);
}
}
error(message, trace, context, ...args) {
if (context) {
this.logger.error({ context, trace }, message, ...args);
}
else if (trace) {
this.logger.error({ trace }, message);
}
else {
this.logger.error(message);
}
}
get logger() {
return express_ctx_1.getValue(LOGGER_KEY) || this.outOfContext;
}
};
Logger = __decorate([
common_1.Injectable()
common_1.Injectable(),
__param(0, common_1.Inject(OPTIONS_PROVIDER_TOKEN)),
__metadata("design:paramtypes", [Object])
], Logger);
exports.Logger = Logger;
let LoggerModule = LoggerModule_1 = class LoggerModule {
static forRoot(...params) {
rootParams = params;
if (hasLoggerParamsPassedLogger(rootParams)) {
outOfContextLogger = rootParams[0].logger;
}
else {
outOfContextLogger = pino_1.default(...rootParams);
}
static forRoot(opts, stream) {
return {
module: LoggerModule_1,
providers: [Logger],
imports: [
LoggerCoreModule.forRoot(stream ? [opts, stream] : opts)
]
};
}
static forRootAsync(options) {
return {
module: LoggerModule_1,
imports: [LoggerCoreModule.forRootAsync(options)]
};
}
};
LoggerModule = LoggerModule_1 = __decorate([
common_1.Module({})
], LoggerModule);
exports.LoggerModule = LoggerModule;
let LoggerCoreModule = LoggerCoreModule_1 = class LoggerCoreModule {
constructor(options) {
this.options = options;
}
static forRoot(options) {
const optionsProvider = {
provide: OPTIONS_PROVIDER_TOKEN,
useValue: options || null
};
return {
module: LoggerCoreModule_1,
providers: [Logger, optionsProvider],
exports: [Logger]
};
}
static forRootAsync(options) {
const optionsProvider = {
provide: OPTIONS_PROVIDER_TOKEN,
useFactory: options.useFactory,
inject: options.inject
};
return {
module: LoggerCoreModule_1,
imports: options.imports,
providers: options.providers
? [Logger, optionsProvider, ...options.providers]
: [Logger, optionsProvider],
exports: [Logger]
};
}
configure(consumer) {
consumer
.apply(...createLoggerMiddlewares())
.apply(...createLoggerMiddlewares(this.options))
.forRoutes({ path: "*", method: common_1.RequestMethod.ALL });
}
};
LoggerModule = LoggerModule_1 = __decorate([
LoggerCoreModule = LoggerCoreModule_1 = __decorate([
common_1.Global(),
common_1.Module({
providers: [Logger],
exports: [Logger]
})
], LoggerModule);
exports.LoggerModule = LoggerModule;
function createLoggerMiddlewares() {
return [
express_ctx_1.middleware,
express_pino_logger_1.default(...rootParams),
(req, res, next) => {
express_ctx_1.setValue(loggerKey, req.log);
next();
}
];
common_1.Module({ providers: [Logger], exports: [Logger] }),
__param(0, common_1.Inject(OPTIONS_PROVIDER_TOKEN)),
__metadata("design:paramtypes", [Object])
], LoggerCoreModule);
function isPassedLogger(params) {
return !!params && "logger" in params;
}
function hasLoggerParamsPassedLogger(params) {
return params[0] && "logger" in params[0];
function createLoggerMiddlewares(params) {
const middleware = Array.isArray(params)
? pino_http_1.default(...params)
: pino_http_1.default(params || undefined);
return [express_ctx_1.middleware, middleware, bindLoggerMiddleware];
}
function bindLoggerMiddleware(req, res, next) {
express_ctx_1.setValue(LOGGER_KEY, req.log);
next();
}
//# sourceMappingURL=index.js.map
{
"name": "nestjs-pino",
"version": "0.2.1",
"version": "0.3.0",
"description": "Pino logger for NestJS",
"main": "dist/index.js",
"scripts": {
"test": "jest",
"build": "tsc --p tsconfig.build.json",
"test": "jest --verbose",
"build": "rm -rf ./dist && tsc --p tsconfig.build.json",
"report": "cat ./coverage/lcov.info | coveralls",
"example": "tsc && LOG_LEVEL=debug node dist/example/main"
"example": "rm -rf ./dist && tsc && LOG_LEVEL=debug node dist/example/main"
},

@@ -35,3 +35,3 @@ "engineStrict": false,

"express-ctx": "^0.1.1",
"express-pino-logger": "^4.0.0"
"pino-http": "^4.3.0"
},

@@ -45,6 +45,6 @@ "devDependencies": {

"@types/express": "^4.17.1",
"@types/express-pino-logger": "^4.0.1",
"@types/jest": "^24.0.18",
"@types/memorystream": "^0.3.0",
"@types/node": "^12.7.4",
"@types/pino-http": "^4.3.2",
"@types/supertest": "^2.0.8",

@@ -67,3 +67,2 @@ "coveralls": "^3.0.6",

],
"rootDir": "src",
"testRegex": ".spec.ts$",

@@ -75,4 +74,7 @@ "transform": {

"coverageDirectory": "../coverage",
"collectCoverageFrom": [
"src/**/*.ts"
],
"testEnvironment": "node"
}
}

@@ -27,2 +27,15 @@ <p align="center">

Import module:
```ts
import { LoggerModule } from 'nestjs-pino';
@Module({
imports: [LoggerModule.forRoot()],
controllers: [AppController],
providers: [MyService]
})
class MyModule {}
```
In controller:

@@ -42,3 +55,3 @@

getHello(): string {
this.logger.log("calling AppController.getHello");
this.logger.log("getHello()", AppController.name);
return `Hello ${this.myService.getWorld()}`;

@@ -58,4 +71,4 @@ }

getWorld() {
this.logger.debug("calling MyService.getWorld");
getWorld(...params: any[]) {
this.logger.log("getWorld(%o)", MyService.name, params);
return "World!";

@@ -66,8 +79,17 @@ }

Output (every log has request context):
Output:
```json
{"level":30,"time":1568720266616,"pid":25566,"hostname":"my-host","req":{"id":1,"method":"GET","url":"/","headers":{...},"remoteAddress":"::1","remotePort":53753},"msg":"calling AppController.getHello","v":1}
{"level":20,"time":1568720266616,"pid":25566,"hostname":"my-host","req":{"id":1,"method":"GET","url":"/","headers":{...},"remoteAddress":"::1","remotePort":53753},"msg":"calling MyService.getWorld","v":1}
{"level":30,"time":1568720266623,"pid":25566,"hostname":"my-host","req":{"id":1,"method":"GET","url":"/","headers":{...},"remoteAddress":"::1","remotePort":53753},"res":{"statusCode":200,"headers":{...}},"responseTime":9,"msg":"request completed","v":1}
// Logs by Nest itself, when set `app.useLogger(app.get(Logger))`
{"level":30,"time":1570470154387,"pid":17383,"hostname":"my-host","context":"RoutesResolver","msg":"AppController {/}: true","v":1}
{"level":30,"time":1570470154391,"pid":17383,"hostname":"my-host","context":"RouterExplorer","msg":"Mapped {/, GET} route true","v":1}
{"level":30,"time":1570470154405,"pid":17383,"hostname":"my-host","context":"NestApplication","msg":"Nest application successfully started true","v":1}
// Logs by injected Logger methods in Services/Controllers
// Every log has it's request data
{"level":30,"time":1570470161805,"pid":17383,"hostname":"my-host","req":{"id":1,"method":"GET","url":"/","headers":{...},"remoteAddress":"::1","remotePort":53957},"context":"AppController","msg":"getHello()","v":1}
{"level":30,"time":1570470161805,"pid":17383,"hostname":"my-host","req":{"id":1,"method":"GET","url":"/","headers":{...},"remoteAddress":"::1","remotePort":53957},"context":"MyService","msg":"getWorld([])","v":1}
// Automatic logs of every request/response
{"level":30,"time":1570470161819,"pid":17383,"hostname":"my-host","req":{"id":1,"method":"GET","url":"/","headers":{...},"remoteAddress":"::1","remotePort":53957},"res":{"statusCode":304,"headers":{...}},"responseTime":15,"msg":"request completed","v":1}
```

@@ -97,5 +119,5 @@

### Configure
### Synchronous configuration
Also, you can configure it. `forRoot` function has the same API as [express-pino-logger](https://github.com/pinojs/express-pino-logger#api) has (it's the same as [pino itself](https://github.com/pinojs/pino/blob/master/docs/api.md#options) and can take existing logger via `{ logger: pino(...) }`):
`LoggerModule.forRoot` has the same API as [pino-http](https://github.com/pinojs/pino-http#pinohttpopts-stream):

@@ -123,2 +145,64 @@ ```ts

### Asynchronous configuration
With `LoggerModule.forRootAsync` you can for example import your `ConfigModule` and inject `ConfigService` to use it in `useFactory` method.
`useFactory` should return result typeof arguments of [pino-http](https://github.com/pinojs/pino-http#pinohttpopts-stream) or `null`, example:
```ts
import { LoggerModule } from 'nestjs-pino';
@Injectable()
class ConfigService {
public readonly level = "debug";
}
@Module({
providers: [ConfigService],
exports: [ConfigService]
})
class ConfigModule {}
@Module({
imports: [
LoggerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => {
return { level: config.level };
}
})
],
...
})
class TestModule {}
```
Or without `ConfigModule` you can just pass `ConfigService` to `providers`:
```ts
import { LoggerModule } from 'nestjs-pino';
@Injectable()
class ConfigService {
public readonly level = "debug";
public readonly stream = stream;
}
@Module({
imports: [
LoggerModule.forRootAsync({
providers: [ConfigService],
inject: [ConfigService],
useFactory: (config: ConfigService) => {
return [{ level: config.level }, config.stream];
}
})
],
controllers: [TestController]
})
class TestModule {}
```
### Extreme mode

@@ -158,4 +242,4 @@

getWorld() {
this.logger.debug("calling MyService.getWorld");
getWorld(...params: any[]) {
this.logger.log("getWorld(%o)", MyService.name, params);
return "World!";

@@ -168,6 +252,9 @@ }

According to [official docs](https://docs.nestjs.com/techniques/logger#dependency-injection), loggers with Dependency injection should be set via following construction:
```ts
import { Logger } from 'nestjs-pino';
const app = await NestFactory.create(MyModule, { logger: new Logger() });
const app = await NestFactory.create(MyModule, { logger: false });
app.useLogger(app.get(Logger));
```

@@ -179,3 +266,3 @@

__A__: It use [express-pino-logger](https://github.com/pinojs/express-pino-logger) under hood, so every request has it's own [child-logger](https://github.com/pinojs/pino/blob/master/docs/child-loggers.md), and with help of [async_hooks](https://nodejs.org/api/async_hooks.html) `Logger` can get it while calling own methods. So your logs can be groupped by `req.id`.
__A__: It use [pino-http](https://github.com/pinojs/pino-http) under hood, so every request has it's own [child-logger](https://github.com/pinojs/pino/blob/master/docs/child-loggers.md), and with help of [async_hooks](https://nodejs.org/api/async_hooks.html) `Logger` can get it while calling own methods. So your logs can be groupped by `req.id`.

@@ -193,6 +280,9 @@ __Q__: _Why use [async_hooks](https://nodejs.org/api/async_hooks.html) instead of [REQUEST scope](https://docs.nestjs.com/fundamentals/injection-scopes#per-request-injection)?_

__A__: Pino built in methods are not compatible to NestJS built in `LoggerService` methods, so decision is to map pino methods to `LoggerService` methods to save `Logger` API:
- `trace`=`verbose`
- `debug`=`debug`
- `info`=`log`
- `warn`=`warn`
- `error`=`error`
| pino | LoggerService |
| ------- | ------------- |
| `trace` | `verbose` |
| `debug` | `debug` |
| `info` | `log` |
| `warn` | `warn` |
| `error` | `error` |
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "dist", "**/*.spec.ts", "example"]
"include": ["src"]
}

@@ -13,5 +13,6 @@ {

"incremental": true,
"esModuleInterop": true
"esModuleInterop": true,
"strict": true
},
"exclude": ["node_modules", "dist"]
"include": ["src", "example", "__tests__"]
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc