Giter Club home page Giter Club logo

nest-winston's Introduction

๐Ÿ‘‹ Ciao, I'm Marco

Gmail LinkedIn Stack Overflow Facebook Instagram

I'm a web developer from Italy ๐Ÿ• with over 10 years of experience. Programming is my passion โค๏ธ and I couldn't imagine doing anything else in my life!

GitHub stats

๐Ÿ“… Hobbies

  • โœˆ๏ธ Travel and explore the world
  • ๐Ÿป Enjoy free time with friends
  • ๐ŸŽฅ Watch TV shows and movies
  • ๐Ÿ•น๏ธ Play my favorite videogame Dead by Daylight
  • โšฝ Play tennis and five-a-side

โšก Recent activity

  1. ๐Ÿ—ฃ Commented on #646 in antares-sql/antares
  2. ๐Ÿ—ฃ Commented on #54641 in symfony/symfony
  3. ๐Ÿ”’ Closed issue #54641 in symfony/symfony
  4. ๐Ÿ—ฃ Commented on #1150 in symfony/ux
  5. ๐Ÿ—ฃ Commented on #1150 in symfony/ux

nest-winston's People

Contributors

adrianmxb avatar angeloanan avatar ankit-noba avatar cchanche avatar chrisipk avatar danijelpredojevic avatar devvspaces avatar faithfulojebiyi avatar github-actions[bot] avatar gremo avatar guillaumedeconinck avatar ibrcko avatar j3bb9z avatar jbpin avatar jdg- avatar kadrian avatar kierans avatar kiriancaumes avatar lwhiteley avatar mizozobu avatar nemanja-mudrinic avatar piranit avatar renovate-bot avatar renovate[bot] avatar sezanzeb avatar tmkx avatar trejgun avatar viceice avatar vorotech avatar yardz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

nest-winston's Issues

Best approach for unit testing modules

Hi,

I have recently started using this package. As I run my unit tests all tests failed that are injecting the logger.

Nest can't resolve dependencies of the [SERVICE] (?, ANOTHER_SERVICE). Please make sure that the argument NestWinston at index [0] is available in the RootTestModule context.

I'm using the Quick start example for implementing nest-winston.
For testing I'm using the provided way by the nestjs docs.

Could anyone provide an example how to mock this package for testing?

Override formating per module?

Hello,

Is there a way to override format options per module?

For instance, my app.module.ts looks like:

 imports: [
    WinstonModule.forRoot({
      transports: [...],
      format: combine(
        label({ label: 'CONTROLLER_NAME' }),
        timestamp(),
        myFormat,
      ),
    }),

And I'm calling it as such:

@Controller('SomeController')
export class SomeController {
  constructor(
    @Inject('winston')
    private readonly logger: Logger,
  ) {}

With the nest logger I would be able to add something like setContext. Is there any way to achieve this?

Thanks

getTimestamp exception thrown when creating Application logger

Creating an application level Logger (via the bootstrap) now appears to cause the following exception:

[ExceptionHandler] instance.getTimestamp is not a function - {"stack":["TypeError: instance.getTimestamp is not a function\n

I created a vanilla application with the following main.ts file:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { utilities as nestWinstonModuleUtilities, WINSTON_MODULE_NEST_PROVIDER, WinstonModule } from 'nest-winston';
import * as winston from 'winston';

const winstonTransports: winston.transport[] = [
  new winston.transports.Console({
    format: winston.format.combine(winston.format.timestamp(), nestWinstonModuleUtilities.format.nestLike()),
  }),
];

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: WinstonModule.createLogger({
      transports: winstonTransports,
    })})
  await app.listen(3000);
}
bootstrap();

Then adding a simple log to the app.controller.ts file

import { Controller, Get, Logger } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {
    Logger.log('Try it then')
  }

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

This should cause the issue as described. If you need any more information just let me know.

Thanks

Nest can't resolve dependencies 'Logger' provider

Many thanks for module, I have added to my personal project, following readme, everything is fine for me until apply NestWinston as default (also for bootstrapping) I cannot start project.

Please help me to point out my mistake, may I misunderstanding for

This works because Nest Logger wraps our winston logger (the same instance returned by the createLogger method) and will forward all calls to it.

Details of log is showing like this:

Nest can't resolve dependencies of the UserService (?, HashService, UserRepository). Please make sure that the argument Logger at index [0] is available in the Us
erModule context.

Potential solutions:
- If Logger is a provider, is it part of the current UserModule?
- If Logger is exported from a separate @Module, is that module imported within UserModule?

Here is my main.ts

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: WinstonModule.createLogger({
      format: winston.format.json(),
      defaultMeta: { service: 'bootstrap' },
      transports: [
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp(),
            utilities.format.nestLike(),
          ),
        }),
        new winston.transports.File({
          filename: __dirname + '/log/error.log',
          level: 'error',
        }), // - Write all logs with level `error` and below to `error.log`
        new winston.transports.File({
          filename: __dirname + '/log/combined.log',
        }),
        // - Write all logs with level `info` and below to `combined.log`
      ],
    }),
    cors: true,
  });

  const configService = app.get(ConfigService);

  await app.listen(configService.get<number>('port'));
}
bootstrap();

