Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with date formatting? #320

Closed
KirianCaumes opened this issue Mar 28, 2021 · 12 comments
Closed

Issue with date formatting? #320

KirianCaumes opened this issue Mar 28, 2021 · 12 comments

Comments

@KirianCaumes
Copy link
Contributor

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!

@gremo
Copy link
Owner

gremo commented Mar 30, 2021

Hi @KirianCaumes nestLikeConsoleFormat was intended to "mimic" the default Nest behaviour, that is print the timestamp using toLocaleString (look here).

If I understand it correctly, using winston.format.timestamp with a custom format option breaks the nestLikeConsoleFormat, right?

@KirianCaumes
Copy link
Contributor Author

Yep that's it, but you might be right te keep it closer to how the nest console works, don't know 🤷‍♀️

Btw, I don't think my "fix" break anything, as by default the date is displayed with the toLocaleString function if you don't set winston.format.timestamp.

@gremo
Copy link
Owner

gremo commented Mar 31, 2021

@KirianCaumes I agree with you. If winston allows to pass a custom date format, the nestLikeConsoleFormat should continue to work. If it doesn't, it's a design issue.

However, we should handle the case when:

  • winston.format.timestamp is not passed
  • winston.format.timestamp is passed without argument
  • winston.format.timestamp is passed with custom format argument (like your example)

This: ('undefined' !== typeof timestamp ? ${timestamp} :${new Date().toLocaleString()} ) seems not 100% right to me. Why stripping the timestamp argument from new Date()?

@KirianCaumes
Copy link
Contributor Author

Like this, you can handle the three different cases:

export const nestLikeConsoleFormat = (appName = 'NestWinston'): Format => winston.format.printf(({ context, level, timestamp, message, ...meta }) => {
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
    const color = nestLikeColorScheme[level] || ((text: string): string => text);

    const metaStr = safeStringify(meta)

    const timeToDisplay = (() => {
        // Without winston.format.timestamp()
        if ('undefined' === typeof timestamp) {
            return ' '
        } else {
            const dt = new Date(timestamp)
            // With winston.format.timestamp(), is this case "format" is equivalent to "new Date().toISOString()", example '2021-03-31T11:36:52.110Z'
            if (Object.prototype.toString.call(dt) === "[object Date]" && !isNaN(dt.getTime())) {
                return `${dt.toLocaleString()} `
            } else {
                // With winston.format.timestamp({ format: "DD/MM/YYYY HH:mm:ss" }), with valid "fecha" format, example '31/03/2021 13:43:00'
                return `${timestamp} `
            }
        }
    })()

    return `${color(`[${appName}]`)} ` +
        `${clc.yellow(level.charAt(0).toUpperCase() + level.slice(1))}\t` +
        (timeToDisplay) +
        ('undefined' !== typeof context ? `${clc.yellow('[' + context + ']')} ` : '') +
        `${color(message)}` +
        `${metaStr !== "{}" ? ` - ${metaStr}` : ''}`;
});

Feel free to make it cleaner 😁

ps: I've also handled a bit differently the meta, so that it won't be displayed if it's an empty object, but it's not really related to this issue

@gremo
Copy link
Owner

gremo commented Apr 3, 2021

Thanks, looking into this right now. I'll keep you updated :)

@gremo gremo closed this as completed in 50028e4 Apr 5, 2021
@gremo
Copy link
Owner

gremo commented Apr 7, 2021

Have you checked the new tag which includes your fix? It's OK? 👍

@KirianCaumes
Copy link
Contributor Author

I just check it, and it works fine, thank you!

Btw, what do you think about hidding the "meta" data if it is empty, like I did in my previous message?

@gremo
Copy link
Owner

gremo commented Apr 7, 2021

Sorry forgot about it, it depends on how Nest logger do in this case (since that formatter should mimic the Nest one). Can you check and report? Maybe we should open another issue for this.

@KirianCaumes
Copy link
Contributor Author

Hey,
It seems that we missed something.
Today, after a few days of nest-winston working fine, a strange bug appeared.
It took me some times to figure it out, but it's seems that when you do:

(new Date("my invalid date"))?.toISOString()

It doesn't return "Invalid Date" as:

(new Date("my invalid date"))?.toLocaleString()

But it throw an error: "Uncaught RangeError: invalid date".
Don't know how I missed this, but when you let this bug, my nest project won't run:

[4:03:34 PM] File change detected. Starting incremental compilation...

[4:03:34 PM] Found 0 errors. Watching for file changes.

Debugger attached.
(node:5213) Warning: Accessing non-existent property 'MongoError' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
 1: 0xa04200 node::Abort() [node]
 2: 0xa78549  [node]
 3: 0xbe56eb  [node]
 4: 0xbe6c96  [node]
 5: 0xbe7316 v8::internal::Builtin_HandleApiCall(int, unsigned long*, v8::internal::Isolate*) [node]
 6: 0x14012f9  [node]
Aborted

An easy solution would be to do something like this:

if ('undefined' !== typeof timestamp) {
    try {
        if (timestamp === (new Date(timestamp)).toISOString()) {
            timestamp = (new Date(timestamp)).toLocaleString();
        }
    } catch (error) { }
}

What do you think about this?
Thank you 😁

@gremo gremo reopened this Apr 14, 2021
@gremo
Copy link
Owner

gremo commented Apr 14, 2021

Hi there, why the timestamp passed to the formatter is in the wrong format (not a date format)?

@KirianCaumes
Copy link
Contributor Author

Here is an example:

new winston.transports.Console({
    format: winston.format.combine(
        winston.format.timestamp({ format: "DD/MM/YYYY HH:mm:ss" }), 
        nestWinstonModuleUtilities.format.nestLike("Emptio")
    ),
})
// => '14/04/2021 13:31:54'
// (new Date('14/04/2021 13:31:54')).toISOString() -> Uncaught RangeError: invalid date

new winston.transports.Console({
    format: winston.format.combine(
        winston.format.timestamp(),
        nestWinstonModuleUtilities.format.nestLike("Emptio")
    ),
})
// => '2021-04-14T13:33:29.814Z'
// (new Date('2021-04-14T13:33:29.814Z')).toISOString() ->  "2021-04-14T13:33:29.814Z"

@gremo
Copy link
Owner

gremo commented Apr 14, 2021

Oh right, thanks, guess I need to implement some testing for that. I was fooled using always an accepted format. I’ll work on a fix!

@gremo gremo closed this as completed in 5e932a5 Apr 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants