Repository: iamolegga/nestjs-pino
Pull request #152 (2020-01-06 16:30:59)

Multiparams


Patch:
diff --git a/.npmignore b/.npmignore
index 118aca0..6cca171 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,5 +1,11 @@
+__tests__/
+.github/
 coverage/
+dist/*.tsbuildinfo
 example/
 src/
+.mergify.yml
 .travis.yml
+CONTRIBUTING.md
+logo.png
 README.md
diff --git a/README.md b/README.md
index c14acd2..743814f 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
 <p align="center">
-  <img alt="NestJS-Pino logo" src="./logo.png"/>
+  <img alt="NestJS-Pino logo" src="https://github.com/iamolegga/nestjs-pino/blob/master/logo.png"/>
 </p>
 
 <h1 align="center">NestJS-Pino</h1>
@@ -169,7 +169,7 @@ npm i nestjs-pino
 
 ## Register module
 
-### Default params
+### Zero configuration
 
 Just import `LoggerModule` to your module:
 
@@ -183,25 +183,73 @@ import { LoggerModule } from 'nestjs-pino';
 class MyModule {}
 ```
 
+### Configuration params
+
+`nestjs-pino` can be configured with params object of next interface:
+
+```ts
+interface Params {
+  /**
+   * Optional parameters for `pino-http` module
+   * @see https://github.com/pinojs/pino-http#pinohttpopts-stream
+   */
+  pinoHttp?:
+    | pinoHttp.Options
+    | DestinationStream
+    | [pinoHttp.Options, DestinationStream];
+
+  /**
+   * Optional parameter for routing. It should implement interface of
+   * parameters of NestJS buil-in `MiddlewareConfigProxy['forRoutes']`.
+   * @see https://docs.nestjs.com/middleware#applying-middleware
+   * It can be used for disabling automatic req/res logs (see above).
+   * Keep in mind that it will remove context data from logs that are called
+   * inside not included or excluded routes and controlles.
+   */
+  forRoutes?: Parameters<MiddlewareConfigProxy["forRoutes"]>;
+
+  /**
+   * Optional parameter for routing. It should implement interface of
+   * parameters of NestJS buil-in `MiddlewareConfigProxy['exclude']`.
+   * @see https://docs.nestjs.com/middleware#applying-middleware
+   * It can be used for disabling automatic req/res logs (see above).
+   * Keep in mind that it will remove context data from logs that are called
+   * inside not included or excluded routes and controlles.
+   */
+  exclude?: Parameters<MiddlewareConfigProxy["exclude"]>;
+
+  /**
+   * Optional parameter to skip `pino` configuration in case you are using
+   * Fastify adapter, and already configuring it on adapter level.
+   * Pros and cons of this approach are descibed in the last section.
+   */
+  useExisting?: true;
+}
+```
+
 ### Synchronous configuration
 
-`LoggerModule.forRoot` has the same API as [pino-http](https://github.com/pinojs/pino-http#pinohttpopts-stream):
+Use `LoggerModule.forRoot` method with argument of [Params interface](#configuration-params):
 
 ```ts
 import { LoggerModule } from 'nestjs-pino';
 
 @Module({
   imports: [
-    LoggerModule.forRoot(
-      {
-        name: 'add some name to every JSON line',
-        level: process.env.NODE_ENV !== 'production' ? 'debug' : 'info',
-        prettyPrint: process.env.NODE_ENV !== 'production',
-        useLevelLabels: true,
-        // and all the others...
-      },
-      someWritableStream
-    )
+    LoggerModule.forRoot({
+      pinoHttp: [
+        {
+          name: 'add some name to every JSON line',
+          level: process.env.NODE_ENV !== 'production' ? 'debug' : 'info',
+          prettyPrint: process.env.NODE_ENV !== 'production',
+          useLevelLabels: true,
+          // and all the others...
+        },
+        someWritableStream
+      ],
+      forRoutes: [MyController],
+      exclude: [{ method: RequestMethod.ALL, path: "check" }]
+    })
   ],
   ...
 })
@@ -213,10 +261,7 @@ class MyModule {}
 
 With `LoggerModule.forRootAsync` you can, for example, import your `ConfigModule` and inject `ConfigService` to use it in `useFactory` method.
 
-`useFactory` should return either:
-- `null`
-- or `typeof arguments` of [pino-http](https://github.com/pinojs/pino-http#pinohttpopts-stream)
-- or `Promise` of it
+`useFactory` should return object with [Params interface](#configuration-params) or undefined
 
 Here's an example:
 
@@ -241,7 +286,9 @@ class ConfigModule {}
       inject: [ConfigService],
       useFactory: async (config: ConfigService) => {
         await somePromise();
-        return { level: config.level };
+        return {
+          pinoHttp: { level: config.level },
+        };
       }
     })
   ],
@@ -267,7 +314,9 @@ class ConfigService {
       providers: [ConfigService],
       inject: [ConfigService],
       useFactory: (config: ConfigService) => {
-        return [{ level: config.level }, config.stream];
+        return {
+          pinoHttp: [{ level: config.level }, config.stream],
+        };
       }
     })
   ],
@@ -291,7 +340,7 @@ const dest = pino.extreme();
 const logger = pino(dest);
 
 @Module({
-  imports: [LoggerModule.forRoot({ logger })],
+  imports: [LoggerModule.forRoot({ pinoHttp: { logger } })],
   ...
 })
 class MyModule {}
@@ -364,6 +413,13 @@ const app = await NestFactory.create(MyModule, { logger: false });
 app.useLogger(app.get(Logger));
 ```
 
+## Migrating
+
+### v1
+
+- All parameters of v.0 are moved to `pinoHttp` property (except `useExisting`).
+- `useExisting` now accept only `true`, because `false` does not make any sense
+
 ## FAQ
 
 __Q__: _How does it work?_
diff --git a/package-lock.json b/package-lock.json
index 14e8a87..e07690a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "nestjs-pino",
-  "version": "0.6.0",
+  "version": "1.0.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -3114,9 +3114,9 @@
       "dev": true
     },
     "handlebars": {
-      "version": "4.3.1",
-      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.3.1.tgz",
-      "integrity": "sha512-c0HoNHzDiHpBt4Kqe99N8tdLPKAnGCQ73gYMPWtAYM4PwGnf7xl8PBUHJqh9ijlzt2uQKaSRxbXRt+rZ7M2/kA==",
+      "version": "4.5.3",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
+      "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
       "dev": true,
       "requires": {
         "neo-async": "^2.6.0",
@@ -6253,14 +6253,23 @@
       "dev": true
     },
     "uglify-js": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz",
-      "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==",
+      "version": "3.7.3",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.3.tgz",
+      "integrity": "sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==",
       "dev": true,
       "optional": true,
       "requires": {
-        "commander": "~2.20.0",
+        "commander": "~2.20.3",
         "source-map": "~0.6.1"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.20.3",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+          "dev": true,
+          "optional": true
+        }
       }
     },
     "union-value": {
diff --git a/package.json b/package.json
index bd512c7..9ba8de1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "nestjs-pino",
-  "version": "0.6.0",
+  "version": "1.0.0",
   "description": "Pino logger for NestJS",
   "main": "dist/index.js",
   "scripts": {
diff --git a/src/LoggerCoreModule.ts b/src/LoggerCoreModule.ts
index 6ec0aee..c48b81c 100644
--- a/src/LoggerCoreModule.ts
+++ b/src/LoggerCoreModule.ts
@@ -12,34 +12,36 @@ import * as express from "express";
 import * as pinoHttp from "pino-http";
 import { setValue, middleware as ctxMiddleware } from "express-ctx";
 import { Logger } from "./Logger";
-import { OPTIONS_PROVIDER_TOKEN, LOGGER_KEY } from "./constants";
-import { Params, LoggerModuleAsyncOptions } from "./params";
+import { PARAMS_PROVIDER_TOKEN, LOGGER_KEY } from "./constants";
+import { Params, LoggerModuleAsyncParams } from "./params";
 import { PinoLogger } from "./PinoLogger";
 import { createProvidersForDecorated } from "./InjectPinoLogger";
 
+const DEFAULT_ROUTES = [{ path: "*", method: RequestMethod.ALL }];
+
 @Global()
 @Module({ providers: [Logger], exports: [Logger] })
 export class LoggerCoreModule implements NestModule {
-  static forRoot(options: Params | undefined): DynamicModule {
-    const optionsProvider: Provider<Params> = {
-      provide: OPTIONS_PROVIDER_TOKEN,
-      useValue: options || null
+  static forRoot(params: Params | undefined): DynamicModule {
+    const paramsProvider: Provider<Params> = {
+      provide: PARAMS_PROVIDER_TOKEN,
+      useValue: params || {}
     };
 
     const decorated = createProvidersForDecorated();
 
     return {
       module: LoggerCoreModule,
-      providers: [Logger, ...decorated, PinoLogger, optionsProvider],
+      providers: [Logger, ...decorated, PinoLogger, paramsProvider],
       exports: [Logger, ...decorated, PinoLogger]
     };
   }
 
-  static forRootAsync(options: LoggerModuleAsyncOptions): DynamicModule {
-    const optionsProvider: Provider<Params | Promise<Params>> = {
-      provide: OPTIONS_PROVIDER_TOKEN,
-      useFactory: options.useFactory,
-      inject: options.inject
+  static forRootAsync(params: LoggerModuleAsyncParams): DynamicModule {
+    const paramsProvider: Provider<Params | Promise<Params>> = {
+      provide: PARAMS_PROVIDER_TOKEN,
+      useFactory: params.useFactory,
+      inject: params.inject
     };
 
     const decorated = createProvidersForDecorated();
@@ -48,36 +50,51 @@ export class LoggerCoreModule implements NestModule {
       Logger,
       ...decorated,
       PinoLogger,
-      optionsProvider,
-      ...(options.providers || [])
+      paramsProvider,
+      ...(params.providers || [])
     ];
 
     return {
       module: LoggerCoreModule,
-      imports: options.imports,
+      imports: params.imports,
       providers,
       exports: [Logger, ...decorated, PinoLogger]
     };
   }
 
-  constructor(
-    @Inject(OPTIONS_PROVIDER_TOKEN) private readonly options: Params
-  ) {}
+  constructor(@Inject(PARAMS_PROVIDER_TOKEN) private readonly params: Params) {}
 
   configure(consumer: MiddlewareConsumer) {
-    consumer
-      .apply(...createLoggerMiddlewares(this.options || {}))
-      .forRoutes({ path: "*", method: RequestMethod.ALL });
+    const {
+      exclude,
+      forRoutes = DEFAULT_ROUTES,
+      pinoHttp,
+      useExisting
+    } = this.params;
+
+    const middlewares = createLoggerMiddlewares(pinoHttp || {}, useExisting);
+
+    if (exclude) {
+      consumer
+        .apply(...middlewares)
+        .exclude(...exclude)
+        .forRoutes(...forRoutes);
+    } else {
+      consumer.apply(...middlewares).forRoutes(...forRoutes);
+    }
   }
 }
 
-function createLoggerMiddlewares(params: Exclude<Params, null>) {
-  if (Array.isArray(params)) {
-    return [ctxMiddleware, pinoHttp(...params), bindLoggerMiddleware];
+function createLoggerMiddlewares(
+  params: NonNullable<Params["pinoHttp"]>,
+  useExisting?: true
+) {
+  if (useExisting) {
+    return [ctxMiddleware, bindLoggerMiddleware];
   }
 
-  if ("useExisting" in params) {
-    return [ctxMiddleware, bindLoggerMiddleware];
+  if (Array.isArray(params)) {
+    return [ctxMiddleware, pinoHttp(...params), bindLoggerMiddleware];
   }
 
   // FIXME: params type here is pinoHttp.Options | pino.DestinationStream
diff --git a/src/LoggerModule.ts b/src/LoggerModule.ts
index 8a0f8dd..2e42fd1 100644
--- a/src/LoggerModule.ts
+++ b/src/LoggerModule.ts
@@ -1,29 +1,20 @@
 import { Module, DynamicModule } from "@nestjs/common";
-import { DestinationStream, LoggerOptions } from "pino";
-import { PassedLogger, LoggerModuleAsyncOptions, Params } from "./params";
+import { LoggerModuleAsyncParams, Params } from "./params";
 import { LoggerCoreModule } from "./LoggerCoreModule";
 
 @Module({})
 export class LoggerModule {
-  static forRoot(
-    opts?: Exclude<Params, [LoggerOptions, DestinationStream]>
-  ): DynamicModule;
-  static forRoot(opts: LoggerOptions, stream: DestinationStream): DynamicModule;
-  static forRoot(opts?: Params, stream?: DestinationStream): DynamicModule {
+  static forRoot(params?: Params | undefined): DynamicModule {
     return {
       module: LoggerModule,
-      imports: [
-        LoggerCoreModule.forRoot(
-          stream ? [opts as LoggerOptions, stream] : opts
-        )
-      ]
+      imports: [LoggerCoreModule.forRoot(params)]
     };
   }
 
-  static forRootAsync(options: LoggerModuleAsyncOptions): DynamicModule {
+  static forRootAsync(params: LoggerModuleAsyncParams): DynamicModule {
     return {
       module: LoggerModule,
-      imports: [LoggerCoreModule.forRootAsync(options)]
+      imports: [LoggerCoreModule.forRootAsync(params)]
     };
   }
 }
diff --git a/src/PinoLogger.ts b/src/PinoLogger.ts
index 63be1f6..67d22d0 100644
--- a/src/PinoLogger.ts
+++ b/src/PinoLogger.ts
@@ -1,7 +1,7 @@
 import { Injectable, Inject, Scope } from "@nestjs/common";
 import * as pino from "pino";
 import { getValue } from "express-ctx";
-import { OPTIONS_PROVIDER_TOKEN, LOGGER_KEY } from "./constants";
+import { PARAMS_PROVIDER_TOKEN, LOGGER_KEY } from "./constants";
 import { Params, isPassedLogger } from "./params";
 
 interface PinoMethods
@@ -26,17 +26,14 @@ export function __resetOutOfContextForTests() {
 export class PinoLogger implements PinoMethods {
   private context = "";
 
-  constructor(@Inject(OPTIONS_PROVIDER_TOKEN) options: Params) {
+  constructor(@Inject(PARAMS_PROVIDER_TOKEN) { pinoHttp }: Params) {
     if (!outOfContext) {
-      if (Array.isArray(options)) {
-        outOfContext = pino(...options);
-      } else if (isPassedLogger(options)) {
-        outOfContext = options.logger;
-      } else if (options && "useExisting" in options) {
-        const { useExisting, ...rest } = options;
-        outOfContext = pino(rest);
+      if (Array.isArray(pinoHttp)) {
+        outOfContext = pino(...pinoHttp);
+      } else if (isPassedLogger(pinoHttp)) {
+        outOfContext = pinoHttp.logger;
       } else {
-        outOfContext = pino(options || undefined);
+        outOfContext = pino(pinoHttp);
       }
     }
   }
diff --git a/src/constants.ts b/src/constants.ts
index 0742550..c41cd20 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -1,3 +1,3 @@
 export const LOGGER_KEY = "logger";
 
-export const OPTIONS_PROVIDER_TOKEN = "pino-options";
+export const PARAMS_PROVIDER_TOKEN = "pino-params";
diff --git a/src/index.ts b/src/index.ts
index 45ccaeb..8cc34ce 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,5 +1,5 @@
 export { LoggerModule } from "./LoggerModule";
-export { Params, LoggerModuleAsyncOptions } from "./params";
+export { Params, LoggerModuleAsyncParams } from "./params";
 export { Logger } from "./Logger";
 export { PinoLogger } from "./PinoLogger";
 export { InjectPinoLogger } from "./InjectPinoLogger";
diff --git a/src/params.ts b/src/params.ts
index e5295d1..317a057 100644
--- a/src/params.ts
+++ b/src/params.ts
@@ -1,25 +1,31 @@
 import * as pinoHttp from "pino-http";
 import * as pino from "pino";
 import { DestinationStream } from "pino";
-import { ModuleMetadata } from "@nestjs/common/interfaces";
+import {
+  ModuleMetadata,
+  MiddlewareConfigProxy
+} from "@nestjs/common/interfaces";
 
 export type PassedLogger = { logger: pino.Logger };
 
-export type UseExisting = { useExisting: boolean };
-
-export type Params =
-  | null
-  | pinoHttp.Options
-  | DestinationStream
-  | [pinoHttp.Options, DestinationStream]
-  | UseExisting;
+export interface Params {
+  pinoHttp?:
+    | pinoHttp.Options
+    | DestinationStream
+    | [pinoHttp.Options, DestinationStream];
+  exclude?: Parameters<MiddlewareConfigProxy["exclude"]>;
+  forRoutes?: Parameters<MiddlewareConfigProxy["forRoutes"]>;
+  useExisting?: true;
+}
 
-export interface LoggerModuleAsyncOptions
+export interface LoggerModuleAsyncParams
   extends Pick<ModuleMetadata, "imports" | "providers"> {
   useFactory: (...args: any[]) => Params | Promise<Params>;
   inject?: any[];
 }
 
-export function isPassedLogger(params: Params): params is PassedLogger {
-  return !!params && "logger" in params;
+export function isPassedLogger(
+  pinoHttpProp: any
+): pinoHttpProp is PassedLogger {
+  return !!pinoHttpProp && "logger" in pinoHttpProp;
 }


Test patch:
diff --git a/__tests__/inject.spec.ts b/__tests__/inject.spec.ts
index 425ba42..05db013 100644
--- a/__tests__/inject.spec.ts
+++ b/__tests__/inject.spec.ts
@@ -50,7 +50,7 @@ describe("InjectPinoLogger", () => {
         }
 
         @Module({
-          imports: [LoggerModule.forRoot(stream)],
+          imports: [LoggerModule.forRoot({ pinoHttp: stream })],
           controllers: [TestController],
           providers: [TestService]
         })
diff --git a/__tests__/levels.spec.ts b/__tests__/levels.spec.ts
index 26b990c..8f72d8e 100644
--- a/__tests__/levels.spec.ts
+++ b/__tests__/levels.spec.ts
@@ -70,7 +70,9 @@ describe(`${Logger.name} levels`, () => {
           }
 
           @Module({
-            imports: [LoggerModule.forRoot({ level: pinoLevel }, stream)],
+            imports: [
+              LoggerModule.forRoot({ pinoHttp: [{ level: pinoLevel }, stream] })
+            ],
             controllers: [TestController],
             providers: [TestService]
           })
@@ -172,7 +174,9 @@ describe(`${PinoLogger.name} levels`, () => {
           }
 
           @Module({
-            imports: [LoggerModule.forRoot({ level: pinoLevel }, stream)],
+            imports: [
+              LoggerModule.forRoot({ pinoHttp: [{ level: pinoLevel }, stream] })
+            ],
             controllers: [TestController],
             providers: [TestService]
           })
diff --git a/__tests__/module.spec.ts b/__tests__/module.spec.ts
index ae959e2..a19cc09 100644
--- a/__tests__/module.spec.ts
+++ b/__tests__/module.spec.ts
@@ -40,7 +40,7 @@ describe("module initialization", () => {
           await fastifyExtraWait(PlatformAdapter, app);
         });
 
-        it("should work properly with single param", async () => {
+        it("should work properly with single value of `httpPino` property", async () => {
           const stream = new MemoryStream();
           const random = Math.random().toString();
           let logs = "";
@@ -59,7 +59,7 @@ describe("module initialization", () => {
           }
 
           @Module({
-            imports: [LoggerModule.forRoot(stream)],
+            imports: [LoggerModule.forRoot({ pinoHttp: stream })],
             controllers: [TestController]
           })
           class TestModule {}
@@ -82,7 +82,7 @@ describe("module initialization", () => {
           expect(logObject).toBeTruthy();
         });
 
-        it("should work properly with two params", async () => {
+        it("should work properly with array as value of `httpPino` property", async () => {
           const stream = new MemoryStream();
           const random = Math.random().toString();
           let logs = "";
@@ -101,7 +101,9 @@ describe("module initialization", () => {
           }
 
           @Module({
-            imports: [LoggerModule.forRoot({ level: "debug" }, stream)],
+            imports: [
+              LoggerModule.forRoot({ pinoHttp: [{ level: "debug" }, stream] })
+            ],
             controllers: [TestController]
           })
           class TestModule {}
@@ -126,33 +128,7 @@ describe("module initialization", () => {
       });
 
       describe("forRootAsync", () => {
-        it("should compile when useFactory returns null", async () => {
-          @Controller("/")
-          class TestController {
-            constructor(private readonly logger: Logger) {}
-            @Get("/")
-            get() {
-              this.logger.log("");
-              return {};
-            }
-          }
-
-          @Module({
-            imports: [LoggerModule.forRootAsync({ useFactory: () => null })],
-            controllers: [TestController]
-          })
-          class TestModule {}
-
-          const app = await NestFactory.create(
-            TestModule,
-            new PlatformAdapter(),
-            { logger: false }
-          );
-          await app.init();
-          await fastifyExtraWait(PlatformAdapter, app);
-        });
-
-        it("should work properly when useFactory returns single params", async () => {
+        it("should work properly when useFactory returns single value of `httpPino` property", async () => {
           const stream = new MemoryStream();
           const random = Math.random().toString();
           let logs = "";
@@ -188,7 +164,7 @@ describe("module initialization", () => {
                 imports: [ConfigModule],
                 inject: [ConfigService],
                 useFactory: (config: ConfigService) => {
-                  return config.stream;
+                  return { pinoHttp: config.stream };
                 }
               })
             ],
@@ -214,7 +190,7 @@ describe("module initialization", () => {
           expect(logObject).toBeTruthy();
         });
 
-        it("should work properly when useFactory returns array of two params", async () => {
+        it("should work properly when useFactory returns array as value of `httpPino` property", async () => {
           const stream = new MemoryStream();
           const random = Math.random().toString();
           let logs = "";
@@ -251,7 +227,7 @@ describe("module initialization", () => {
                 imports: [ConfigModule],
                 inject: [ConfigService],
                 useFactory: (config: ConfigService) => {
-                  return [{ level: config.level }, config.stream];
+                  return { pinoHttp: [{ level: config.level }, config.stream] };
                 }
               })
             ],
@@ -307,7 +283,7 @@ describe("module initialization", () => {
                 providers: [ConfigService],
                 inject: [ConfigService],
                 useFactory: (config: ConfigService) => {
-                  return config.stream;
+                  return { pinoHttp: config.stream };
                 }
               })
             ],
@@ -370,7 +346,7 @@ describe("module initialization", () => {
                 inject: [ConfigService],
                 useFactory: async (config: ConfigService) => {
                   await new Promise(r => setTimeout(r, 10));
-                  return config.stream;
+                  return { pinoHttp: config.stream };
                 }
               })
             ],
diff --git a/__tests__/pass-logger.spec.ts b/__tests__/pass-logger.spec.ts
index 7b942b1..e097ed2 100644
--- a/__tests__/pass-logger.spec.ts
+++ b/__tests__/pass-logger.spec.ts
@@ -42,7 +42,9 @@ describe("pass existing logger", () => {
         }
 
         @Module({
-          imports: [LoggerModule.forRoot({ logger: pino(stream) })],
+          imports: [
+            LoggerModule.forRoot({ pinoHttp: { logger: pino(stream) } })
+          ],
           controllers: [TestController],
           providers: [TestService]
         })
diff --git a/__tests__/routing.spec.ts b/__tests__/routing.spec.ts
new file mode 100644
index 0000000..c6bf8ec
--- /dev/null
+++ b/__tests__/routing.spec.ts
@@ -0,0 +1,102 @@
+import { NestFactory } from "@nestjs/core";
+import { Module, Controller, Get, RequestMethod } from "@nestjs/common";
+import MemoryStream = require("memorystream");
+import * as request from "supertest";
+import { Logger, LoggerModule } from "../src";
+import { platforms } from "./utils/platforms";
+import { fastifyExtraWait } from "./utils/fastifyExtraWait";
+import { parseLogs } from "./utils/logs";
+import { __resetOutOfContextForTests } from "../src/PinoLogger";
+
+describe("routing", () => {
+  beforeEach(() => __resetOutOfContextForTests());
+
+  for (const PlatformAdapter of platforms) {
+    describe(PlatformAdapter.name, () => {
+      it("routing should work properly", async () => {
+        const logValue = Math.random().toString();
+        const logValue2 = Math.random().toString();
+        const logValue3 = Math.random().toString();
+
+        let logs = "";
+        const stream = new MemoryStream();
+        stream.on("data", (chunk: string) => {
+          logs += chunk.toString();
+        });
+
+        @Controller("/")
+        class LoggingController {
+          constructor(private readonly logger: Logger) {}
+          @Get("/")
+          withLog() {
+            this.logger.log(logValue);
+            return {};
+          }
+
+          @Get("/skip-log")
+          skipLog() {
+            this.logger.log(logValue2);
+            return {};
+          }
+        }
+
+        @Controller("/no-logging")
+        class NoLoggingController {
+          constructor(private readonly logger: Logger) {}
+          @Get()
+          get() {
+            this.logger.log(logValue3);
+            return {};
+          }
+        }
+
+        @Module({
+          imports: [
+            LoggerModule.forRoot({
+              pinoHttp: stream,
+              forRoutes: [LoggingController],
+              exclude: [{ method: RequestMethod.ALL, path: "skip-log" }]
+            })
+          ],
+          controllers: [LoggingController, NoLoggingController]
+        })
+        class TestModule {}
+
+        const app = await NestFactory.create(
+          TestModule,
+          new PlatformAdapter(),
+          { logger: false }
+        );
+        const server = app.getHttpServer();
+
+        await app.init();
+        await fastifyExtraWait(PlatformAdapter, app);
+
+        await Promise.all([
+          request(server).get("/"),
+          request(server).get("/skip-log"),
+          request(server).get("/no-logging")
+        ]);
+        await app.close();
+
+        const parsedLogs = parseLogs(logs);
+
+        // log object of included controller should have `req` property
+        const logObject = parsedLogs.find(v => v.msg === logValue && !!v.req);
+        expect(logObject).toBeTruthy();
+
+        // log object of included controller but excluded route should not have `req` property
+        const logObject2 = parsedLogs.find(v => v.msg === logValue2 && !v.req);
+        expect(logObject2).toBeTruthy();
+
+        // log object of not included controller should not have `req` property
+        const logObject3 = parsedLogs.find(v => v.msg === logValue3);
+        expect(logObject3).toBeTruthy();
+
+        // should be only 1 req/res auto log
+        const responseLogObjects = parsedLogs.filter(v => !!v.res);
+        expect(responseLogObjects).toHaveLength(1);
+      });
+    });
+  }
+});
diff --git a/__tests__/use-existing.spec.ts b/__tests__/use-existing.spec.ts
index 18cef4f..787c1b2 100644
--- a/__tests__/use-existing.spec.ts
+++ b/__tests__/use-existing.spec.ts
@@ -18,7 +18,7 @@ describe("useExisting property", () => {
   beforeEach(() => __resetOutOfContextForTests());
 
   describe(FastifyAdapter.name, () => {
-    it("should use adapter logger in req context and dafault beyond", async () => {
+    it("should use adapter logger in req context and default beyond", async () => {
       const stream = new MemoryStream();
       const random = Math.random().toString();
       const moduleInitMessage = "module initiated";
diff --git a/__tests__/utils/logs.ts b/__tests__/utils/logs.ts
index dcfed23..009ac6a 100644
--- a/__tests__/utils/logs.ts
+++ b/__tests__/utils/logs.ts
@@ -1,6 +1,7 @@
 export type LogObject = {
   msg: string;
   req?: { id: number };
+  res?: object;
   context?: string;
   trace?: string;
 };