My app.module.ts file

@Module({
  providers: [Logger],
})
export class AppModule {}

My user.service.ts file:

@Injectable()
export class UserService {
  constructor(
    @Inject(Logger)
    private readonly logger: LoggerService,
    private readonly hashService: HashService,
    private readonly userRepo: UserRepository,
  ) {}
}

Using the same instance for both bootstrap and whole project logging.

Maybe I didn't understand the docs fully, but it seems to me as thought we use two different logger instances for across the whole project logging, e.g.

import { Module } from '@nestjs/common';
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';

@Module({
  imports: [
    WinstonModule.forRoot({
      // options
    }),
  ],
})
export class AppModule {}

and for logging during bootstrap, e.g.

import { WinstonModule } from 'nest-winston';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: WinstonModule.createLogger({
      // options (same as WinstonModule.forRoot() options)
    })
  });
}
bootstrap();

For across the project logging we use whatever WinstonModule.forRoot returns, and for logging during the bootstrap we use whatever WinstonModule.createLogger returns. So it's like using two different loggers, or at least two different instances.

If I, let's say, want to move the logic associated with creating a logger to another file, so then I could import it. My logger file would look like this.

export const bootstrapLogger = WinstonModule.createLogger(options);
export const projectLogger = WinstonModule.forRoot(options); 

Is there any way to "combine" bootstrapLogger and projectLogger into just one instance?

Initializing logger with setContext inside constructor

@gremo Is there an option to initialize the logger inside the class constructor with the context, so that everytime the context need not be specified in a class.

If we could do something like

_logger: any;
constructor(@Inject(WINSTON_MODULE_NEST_PROVIDER) private logger: LoggerService) {
    this._logger = logger.setContext('ClassName');
}

async test() {
    this._logger.log('Hello World');
}

Using as Main logger: fails for unit tests: RootTestModule

I followed the directions to use this as the main logger, and I am importing the Logger and LoggerService per the readme in a class that a unit test utilizes. Just running the app, things work fine, however with I npm run test I get this

   Nest can't resolve dependencies of the ApiTokenService (ConfigService, HttpService, ?). Please make sure that the argument Logger at index [2] is available in the RootTestModule context.

    Potential solutions:
    - If Logger is a provider, is it part of the current RootTestModule?
    - If Logger is exported from a separate @Module, is that module imported within RootTestModule?
      @Module({
        imports: [ /* the Module containing Logger */ ]
      })

Unable to inject Logger in Repository and logrotate function

Hello,
thanks for your great work here.
I do have a question:

I was unable after following your tutorial using nest-winston as nestjs logger to use it inside a repository class:

Here some code:

import { ConflictException, Inject, InternalServerErrorException, LoggerService } from "@nestjs/common";
import { WINSTON_MODULE_NEST_PROVIDER } from "nest-winston";
import { EntityRepository, Repository } from "typeorm";
import { AuthCredentialsDto } from "./dto/auth-credentials.dto";
import { User } from "./user.entity";

@EntityRepository(User)
export class UserRepository extends Repository<User> {
    constructor(@Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: LoggerService) {        
        super()
    }

    async signUp(authCredentialsDto: AuthCredentialsDto): Promise<void> {

        const { username, password, primaryEmailAddress } = authCredentialsDto

        const user = new User();
        user.username = username;
        user.password = password;
        user.primaryEmailAddress = primaryEmailAddress;
        
        try {
            await user.save()
        } catch(error) {
            // Catches duplicated Entry Error
            if (error.code === 'ER_DUP_ENTRY') {
                this.logger.error(`User with name ${user.username} tried to be registered a second time.`)
                throw new ConflictException('Username already exists')
            } else {
                throw new InternalServerErrorException();
            }
        }
    }
}

When the user is already in the database the line this.logger ... is called, but ending up in this error message:
TypeError: this.logger.error is not a function . This message is also logged to the error.log. But the expected value should be User with name ${user.username} tried to be registered a second time.

I straight followed your documentation by creating the logger in this way:

app.module.ts

@Module({
  imports: [
  TypeOrmModule.forRoot(configService.getTypeOrmConfig()),
  WinstonModule.forRoot({
    transports: [
      new winston.transports.Console({
        format: winston.format.combine(
          winston.format.timestamp(),
          nestWinstonModuleUtilities.format.nestLike(),
        )
      },
    ),
    new winston.transports.File({
      format: winston.format.json(),
      filename: errorLogPath, level: 'error',
      zippedArchive: true,
      tailable: true,      
    }),
    new winston.transports.File({
      format: winston.format.json(),
      filename: infoLogPath, level: 'info',
      zippedArchive: true,
      tailable: true,      
    })
    ],

  }),
  AuthModule
],
  controllers: [],
  providers: []
})
export class AppModule {}

