1 | <p align="center">
|
2 | <img alt="NestJS-Pino logo" src="https://raw.githubusercontent.com/iamolegga/nestjs-pino/master/logo.png"/>
|
3 | </p>
|
4 |
|
5 | <h1 align="center">NestJS-Pino</h1>
|
6 |
|
7 | <p align="center">
|
8 | <a href="https://www.npmjs.com/package/nestjs-pino">
|
9 | <img alt="npm" src="https://img.shields.io/npm/v/nestjs-pino" />
|
10 | </a>
|
11 | <a href="https://travis-ci.org/iamolegga/nestjs-pino">
|
12 | <img alt="Travis (.org)" src="https://img.shields.io/travis/iamolegga/nestjs-pino" />
|
13 | </a>
|
14 | <a href="https://coveralls.io/github/iamolegga/nestjs-pino?branch=master">
|
15 | <img alt="Coverage Status" src="https://coveralls.io/repos/github/iamolegga/nestjs-pino/badge.svg?branch=master" />
|
16 | </a>
|
17 | <a href="https://snyk.io/test/github/iamolegga/nestjs-pino">
|
18 | <img alt="Snyk Vulnerabilities for npm package" src="https://img.shields.io/snyk/vulnerabilities/npm/nestjs-pino" />
|
19 | </a>
|
20 | <img alt="David" src="https://img.shields.io/david/iamolegga/nestjs-pino">
|
21 | <img alt="Dependabot" src="https://badgen.net/dependabot/iamolegga/nestjs-pino/?icon=dependabot">
|
22 | <img alt="Supported platforms: Express & Fastify" src="https://img.shields.io/badge/platforms-Express%20%26%20Fastify-green" />
|
23 | </p>
|
24 |
|
25 | <p align="center">✨✨✨ Platform agnostic logger for NestJS based on Pino with <b>REQUEST CONTEXT IN EVERY LOG</b> ✨✨✨</p>
|
26 |
|
27 | ## Example
|
28 |
|
29 | Import module with `LoggerModule.forRoot(...)` or `LoggerModule.forRootAsync(...)`:
|
30 |
|
31 | ```ts
|
32 | import { LoggerModule } from "nestjs-pino";
|
33 |
|
34 | @Module({
|
35 | imports: [LoggerModule.forRoot()],
|
36 | controllers: [AppController],
|
37 | providers: [MyService]
|
38 | })
|
39 | class MyModule {}
|
40 | ```
|
41 |
|
42 | In controller let's use `Logger` - class with the same API as [built-in NestJS logger](https://docs.nestjs.com/techniques/logger):
|
43 |
|
44 | ```ts
|
45 | import { Logger } from "nestjs-pino";
|
46 |
|
47 | @Controller()
|
48 | export class AppController {
|
49 | constructor(
|
50 | private readonly myService: MyService,
|
51 | private readonly logger: Logger
|
52 | ) {}
|
53 |
|
54 | @Get()
|
55 | getHello(): string {
|
56 | // pass message
|
57 | this.logger.log("getHello()");
|
58 |
|
59 | // also we can pass context
|
60 | this.logger.log("getHello()", AppController.name);
|
61 |
|
62 | return `Hello ${this.myService.getWorld()}`;
|
63 | }
|
64 | }
|
65 | ```
|
66 |
|
67 | Let's compare it to another one logger - `PinoLogger`, it has same _logging_ API as `pino` instance.
|
68 |
|
69 | For example in service it will be used instead of previous one:
|
70 |
|
71 | ```ts
|
72 | import { PinoLogger } from "nestjs-pino";
|
73 |
|
74 | @Injectable()
|
75 | export class MyService {
|
76 | constructor(private readonly logger: PinoLogger) {}
|
77 |
|
78 | getWorld(...params: any[]) {
|
79 | this.logger.info({ context: MyService.name }, "getWorld(%o)", params);
|
80 | return "World!";
|
81 | }
|
82 | }
|
83 | ```
|
84 |
|
85 | Also context can be set just once in `constructor` instead of every call:
|
86 |
|
87 | ```ts
|
88 | import { PinoLogger } from "nestjs-pino";
|
89 |
|
90 | @Injectable()
|
91 | export class MyService {
|
92 | constructor(private readonly logger: PinoLogger) {
|
93 | logger.setContext(MyService.name);
|
94 | }
|
95 |
|
96 | getWorld(...params: any[]) {
|
97 | this.logger.info("getWorld(%o)", params);
|
98 | return "World!";
|
99 | }
|
100 | }
|
101 | ```
|
102 |
|
103 | Also context can be set at injection via decorator `@InjectPinoLogger(...)`:
|
104 |
|
105 | ```ts
|
106 | import { PinoLogger, InjectPinoLogger } from "nestjs-pino";
|
107 |
|
108 | @Injectable()
|
109 | export class MyService {
|
110 | constructor(
|
111 | @InjectPinoLogger(MyService.name) private readonly logger: PinoLogger
|
112 | ) {}
|
113 |
|
114 | getWorld(...params: any[]) {
|
115 | this.logger.info("getWorld(%o)", params);
|
116 | return "World!";
|
117 | }
|
118 | }
|
119 | ```
|
120 |
|
121 | And also `Logger` can be set as app logger, as it is compatible with [built-in NestJS logger](https://docs.nestjs.com/techniques/logger):
|
122 |
|
123 | ```ts
|
124 | import { Logger } from "nestjs-pino";
|
125 |
|
126 | const app = await NestFactory.create(AppModule, { logger: false });
|
127 | app.useLogger(app.get(Logger));
|
128 | ```
|
129 |
|
130 | Output:
|
131 |
|
132 | ```json
|
133 | // Logs by app itself
|
134 | {"level":30,"time":1570470154387,"pid":17383,"hostname":"my-host","context":"RoutesResolver","msg":"AppController {/}: true","v":1}
|
135 | {"level":30,"time":1570470154391,"pid":17383,"hostname":"my-host","context":"RouterExplorer","msg":"Mapped {/, GET} route true","v":1}
|
136 | {"level":30,"time":1570470154405,"pid":17383,"hostname":"my-host","context":"NestApplication","msg":"Nest application successfully started true","v":1}
|
137 |
|
138 | // Logs by injected Logger and PinoLogger in Services/Controllers
|
139 | // Every log has it's request data and unique `req.id` (per process)
|
140 | {"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}
|
141 | {"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}
|
142 |
|
143 | // Automatic logs of every request/response
|
144 | {"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}
|
145 | ```
|
146 |
|
147 | ## Comparison with others
|
148 |
|
149 | There are other Nestjs loggers. The key purposes of this module are:
|
150 |
|
151 | - to be compatible with built-in `LoggerService`
|
152 | - to log with JSON (thanks to `pino` - [super fast logger](https://github.com/pinojs/pino/blob/master/docs/benchmarks.md)) ([why JSON?](https://jahed.dev/2018/07/05/always-log-to-json/))
|
153 | - to log every request/response automatically (thanks to `pino-http`)
|
154 | - to bind request data to the logs automatically from any service on any application layer without passing request context
|
155 | - to have another one alternative `PinoLogger` for experienced `pino` users for more comfortable usage.
|
156 |
|
157 | | Logger | Nest App logger | Logger service | Autobind request data to logs |
|
158 | | ------------------ | :-------------: | :------------: | :---------------------------: |
|
159 | | nest-morgan | - | - | - |
|
160 | | nest-winston | + | + | - |
|
161 | | nestjs-pino-logger | + | + | - |
|
162 | | **nestjs-pino** | + | + | + |
|
163 |
|
164 | ## Install
|
165 |
|
166 | ```sh
|
167 | npm i nestjs-pino
|
168 | ```
|
169 |
|
170 | ## Register module
|
171 |
|
172 | ### Zero configuration
|
173 |
|
174 | Just import `LoggerModule` to your module:
|
175 |
|
176 | ```ts
|
177 | import { LoggerModule } from 'nestjs-pino';
|
178 |
|
179 | @Module({
|
180 | imports: [LoggerModule.forRoot()],
|
181 | ...
|
182 | })
|
183 | class MyModule {}
|
184 | ```
|
185 |
|
186 | ### Configuration params
|
187 |
|
188 | `nestjs-pino` can be configured with params object of next interface:
|
189 |
|
190 | ```ts
|
191 | interface Params {
|
192 | /**
|
193 | * Optional parameters for `pino-http` module
|
194 | * @see https://github.com/pinojs/pino-http#pinohttpopts-stream
|
195 | */
|
196 | pinoHttp?:
|
197 | | pinoHttp.Options
|
198 | | DestinationStream
|
199 | | [pinoHttp.Options, DestinationStream];
|
200 |
|
201 | /**
|
202 | * Optional parameter for routing. It should implement interface of
|
203 | * parameters of NestJS buil-in `MiddlewareConfigProxy['forRoutes']`.
|
204 | * @see https://docs.nestjs.com/middleware#applying-middleware
|
205 | * It can be used for disabling automatic req/res logs (see above).
|
206 | * Keep in mind that it will remove context data from logs that are called
|
207 | * inside not included or excluded routes and controlles.
|
208 | */
|
209 | forRoutes?: Parameters<MiddlewareConfigProxy["forRoutes"]>;
|
210 |
|
211 | /**
|
212 | * Optional parameter for routing. It should implement interface of
|
213 | * parameters of NestJS buil-in `MiddlewareConfigProxy['exclude']`.
|
214 | * @see https://docs.nestjs.com/middleware#applying-middleware
|
215 | * It can be used for disabling automatic req/res logs (see above).
|
216 | * Keep in mind that it will remove context data from logs that are called
|
217 | * inside not included or excluded routes and controlles.
|
218 | */
|
219 | exclude?: Parameters<MiddlewareConfigProxy["exclude"]>;
|
220 |
|
221 | /**
|
222 | * Optional parameter to skip `pino` configuration in case you are using
|
223 | * Fastify adapter, and already configuring it on adapter level.
|
224 | * Pros and cons of this approach are descibed in the last section.
|
225 | */
|
226 | useExisting?: true;
|
227 |
|
228 | /**
|
229 | * Optional parameter to change property name `context` in resulted logs,
|
230 | * so logs will be like:
|
231 | * {"level":30, ... "RENAME_CONTEXT_VALUE_HERE":"AppController" }
|
232 | * Works with both `Logger` and `PinoLogger`
|
233 | */
|
234 | renameContext?: string;
|
235 | }
|
236 | ```
|
237 |
|
238 | ### Synchronous configuration
|
239 |
|
240 | Use `LoggerModule.forRoot` method with argument of [Params interface](#configuration-params):
|
241 |
|
242 | ```ts
|
243 | import { LoggerModule } from 'nestjs-pino';
|
244 |
|
245 | @Module({
|
246 | imports: [
|
247 | LoggerModule.forRoot({
|
248 | pinoHttp: [
|
249 | {
|
250 | name: 'add some name to every JSON line',
|
251 | level: process.env.NODE_ENV !== 'production' ? 'debug' : 'info',
|
252 | // install 'pino-pretty' package in order to use the following option
|
253 | prettyPrint: process.env.NODE_ENV !== 'production',
|
254 | useLevelLabels: true,
|
255 | // and all the others...
|
256 | },
|
257 | someWritableStream
|
258 | ],
|
259 | forRoutes: [MyController],
|
260 | exclude: [{ method: RequestMethod.ALL, path: "check" }]
|
261 | })
|
262 | ],
|
263 | ...
|
264 | })
|
265 | class MyModule {}
|
266 | ```
|
267 |
|
268 | ### Asynchronous configuration
|
269 |
|
270 | With `LoggerModule.forRootAsync` you can, for example, import your `ConfigModule` and inject `ConfigService` to use it in `useFactory` method.
|
271 |
|
272 | `useFactory` should return object with [Params interface](#configuration-params) or undefined
|
273 |
|
274 | Here's an example:
|
275 |
|
276 | ```ts
|
277 | import { LoggerModule } from 'nestjs-pino';
|
278 |
|
279 | @Injectable()
|
280 | class ConfigService {
|
281 | public readonly level = "debug";
|
282 | }
|
283 |
|
284 | @Module({
|
285 | providers: [ConfigService],
|
286 | exports: [ConfigService]
|
287 | })
|
288 | class ConfigModule {}
|
289 |
|
290 | @Module({
|
291 | imports: [
|
292 | LoggerModule.forRootAsync({
|
293 | imports: [ConfigModule],
|
294 | inject: [ConfigService],
|
295 | useFactory: async (config: ConfigService) => {
|
296 | await somePromise();
|
297 | return {
|
298 | pinoHttp: { level: config.level },
|
299 | };
|
300 | }
|
301 | })
|
302 | ],
|
303 | ...
|
304 | })
|
305 | class TestModule {}
|
306 | ```
|
307 |
|
308 | Or you can just pass `ConfigService` to `providers`, if you don't have any `ConfigModule`:
|
309 |
|
310 | ```ts
|
311 | import { LoggerModule } from "nestjs-pino";
|
312 |
|
313 | @Injectable()
|
314 | class ConfigService {
|
315 | public readonly level = "debug";
|
316 | public readonly stream = stream;
|
317 | }
|
318 |
|
319 | @Module({
|
320 | imports: [
|
321 | LoggerModule.forRootAsync({
|
322 | providers: [ConfigService],
|
323 | inject: [ConfigService],
|
324 | useFactory: (config: ConfigService) => {
|
325 | return {
|
326 | pinoHttp: [{ level: config.level }, config.stream]
|
327 | };
|
328 | }
|
329 | })
|
330 | ],
|
331 | controllers: [TestController]
|
332 | })
|
333 | class TestModule {}
|
334 | ```
|
335 |
|
336 | ### Extreme mode
|
337 |
|
338 | > In essence, `extreme` mode enables even faster performance by Pino.
|
339 |
|
340 | Please, read [pino extreme mode docs](https://github.com/pinojs/pino/blob/master/docs/extreme.md#extreme-mode) first. There is a risk of some logs being lost, but you can [minimize it](https://github.com/pinojs/pino/blob/master/docs/extreme.md#log-loss-prevention).
|
341 |
|
342 | If you know what you're doing, you can enable it like so:
|
343 |
|
344 | ```ts
|
345 | import * as pino from 'pino';
|
346 | import { LoggerModule } from 'nestjs-pino';
|
347 |
|
348 | const dest = pino.extreme();
|
349 | const logger = pino(dest);
|
350 |
|
351 | @Module({
|
352 | imports: [LoggerModule.forRoot({ pinoHttp: { logger } })],
|
353 | ...
|
354 | })
|
355 | class MyModule {}
|
356 | ```
|
357 |
|
358 | ## Usage as Logger service
|
359 |
|
360 | As it said before, there are 2 logger classes:
|
361 |
|
362 | - `Logger` - implements standard NestJS `LoggerService` interface. So if you are familiar with [built-in NestJS logger](https://docs.nestjs.com/techniques/logger), you are good to go.
|
363 | - `PinoLogger` - implements standard `pino` _logging_ methods: [trace](https://github.com/pinojs/pino/blob/master/docs/api.md#loggertracemergingobject-message-interpolationvalues), [debug](https://github.com/pinojs/pino/blob/master/docs/api.md#loggerdebugmergingobject-message-interpolationvalues), [info](https://github.com/pinojs/pino/blob/master/docs/api.md#loggerinfomergingobject-message-interpolationvalues), [warn](https://github.com/pinojs/pino/blob/master/docs/api.md#loggerwarnmergingobject-message-interpolationvalues), [error](https://github.com/pinojs/pino/blob/master/docs/api.md#loggererrormergingobject-message-interpolationvalues), [fatal](https://github.com/pinojs/pino/blob/master/docs/api.md#loggerfatalmergingobject-message-interpolationvalues). So if you are familiar with it, you are also good to go.
|
364 |
|
365 | ### Logger
|
366 |
|
367 | ```ts
|
368 | // my.service.ts
|
369 | import { Logger } from "nestjs-pino";
|
370 |
|
371 | @Injectable()
|
372 | export class MyService {
|
373 | constructor(private readonly logger: Logger) {}
|
374 |
|
375 | getWorld(...params: any[]) {
|
376 | this.logger.log("getWorld(%o)", MyService.name, params);
|
377 | return "World!";
|
378 | }
|
379 | }
|
380 | ```
|
381 |
|
382 | ### PinoLogger
|
383 |
|
384 | See [pino logging method parameters](https://github.com/pinojs/pino/blob/master/docs/api.md#logging-method-parameters) for more logging examples.
|
385 |
|
386 | ```ts
|
387 | // my.service.ts
|
388 | import { PinoLogger, InjectPinoLogger } from "nestjs-pino";
|
389 |
|
390 | @Injectable()
|
391 | export class MyService {
|
392 | // regular injecting
|
393 | constructor(private readonly logger: PinoLogger) {}
|
394 |
|
395 | // regular injecting and set context
|
396 | constructor(private readonly logger: PinoLogger) {
|
397 | logger.setContext(MyService.name);
|
398 | }
|
399 |
|
400 | // inject and set context via `InjectPinoLogger`
|
401 | constructor(
|
402 | @InjectPinoLogger(MyService.name) private readonly logger: PinoLogger
|
403 | ) {}
|
404 |
|
405 | getWorld(...params: any[]) {
|
406 | this.logger.info("getWorld(%o)", params);
|
407 | return "World!";
|
408 | }
|
409 | }
|
410 | ```
|
411 |
|
412 | #### Testing a class that uses @InjectPinoLogger
|
413 |
|
414 | This package exposes a getLoggerToken() function that returns a prepared injection token based on the provided context.
|
415 | Using this token, you can easily provide a mock implementation of the logger using any of the standard custom provider techniques, including useClass, useValue, and useFactory.
|
416 |
|
417 | ```ts
|
418 | const module: TestingModule = await Test.createTestingModule({
|
419 | providers: [
|
420 | MyService,
|
421 | {
|
422 | provide: getLoggerToken(MyService.name),
|
423 | useValue: mockLogger,
|
424 | },
|
425 | ],
|
426 | }).compile();
|
427 | ```
|
428 |
|
429 | ## Usage as NestJS app logger
|
430 |
|
431 | According to [official docs](https://docs.nestjs.com/techniques/logger#dependency-injection), loggers with Dependency injection should be set via following construction:
|
432 |
|
433 | ```ts
|
434 | import { Logger } from "nestjs-pino";
|
435 |
|
436 | const app = await NestFactory.create(MyModule, { logger: false });
|
437 | app.useLogger(app.get(Logger));
|
438 | ```
|
439 | ## Extend the Logger class
|
440 |
|
441 | You can extend the Logger class to add your own business logic.
|
442 |
|
443 | ```ts
|
444 | // logger.service.ts
|
445 | import { Logger, PinoLogger, Params, PARAMS_PROVIDER_TOKEN } from "nestjs-pino";
|
446 |
|
447 | @Injectable()
|
448 | class LoggerService extends Logger() {
|
449 | // regular injecting
|
450 | constructor(
|
451 | logger: PinoLogger,
|
452 | @Inject(PARAMS_PROVIDER_TOKEN) params: Params
|
453 | ) {
|
454 | ...
|
455 | }
|
456 |
|
457 | // extended method
|
458 | myMethod(): any {}
|
459 | }
|
460 |
|
461 | import { PinoLogger, Params, PARAMS_PROVIDER_TOKEN } from "nestjs-pino";
|
462 |
|
463 | @Injectable()
|
464 | class LoggerService extends PinoLogger() {
|
465 | // regular injecting
|
466 | constructor(
|
467 | @Inject(PARAMS_PROVIDER_TOKEN) params: Params
|
468 | ) {
|
469 | ...
|
470 | }
|
471 |
|
472 | // extended method
|
473 | myMethod(): any {}
|
474 | }
|
475 |
|
476 |
|
477 | // logger.module.ts
|
478 | @Module({
|
479 | providers: [LoggerService],
|
480 | exports: [LoggerService],
|
481 | imports: [LoggerModule.forRoot()],
|
482 | })
|
483 | class LoggerModule {}
|
484 | ```
|
485 |
|
486 | ## Migrating
|
487 |
|
488 | ### v1
|
489 |
|
490 | - All parameters of v.0 are moved to `pinoHttp` property (except `useExisting`).
|
491 | - `useExisting` now accept only `true`, because `false` does not make any sense
|
492 |
|
493 | ## FAQ
|
494 |
|
495 | **Q**: _How does it work?_
|
496 |
|
497 | **A**: It uses [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` and `PinoLogger` can get it while calling own methods. So your logs can be grouped by `req.id`. If you run several instances, unique key is pair: `pid` + `req.id`.
|
498 |
|
499 | ---
|
500 |
|
501 | **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)?_
|
502 |
|
503 | **A**: [REQUEST scope](https://docs.nestjs.com/fundamentals/injection-scopes#per-request-injection) can have [perfomance issues](https://docs.nestjs.com/fundamentals/injection-scopes#performance). TL;DR: it will have to create an instance of the class (that injects `Logger`) on each request, and that will slow down your responce times.
|
504 |
|
505 | ---
|
506 |
|
507 | **Q**: _I'm using old nodejs version, will it work for me?_
|
508 |
|
509 | **A**: Please read [this](https://github.com/jeff-lewis/cls-hooked#continuation-local-storage--hooked-).
|
510 |
|
511 | ---
|
512 |
|
513 | **Q**: _What about pino built-in methods/levels?_
|
514 |
|
515 | **A**: Pino built-in methods are not compatible with NestJS built-in `LoggerService` methods. So for now there is option which logger to use, here is methods mapping:
|
516 |
|
517 | | `pino` method | `PinoLogger` method | `Logger` method |
|
518 | | ------------- | ------------------- | --------------- |
|
519 | | trace | trace | **verbose** |
|
520 | | debug | debug | debug |
|
521 | | info | info | **log** |
|
522 | | warn | warn | warn |
|
523 | | error | error | error |
|
524 | | fatal | fatal | - |
|
525 |
|
526 | ---
|
527 |
|
528 | **Q**: _Fastify already includes pino, and I want to configure it on `Adapter` level, and use this config for logger_
|
529 |
|
530 | **A**: You can do it by providing `useExisting: true`. But there is one caveat:
|
531 |
|
532 | Fastify creates logger with your config per every request. And this logger is used by `Logger`/`PinoLogger` services inside that context underhood.
|
533 |
|
534 | But Nest Application has another contexts of execution, for example [lifecycle events](https://docs.nestjs.com/fundamentals/lifecycle-events), where you still may want to use logger. For that `Logger`/`PinoLogger` services use separate `pino` instance with config, that provided via `forRoot`/`forRootAsync` methods.
|
535 |
|
536 | **So, when you want to configure pino via `FastifyAdapter`, there is no way to get back this config from it and pass to that _out of context_ logger.**
|
537 |
|
538 | And if you not pass config via `forRoot`/`forRootAsync` _out of context_ logger will be instantiated with default params. So if you want to configure it anyway with the same options, then you have to provide the same config. And then If you are already provide that then you don't have to duplicate your code and provide pino config via fastify.
|
539 |
|
540 | So these property (`useExisting: true`) is not recommended and useful only for cases when:
|
541 |
|
542 | - this logger is not using for lifecycle events and application level logging in Nest apps based on fastify
|
543 | - pino using with default params in Nest apps based on fastify
|
544 |
|
545 | All the other cases are lead to either code duplication or unexpected behaviour.
|
546 |
|
547 | <h2 align="center">Do you use this library?<br/>Don't be shy to give it a star! ★</h2>
|
548 |
|
549 | Also if you are into NestJS ecosystem you may be interested in one of my other libs:
|
550 |
|
551 | [nestjs-pino](https://github.com/iamolegga/nestjs-pino)
|
552 |
|
553 | [![GitHub stars](https://img.shields.io/github/stars/iamolegga/nestjs-pino?style=flat-square)](https://github.com/iamolegga/nestjs-pino)
|
554 | [![npm](https://img.shields.io/npm/dm/nestjs-pino?style=flat-square)](https://www.npmjs.com/package/nestjs-pino)
|
555 |
|
556 | Platform agnostic logger for NestJS based on [pino](http://getpino.io/) with request context in every log
|
557 |
|
558 | ---
|
559 |
|
560 | [nestjs-session](https://github.com/iamolegga/nestjs-session)
|
561 |
|
562 | [![GitHub stars](https://img.shields.io/github/stars/iamolegga/nestjs-session?style=flat-square)](https://github.com/iamolegga/nestjs-session)
|
563 | [![npm](https://img.shields.io/npm/dm/nestjs-session?style=flat-square)](https://www.npmjs.com/package/nestjs-session)
|
564 |
|
565 | Idiomatic session module for NestJS. Built on top of [express-session](https://www.npmjs.com/package/express-session)
|
566 |
|
567 | ---
|
568 |
|
569 | [nestjs-cookie-session](https://github.com/iamolegga/nestjs-cookie-session)
|
570 |
|
571 | [![GitHub stars](https://img.shields.io/github/stars/iamolegga/nestjs-cookie-session?style=flat-square)](https://github.com/iamolegga/nestjs-cookie-session)
|
572 | [![npm](https://img.shields.io/npm/dm/nestjs-cookie-session?style=flat-square)](https://www.npmjs.com/package/nestjs-cookie-session)
|
573 |
|
574 | Idiomatic cookie session module for NestJS. Built on top of [cookie-session](https://www.npmjs.com/package/cookie-session)
|
575 |
|
576 | ---
|
577 |
|
578 | [nestjs-roles](https://github.com/iamolegga/nestjs-roles)
|
579 |
|
580 | [![GitHub stars](https://img.shields.io/github/stars/iamolegga/nestjs-roles?style=flat-square)](https://github.com/iamolegga/nestjs-roles)
|
581 | [![npm](https://img.shields.io/npm/dm/nestjs-roles?style=flat-square)](https://www.npmjs.com/package/nestjs-roles)
|
582 |
|
583 | Type safe roles guard and decorator made easy
|
584 |
|
585 | ---
|
586 |
|
587 | [nest-ratelimiter](https://github.com/iamolegga/nestjs-ratelimiter)
|
588 |
|
589 | [![GitHub stars](https://img.shields.io/github/stars/iamolegga/nestjs-ratelimiter?style=flat-square)](https://github.com/iamolegga/nestjs-ratelimiter)
|
590 | [![npm](https://img.shields.io/npm/dm/nest-ratelimiter?style=flat-square)](https://www.npmjs.com/package/nest-ratelimiter)
|
591 |
|
592 | Distributed consistent flexible NestJS rate limiter based on Redis
|
593 |
|
594 | ---
|
595 |
|
596 | [create-nestjs-middleware-module](https://github.com/iamolegga/create-nestjs-middleware-module)
|
597 |
|
598 | [![GitHub stars](https://img.shields.io/github/stars/iamolegga/create-nestjs-middleware-module?style=flat-square)](https://github.com/iamolegga/create-nestjs-middleware-module)
|
599 | [![npm](https://img.shields.io/npm/dm/create-nestjs-middleware-module?style=flat-square)](https://www.npmjs.com/package/create-nestjs-middleware-module)
|
600 |
|
601 | Create simple idiomatic NestJS module based on Express/Fastify middleware in just a few lines of code with routing out of the box
|
602 |
|
603 | ---
|
604 |
|
605 | [nestjs-configure-after](https://github.com/iamolegga/nestjs-configure-after)
|
606 |
|
607 | [![GitHub stars](https://img.shields.io/github/stars/iamolegga/nestjs-configure-after?style=flat-square)](https://github.com/iamolegga/nestjs-configure-after)
|
608 | [![npm](https://img.shields.io/npm/dm/nestjs-configure-after?style=flat-square)](https://www.npmjs.com/package/nestjs-configure-after)
|
609 |
|
610 | Declarative configuration of NestJS middleware order
|