winstonjs / winston-daily-rotate-file

A transport for winston which logs to a rotating file each day.
MIT License
889 stars 151 forks source link

Winston's audit Files are created even when no logs are printed #378

Open hakunamatata97k opened 1 year ago

hakunamatata97k commented 1 year ago

I'm currently using the following NPM packages to create my custom logger, Winston and Winston-daily-rotate-file.

The problem:

The <hash>.json are created regardless of the existance of the <info|error-[Date]>.log files.

What does the code look like:

I have the following code in logger.js :

import  *  as  winston  from  'winston';
import  'winston-daily-rotate-file';

//function is used in other place to get a date formated string. is there a way to get string back from winston logger?
function logWithTimestamp(message) {
    return `[${new Date().toISOString().replace('T', ' ').slice(0, 19)} ${message}]`;
}

//To account for https://github.com/winstonjs/winston/issues/614
const infoFilter = winston.format((info) => {
    return info.level === 'info' ? info : false;
});
function myFilter (func) {
    const filters = [];
    if (func)
        filters.push(func());

    return winston.format.combine(
        ...filters,
        winston.format.errors({ stack: true }),
        winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
        winston.format.json()
    )
}
const logger = winston.createLogger({
    level: 'info', // Minimum log level to be recorded
    transports: [
        // Log errors to error.log file
        new winston.transports.DailyRotateFile({
            level: 'error',
            filename: 'logs/error-%DATE%.log',
                        lazy: true, //EDIT 1:this had no effect.
            datePattern: 'YYYY-MM-DD',
            maxSize: '10m', // Max size of log file
            maxFiles: '14d', // Keep logs for 14 days
            format: myFilter(),
        }),
        // Log info messages to info.log file
        new winston.transports.DailyRotateFile({
            level: 'info',
            filename: 'logs/info-%DATE%.log',
                        lazy: true, //EDIT 1:this had no effect.
            datePattern: 'YYYY-MM-DD',
            maxSize: '10m',
            maxFiles: '14d',
            format: myFilter(infoFilter)
        }),
    ],
});

export {logger, logWithTimestamp}

In my index.js I import it as import {logger} from "./logger.js";

What I tried:

I think it's a bit due to the fact of me declaring it as const that will get called upon the program start.
Thus, I tried this:

`logger.js`

....
let logger;
function getLoggerInstance() {
    if (!logger) {
       logger = winston.createLogger({
          level: 'info', // Minimum log level to be recorded
          transports: [
             // Log errors to error.log file
             new winston.transports.DailyRotateFile({
                level: 'error',
                filename: 'logs/error-%DATE%.log',
                datePattern: 'YYYY-MM-DD',
                maxSize: '10m', // Max size of log file
                maxFiles: '14d', // Keep logs for 14 days
                format: myFilter(),
             }),
             // Log info messages to info.log file
             new winston.transports.DailyRotateFile({
                level: 'info',
                filename: 'logs/info-%DATE%.log',
                datePattern: 'YYYY-MM-DD',
                maxSize: '10m',
                maxFiles: '14d',
                format: myFilter(infoFilter)
             }),
          ],
       });
    }
    return logger;
}
export {getLoggerInstance, logWithTimestamp}
.... 

In index.js :

import { getLoggerInstance} from "./logger.js";
//const logger = getLoggerInstance(); // initializing the logger at top level causes the same problem. 

Then is changed the export in logger.js to export {getLoggerInstance as logger, logWithTimestamp} and in index.js I would have to constantly use logger().info(); to print, which is highly impractical in my opinion but kind of solves the problem.

Do you know how I could either invoke the creation of <hash>.json upon first logger.<info() | debug()> call or achieve the same behavior?

Please let me know, and thanks in advance.

EDIT 1:

Based on the comment from @Nol-go in #291 and the new introduction of the lazy option I modified the code to include it. Yet it still produces the same behaviour. Any suggestions are more than welcome :)

Image from the IDE view:

Untitled2

With or without the lazy option the audit files are being created on initialization, and with or without lazy the *.logs file are not initialized when nothing is logged. :/ sooo i dunno.

hakunamatata97k commented 1 year ago

Edited the issue description to include the usage of the lazy option. Look up :)

Nol-go commented 1 year ago

So what you could try as a temporary fixup is to create a script that erases files that are empty an run it with a cron module like node-schedule.

You could also try to implement MattBerter's solution locally in your node_modules folder, but it wouldn't work if you build the dependencies from scratch on your prod environment.

Last solution if it's really urgent, fork the project, implement his solution and use that fork in your package.json (I know it's possible but not how to do it so -> google if you have questions on that)

As for why the lazy option does not work, you would need to go into the transport code to check how they manage the options.