Here my second question arises: How can I use logrotate? It wants a function, can you provide me an example? I want to daily rotate my logs.

Thanks in advance!!

Best regards
Meywether

Winston does not appear to inject properly

Hi, I'm trying to Inject Winston into a service class. I've added Winston to the main Application module:

import { Module } from '@nestjs/common';
...
import { WinstonModule } from 'nest-winston';
import * as winston from "winston";

@Module({
    imports: [
        TypeOrmModule.forRoot(),
        WinstonModule.forRoot({
            level: 'info',
            format: winston.format.json(),
            transports: [
                //
                // - Write to all logs with level `info` and below to `combined.log`
                // - Write all logs error (and below) to `error.log`.
                //
                new winston.transports.File({ filename: 'error.log', level: 'error' }),
                new winston.transports.File({ filename: 'combined.log' })
            ]
        }),
        AuthModule,
        ...
    ]
})

and in its constructor I've built it like this:

...
import {Logger} from "winston";

@Injectable()
export class FileService {
    constructor(@InjectRepository(ImageFile)
                @Inject('winston') logger: Logger,
                private readonly imageFileRepository: Repository<ImageFile>,
                config: ConfigService,
    ) { ... }

However, upon startup, NestJS presents:

[Nest] 12572   - 11/24/2018, 4:33:15 PM   [ExceptionHandler] Nest can't resolve dependencies of the FileService (ImageFileRepository, ?, ConfigService). Please make sure that the argument at index [1] is available in the current context. +16ms
Error: Nest can't resolve dependencies of the FileService (ImageFileRepository, ?, ConfigService). Please make sure that the argument at index [1] is available in the current context.

So, it looks like the Winston injection isn't there. My understanding is that because I added Winston .forRoot() it should be ready to inject anywhere... Maybe the token is wrong?

Also, it appears that Winston will not operate without a specified config, I think? Maybe it should have a sensible default?

Question: How i can read from mongodb

Hello i use nest winston combined with winston-mongodb for transporter and for now successfully I save my data into the DB, my questions is can i use nest winston to read or i need to get it by my self?

[FeatureRequest] Child loggers creation with use of forFeature

Hello,

I wanted to be able to use "filename/moduleName" in my logging. To do this it would be nice to use child logger functionality of winston. Currently I use it as follows:
export` class Features { constructor( @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger ) { this.logger = logger.child({ module: 'Features'}); } }

This way all logs in this "provider" will be marked with moduleName without need to pass it in each query. Much nicer way would be to use forFeature method on Dynamic Module which would create a child instance for each module.

Export nest like log format

I actually got this idea from https://github.com/pay-k/nestjs-winston (as an aside I don't know why this module/repo exists as it's not a fork of this repo and according the npm this module was published first, so it looks like the author just took a dump of this repo)

It's a Winston formatter that mimics the output format of the default Nest Logger.

const nestLikeFormat = winston.format.printf(({ context, level, timestamp, message }) => {
  return `${level}: ${new Date(timestamp).toLocaleString()}\t [${colors.yellow(context)}] ${message}`;
});

const nestFormat = winston.format.combine(
  winston.format.timestamp(),
  winston.format.colorize({ all: true }),
  nestLikeFormat
);

WinstonOptionFactory

please add WinstonOptionFactory so users can create WinstonConfigService to pass in useClass property for forRootAsync

Can not record trace message when use as the main Nest logger

As the document states, we can replace the system logger with Winston logger like this:

import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));
}
bootstrap();

However, when Nest catches an exception, the trace message is missing in log file. I think it's because Winston logger instance doesn't conform Nest LoggerService.

As a workaround, we should use logger instance return from WinstonModule.createLogger.

error stack trace is not printed

Hi there! I'm not sure if this is feature request of bug repport.

what I do is configure winson in bootstrap function

  app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));

and app module

    WinstonModule.forRootAsync({
      useFactory: () => ({
        transports: [
          new transports.Console({
            format: format.combine(
              format.timestamp(),
              utilities.format.nestLike(),
            ),
          }),
        ],
      }),
    }),

and then use

  constructor(@Inject("winston") private readonly logger: Logger) {}

  public method(): void {
    const error = new Error("On no!");
    this.logger.error(error.message, error.stack, this.constructor.name);
  }

which print just

[NestWinston] Error     11/30/2019, 9:47:02 PM On no! - {}

according to docs it should print [context] and trace property in the meta data

ok lets do this ather way around

  constructor(@Inject("winston") private readonly logger: Logger) {}

  public method(): void {
    const error = new Error("On no!");
    this.logger.error(error);
  }

prints

[NestWinston] Error     11/30/2019, 9:51:27 PM undefined - {}

which is even worth

I was managed to make it work somehow

    WinstonModule.forRootAsync({
      useFactory: () => ({
        format: format.combine(
          format.errors({stack: true}), 
          format.timestamp()
        ),
        transports: [
          new transports.Console({
            format: format.printf(({level, context, timestamp, message, stack, trace}) => {
              let color, text;
              if (level === "error") {
                color = red;
                const lines = (stack || trace).split("\n");
                lines[0] = color(lines[0]);
                text = lines.join("\n");
              } else {
                color = green;
                text = color(message);
              }
              return `${color(`[Nest] ${process.pid}   -`)} ${new Date(timestamp).toLocaleString()}   ${context ? yellow("[" + context + "]") : ""} ${text}`;
            }),
          }),
        ],
      }),
    }),

now it prints Error object

[Nest] 20905   - 11/30/2019, 9:53:37 PM    Error: On no!
    at AuthController.biometric (~/path/to/file.ts:59:19)
    at ~/node_modules/@nestjs/core/router/router-execution-context.js:37:29
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at ~/node_modules/@nestjs/core/router/router-execution-context.js:45:28
    at ~/node_modules/@nestjs/core/router/router-proxy.js:8:17

but i still want to pass context and signature with 3 params just does not work. Please gimme some directions

setContext method implementation and injection scope

Hello,

I have noticed that you haven't implemented "setContext()" method in a similar fashion as it is implemented in @nestjs/logger-service.

Since this is a cool feature, what do you think about adding it to this library?

The implementation itself would look something like this:

class WinstonLogger implements LoggerService {
  private context?: string;

  constructor(private readonly logger: Logger) {
  }

  public log(message: any, context?: string) {
    return this.logger.info(message, {context: context || this.context});
  }

  public error(message: any, trace?: string, context?: string): any {
    return this.logger.error(message, {trace, context: context || this.context});
  }

  public warn(message: any, context?: string): any {
    return this.logger.warn(message, {context: context || this.context});
  }

  public debug(message: any, context?: string): any {
    return this.logger.debug(message, {context: context || this.context});
  }

  public verbose(message: any, context?: string): any {
    return this.logger.verbose(message, {context: context || this.context});
  }

  public setContext(context: string) {
    this.context = context;
  }
}

The use case for this feature would be to set logging context per incoming request, so we don't have to pass "context" as a parameter every time we are logging something.

Furthermore, it would be nice to have an option to set an injection scope for "WinstonLogger" instance i.e. per request.
Since "WinstonLogger" isn't exported from the module, the solution would be either to actually export it, or to add an option "injectionScope" to "WinstonModuleOptions".

What do you think about this?
Thanks.

logs are not logged

After setting as default logger with app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));, logs are not logged
I am doing logging as:
constructor(@Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: LoggerService) { }

and

this.logger.log('some log')

Still unable to inject config

I am using the new imports declaration but still unable to inject Config (or environment) variables, they are undefined.

Below is my main module:

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    WinstonModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        level: 'info',
        format: winston.format.combine(
          winston.format.timestamp(),
          winston.format.splat(),
          winston.format.json()
        ),
        transports: [
          new winston.transports.Console({
            level: configService.get<string>('LOG_LEVEL'),
          }),
        ],
    }),
    inject: [ConfigService],
  }),
  FooModule
  ],
  controllers: [FooController],
  providers: [FooService],
})
export class AppModule {}

The WinstonModule declaration above is identical to my SequelizeModule below (which works):

    SequelizeModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
      dialect: 'mssql',
      dialectOptions: {
        options: {
          encrypt: true
        }
      },
      host: configService.get<string>('DATABASE_HOST'),
      port: configService.get<number>('DATABASE_PORT'),
      username: configService.get<string>('DATABASE_USER'),
      password: configService.get<string>('DATABASE_PASSWORD'),
      database: 'CatFacts',
      models: [Fact, Animal, FactAnimal],
    }),
    inject: [ConfigService]
  }),

[Release Request]

Iโ€™ve been waiting for WinstonLogger to be exported. Looks like itโ€™s been done already. Can we get a new version released?

Issue with date formatting?

Hello,

I'm not sure if it's a bug or not, but if I want to format my date thanks to "winston.format.timestamp", an error "Invalid Date" is displayed in the console.

[test] Info     Invalid Date [RoutesResolver] TestController {/api/tests}: - {}
[test] Info     Invalid Date [RouterExplorer] Mapped {/api/tests, POST} route - {}
[test] Info     Invalid Date [RouterExplorer] Mapped {/api/tests, DELETE} route - {}
[test] Info     Invalid Date [NestApplication] Nest application successfully started - {}

Code example:

async function bootstrap() {
    const app = await NestFactory.create(AppModule, {
        logger: WinstonModule.createLogger({
            transports: [
                new winston.transports.Console({
                    format: winston.format.combine(
                        winston.format.timestamp({ format: "DD:MM:YYYY HH:mm:ss" }), //Date format
                        nestWinstonModuleUtilities.format.nestLike("Test"),
                    ),
                })
            ]
        })
    });
    await app.listen(5000)
}
bootstrap()

So my question is : why the function "nestLikeConsoleFormat" at line 21, does not look like this, to allow custom format to displayed?

('undefined' !== typeof timestamp ? `${timestamp} ` : `${new Date().toLocaleString()} `) +

Thank you very much for your answer!

how to use inside a filter

I want to use this inside a filter where i am catching all 500 exceptions. can anyone provide me with some snippet to get going

How would I use this module with Google's logging-winston middleware?

Thanks for the really cool module. I added it into our Nest project using the bootstrap method and everything worked out of the box! ๐Ÿ‘

However, we use Google App Engine in production, and we would like our log output to be grouped by request. Normally, we use @google-cloud/logging-winston to create an express middleware which automagically picks up GAE correlationIds etc. This is explained in their documentation. Basically, you call the provided makeMiddleware function, passing it your initialised logger. The logger is then attached to your request object.

Unfortunately, WinstonModule.createLogger returns a LoggerService, which doesn't expose an interface compatible with the standard Winston logger.

How can I use your module and take advantage of the request-bundling offered by the logging-winston middleware?

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.

Question: How to use it in TypeOrmModule?

Hi, my question is how to use it in TypeOrmModule ?
Currently, db query didn't saved in log.


const config: TypeOrmModuleOptions = {
  type: 'mysql',
  host: db.host,
  port: db.port,
  password: db.password,
  username: db.user,
  database: db.database,
  entities: [__dirname + '/**/*.entity{.ts,.js}'],
  logging: true,
  logger: // ?? <---- what should I inject here ?
};

@Module({
  imports: [
    TypeOrmModule.forRoot(config),
    UserModule,
    RoomModule,
    RoomHistoryModule,
    WinstonModule.forRoot({
      transports: [
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp({
              format: 'YYYY-MM-DD HH:mm:ss',
            }),
          ),
        }),
        dailyRotateFile,
        // other transports...
      ],
    }),
  ],
  controllers: [],
  providers: [
    {
      provide: APP_GUARD,
      useClass: AuthGuard,
    },
  ],
})
export class AppModule {}

Adding transports based on environment

Since the config options are placed inside the module import in the AppModule, I can't get transports to be added based on which environment the app is running in. Normally using winston, the logger is instantiated in a variable which can be accessed later to add a transport like this:

if (process.env.NODE_ENV !== 'production') {
  logger.add(new transports.Console({
    format: format.combine(
      format.colorize(),
      format.simple()
    )
  }));
}

Where should the code above (or similar) be used to add the transport?

structured logging (info objects)

First things first, thanks for putting together this NestJS module.

We want to be able to use structured logging in our, not only json formatted output but also the ability to include application specific key-value pairs. This is something that Winston already supports, known as info objects.

I could not find a way of achieving this in the current implementation of nest-winston. The limitation stems from the definition of nestjs's LoggerService interface.

export interface LoggerService {
    log(message: any, context?: string): any;
    error(message: any, trace?: string, context?: string): any;
    warn(message: any, context?: string): any;
    debug?(message: any, context?: string): any;
    verbose?(message: any, context?: string): any;
}

I would like to know if there is appetite for a contribution to extend the interface to allow for structured logging. The interface could look like:

export interface StructuredLoggerService extends LoggerService {
  log(message: any, meta?: any): void;
  error(message: any, trace?: string, meta?: any): any;
  warn(message: any, meta?: any): any;
  debug?(message: any, meta?: any): any;
  verbose?(message: any, meta?: any): any;
}

the signature of the methods is compatible with the base interface. The implementation, WinstonLogger, could apply some logic to determine if the argument is a context string or a meta object and based on that delegate the logging to the underlaying winston logger instance.

Something on the lines of:

  public log(message: any, meta?: any) {
    return this.logger.info(message, packFields(this.context, undefined, meta));
  }

function packFields(context?: string, trace?: string, meta?: any): any {
  let fields: any = {}
  if (typeof meta === 'string') {
    fields.context = meta;
  } else {
    fields.context = meta?.context || context
    fields = {...fields, ...meta, trace}
  }
  return fields
}

The app would use the logger like this:

this.logger('this is a simple message`)
this.logger('this is a message that sets the context', 'context foo')
this.logger('this message attaches some key/value pairs', {foo: 'bar'})

If you think this is useful and the right approach I can submit a PR.

Thanks!

can i get a full example of how to implement and log?

I am using forRoot method and injecting using @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger. however when i do this.logger.log('some message') i get an error

TypeError: Cannot create property 'Symbol(level)'

using transaport.console and transport.file

Export WinstonLogger from npm module

Firstly great job on this (npm) module!! It's saved me some hassle so thanks ๐Ÿ‘

However using the WinstonLogger as a @Module means that you have to wait for the logger to be instantiated before it will kick in which means you get the default Nest Logger's output for a bit eg:

[Nest] 13486   - 09/28/2019, 5:16:50 PM   [InstanceLoader] TypeOrmCoreModule dependencies initialized +1314ms
info: 9/28/2019, 5:16:50 PM	 [RoutesResolver] AppController {/}:

However in the Nestjs Logger Docs it suggests passing the logger to app at app creation time eg:

const app = await NestFactory.create(AppModule, {
  logger: createWinstonLogger({
    level: "info"
  })
});

function createWinstonLogger(opts: LoggerOptions): LoggerService {
  const logger: winston.Logger = winston.createLogger(opts);

  return new WinstonLogger(logger);
}

This leads to uniform log output ie:

info: 9/28/2019, 5:24:14 PM	 [InstanceLoader] TypeOrmCoreModule dependencies initialized
info: 9/28/2019, 5:24:14 PM	 [RoutesResolver] AppController {/}:

However because the WinstonLogger class is not exported, the only way to make this work for me to copy/paste it into my codebase.

Constant for inject token

Hi, in the README, there is this example:

@Inject('winston') private readonly logger: Logger

I do not want to type the token 'winston' all the time to avoid typo, also it can change in the future. Best to have a constant for it. I can see this one from type definition:

export declare const WINSTON_MODULE_PROVIDER = "winston"

Is it supposed to be the inject token? If so, the README should mention about it.

winston exceptionHandlers is not printing logs to file

Env:

  1. Node: v10.19.0
  2. Nest: v7.3.2
  3. Nest Winston: ^1.3.6
  4. winston: ^3.3.3
  5. OS: Mac

Issue:

When i configure exceptionHandlers, the file got created but no log saving in the file.

Configure

import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';
const path = require("path");
require('winston-daily-rotate-file');
const myFormat = winston.format.printf(info => {
  return `${info.timestamp} ${info.level} [${info.label}]: ${info.message}`;
});
@Module({
  imports: [ConfigModule.forRoot({
    isGlobal: true,
    load: [configuration]
  }),
  WinstonModule.forRoot({
    exitOnError: false,
    format: winston.format.combine(winston.format.timestamp()
    , winston.format.label({ label: path.basename(process.mainModule.filename) })
    ,myFormat),  // winston.format.json(),
    transports: [
        new (<any>(winston.transports)).DailyRotateFile({
            filename: '/Desktop/logs/daily-%DATE%.log',
            datePattern: 'YYYY-MM-DD',
            maxFiles: '14d'
        }),
        new winston.transports.Console({
          format: winston.format.combine(winston.format.timestamp(), myFormat),
          handleExceptions: true
        })
    ],
    exceptionHandlers: [
        new winston.transports.File({ filename: '/Desktop/logs/exception.log' }),
    ]
  }),],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

The console directly print below but there is no content in the file /Desktop/logs/exception.log

[Nest] 66966   - 07/16/2020, 8:21:33 PM   [ExceptionsHandler] ER_NO_SUCH_TABLE: Table 'test.aaaaa11111' doesn't exist +4038ms
Error: ER_NO_SUCH_TABLE: Table 'test.aaaaa11111' doesn't exist
    at Query.Sequence._packetToError (/node_modules/mysql/lib/protocol/sequences/Sequence.js:47:14)
    at Query.ErrorPacket (/node_modules/mysql/lib/protocol/sequences/Query.js:79:18)
    at Protocol._parsePacket (/node_modules/mysql/lib/protocol/Protocol.js:291:23)
    at Parser._parsePacket (/node_modules/mysql/lib/protocol/Parser.js:433:10)
    at Parser.write (/node_modules/mysql/lib/protocol/Parser.js:43:10)
    at Protocol.write (/node_modules/mysql/lib/protocol/Protocol.js:38:16)
    at Socket.<anonymous> (/node_modules/mysql/lib/Connection.js:88:28)
    at Socket.<anonymous> (/node_modules/mysql/lib/Connection.js:526:10)
    at Socket.emit (events.js:198:13)
    at addChunk (_stream_readable.js:288:12)
    --------------------
    at Protocol._enqueue (/node_modules/mysql/lib/protocol/Protocol.js:144:48)
    at PoolConnection.query (/node_modules/mysql/lib/Connection.js:198:25)
    at /dist/src/common/MySqlService.js:63:28
    at Handshake.onConnect (/node_modules/mysql/lib/Pool.js:64:7)
    at Handshake.<anonymous> (/node_modules/mysql/lib/Connection.js:526:10)
    at Handshake._callback (/node_modules/mysql/lib/Connection.js:488:16)
    at Handshake.Sequence.end (/node_modules/mysql/lib/protocol/sequences/Sequence.js:83:24)
    at Handshake.Sequence.OkPacket (/node_modules/mysql/lib/protocol/sequences/Sequence.js:92:8)
    at Protocol._parsePacket (/node_modules/mysql/lib/protocol/Protocol.js:291:23)
    at Parser._parsePacket (/node_modules/mysql/lib/protocol/Parser.js:433:10)

Adding new logger transport depending on environment

I am implementing a logger module using nest-winston but I don't know how to implement a a new logger depending on environment cleanly, here's my LoggerModule:

import { Module } from "@nestjs/common";
import { WinstonModule, utilities } from 'nest-winston';
import * as winston from 'winston';
import configuration from "../config/configuration";
// Create a method to transform stacktrace error to Object
const errorStackFormat = winston.format(info => {
  if (info instanceof Error) {
    return Object.assign({}, info, {
      stack: info.stack,
      message: info.message
    })
  }
  return info
})

@Module({
  imports: [
    WinstonModule.forRootAsync({
      useFactory: () => ({
        level: "info",
        format: winston.format.combine(errorStackFormat()),
        defaultMeta: { service: "api" },
        transports: [
            new winston.transports.File({ filename: configuration.errLogPath + "/error.log", level: "error" }),
            new winston.transports.File({ filename: configuration.appLogPath + "/combined.log", level: 'info' }),
            new winston.transports.Console({
              format: winston.format.combine(
                winston.format.timestamp(),
                utilities.format.nestLike()
              )
            }),
        ],
      }),
      inject: [],
    }),
  ],
})

export class LoggerModule {}

Using nestLike formatter throws error when tries to log a circular object structure

I use nest-winston for l logging in my NestJS application. I am using a third-party lib to handle some business logic and in some cases, it throws a circular object structure error.

When this happens, I get the following error:

2020-04-20 09:31:20 [ExceptionsHandler] [error] Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    --- property 'someProperty' closes the circle
    TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    --- property 'someProperty' closes the circle
    at JSON.stringify (<anonymous>)
    at Printf.template (/my_project/node_modules/nest-winston/dist/winston.utilities.js:23:17)

After some research, I have found that the winston package uses fast-safe-stringify in order to avoid these kinds of errors. See here

The error comes from the winston.utilities.ts file when it tries to JSON.stringify the meta property.

Expected behaviour:

  • the nestLike formatter handles circular JSON structures using fast-safe-stringify

There is no info function in WinstonLogger class

I'm surprised that nest-winton doesn't provide info function, which is used in winston document frequently. Furthermore, log function sticks with info level. It's very confused and wastes a lot of time when moving from winston to nest-winston. Why don't we implement info and log function like the original library? Can I work on PR to implement it?

How to pass in dynamic label?

I have used Nest-Winston for main logging including bootstrap.

This is my configuration

{
    transports: [new transports.Console({
        level: 'debug'
    })],
    format: f.combine(
        format.colorize({ all: true }),
        format.splat(),
        format.simple(),
        format.timestamp(),
        nestWinstonModuleUtilities.format.nestLike()
    ),
    exitOnError: false
}

And this is what it logs now [NestWinston] debug 9/30/2020, 12:56:51 PM debug - {"abc": "xyz"}

How do I print the class name where the error occurred in the place of NestWinston ?

I tried with label but it wasn't dynamic.

I get from logger.info method [object Object]

I made model in folder modules/logger.

import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { WinstonModule } from 'nest-winston';

import { winstonConfig } from './winston.config';
import { LoggerInterceptor } from './interceptor/logger.interceptor';

@Module({
    imports: [WinstonModule.forRoot(winstonConfig)],
    controllers: [],
    providers: [
        {
            provide: APP_INTERCEPTOR,
            useClass: LoggerInterceptor,
        },
    ],
})
export class LoggerModule {}

My config file of logger in folder modules/logger.

import { utilities, WinstonModuleOptions } from 'nest-winston';
import { config, format, transports } from 'winston';

export const winstonConfig: WinstonModuleOptions = {
    levels: config.npm.levels,
    level: 'verbose',
    transports: [
        new transports.Console({
            format: format.combine(format.timestamp(), utilities.format.nestLike()),
        }),
        new transports.File({
            level: 'verbose',
            filename: 'application.log',
            dirname: 'logs',
            maxsize: 104857600, // 100MB
        }),
    ],
};

After a mode an interceptor in folder modules/logger/interceptor.

import { Injectable, Inject, NestInterceptor, CallHandler, ExecutionContext } from '@nestjs/common';
import { Logger } from 'winston';
import { Observable } from 'rxjs';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';

@Injectable()
export class LoggerInterceptor implements NestInterceptor {
    constructor(@Inject(WINSTON_MODULE_PROVIDER) private logger: Logger) {}

    public intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        this.log(context.switchToHttp().getRequest());
        return next.handle();
    }

    private log(req): void {
        const body = { ...req.body };
        delete body.password;
        delete body.passwordConfirmation;
        const user = (req as any).user;
        const userEmail = user ? user.email : null;
        const data = {
            timestamp: new Date().toISOString(),
            method: req.method,
            route: req.route.path,
            data: {
                body: body,
                query: req.query,
                params: req.params,
            },
            from: req.ip,
            madeBy: userEmail,
        };
        console.log(data);

        this.logger.info(data);
    }
}

In my app.module I added my logger.module.

...
import { LoggerModule } from './modules/logger/logger.module';

@Module({
    imports: [..., LoggerModule],
    controllers: [],
    providers: [],
})
export class AppModule {}

Where I run me app I see in console [object Object].

...
backend     | [NestWinston] Info        9/15/2020, 11:10:24 AM [RouterExplorer] Mapped {/user/update-user, PATCH} route - {}
backend     | [NestWinston] Info        9/15/2020, 11:10:24 AM [RouterExplorer] Mapped {/user/delete-user/:id, DELETE} route - {}
backend     | [NestWinston] Info        9/15/2020, 11:10:24 AM [RouterExplorer] Mapped {/user/profile, GET} route - {}
backend     | [NestWinston] Info        9/15/2020, 11:10:24 AM [RouterExplorer] Mapped {/user/find-users, GET} route - {}
backend     | [NestWinston] Info        9/15/2020, 11:10:24 AM [NestApplication] Nest application successfully started - {}
backend     | {
backend     |   timestamp: '2020-09-15T11:12:01.729Z',
backend     |   method: 'POST',
backend     |   route: '/auth/sign-in',
backend     |   data: { body: { email: '[email protected]' }, query: {}, params: {} },
backend     |   from: '::ffff:172.23.0.1',
backend     |   madeBy: null
backend     | }
backend     | [NestWinston] Info        9/15/2020, 11:12:01 AM [object Object] - {}

But usual console.log is show all object.

Why is it work so? Where I make mistake?

Can I use this logger to see the logs of my project when it runs on a server?

Hello, I'm new with nestjs.

Description::
There is an outside of my network plugin that sends data to my nestjs that runs on a server.
And it seems my nestjs responds with:

responseText: "{"statusCode":500,"message":"Internal server error"}"
success: false```

Can I use this logger to see what data I'm receiving from that plugin?
When I was working locally I was able to use the default logger for that, plus a simple console.log() and I could easily see the receiving objects.

But now that I'm online and that I have to receive something outside of my network I don't know where to see what my nestjs is receiving.

So my basic question:
Can I use this logger to see what I'm receiving while being live on a server?
And if yes, how? Is there a specific file that shows me logs?
Does it have a specific name or path?

Cannot use logger based on package documentation

I want to use Winston global when app starts

async function bootstrap() {

  const app = await NestFactory.createMicroservice(AppModule, {
    logger: WinstonModule.createLogger({
      transports: [
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp(),
            nestWinstonModuleUtilities.format.nestLike(),
          ),
        }),
        new winston.transports.File({
          filename: 'logs/app.log', format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.logstash(),
          )
        })
      ],
    }),
    transport: Transport.TCP,
    options: {
      host: "127.0.0.1",
      port: 8888
    }
  });
  app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));
  await app.listen(() => {app.get(WINSTON_MODULE_NEST_PROVIDER).log("STARTED")}); /**/is this ok?**
}
bootstrap();

- {"trace":"Error: Nest can't resolve dependencies of the AuthController (?, UserService, AuthService). Please make sure that the argument winston at index [0] is available in the AuthModule context.\n\nPotential solutions:\n- If winston is a provider, is it part of the current AuthModule?
This is not working anymore
constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) { }

If I added to the app main.js how can I use it in controllers?

Question: How can I insert the context info (module name) into logging

I wanna know if there's any way to insert (by default) the module name into logging information. I researched and found that the INQUIRER decorator seems to do what I want, however, how can I put this by default? PS.: I'm using the following configurations.

WinstonModule.forRoot({
      transports: [
        new winston.transports.File({
          format: winston.format.combine(
            winston.format.simple(),
            winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
            winston.format.printf(
              info => `[${info.timestamp}] ${info.level} ${info.message}`,
            ),
          ),
          maxsize: 10e6,
          maxFiles: 5,
          filename: `${__dirname}/../logs/log.log`,
        }),
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.simple(),
            winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
            winston.format.colorize(),
            winston.format.printf(
              info => `[${info.timestamp}] ${info.level} ${info.message}`,
            ),
          ),
          level: 'debug',
        }),
      ],
    }),
  ],

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

devcontainer
.devcontainer/devcontainer.json
github-actions
.github/workflows/contributors.yaml
  • wow-actions/contributors-list v1
.github/workflows/slate.yaml
  • actions/stale v8
.github/workflows/test.yaml
  • actions/checkout v4
  • actions/setup-node v4
.github/workflows/toc.yaml
  • technote-space/toc-generator v4
npm
package.json
  • fast-safe-stringify ^2.1.1
  • @nestjs/common 10.3.8
  • @nestjs/core 10.3.8
  • @nestjs/platform-express 10.3.8
  • @nestjs/testing 10.3.8
  • @types/jest 29.5.12
  • @typescript-eslint/eslint-plugin 6.21.0
  • @typescript-eslint/parser 6.21.0
  • eslint 8.57.0
  • jest 29.7.0
  • reflect-metadata 0.2.2
  • rimraf 4.4.1
  • rxjs 7.8.1
  • source-map-support 0.5.21
  • ts-jest 29.1.2
  • ts-node 10.9.2
  • typescript 4.9.5
  • winston 3.13.0
  • @nestjs/common ^5.0.0 || ^6.6.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0
  • winston ^3.0.0

  • Check this box to trigger a request for Renovate to run again on this repository

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.