Coder Social home page Coder Social logo

Logger implementation about deno_std HOT 19 CLOSED

denoland avatar denoland commented on May 2, 2024
Logger implementation

from deno_std.

Comments (19)

ry avatar ry commented on May 2, 2024 2

My initial idea was to leverage Error.stack but I'm concerned with performance, throwing error at each logged message can't be a good idea.

Hm.. It's possible we could provide __LINE__ as a preprocessed symbol in deno. For the filename we could use import.meta once denoland/deno#975 lands.

from deno_std.

bartlomieju avatar bartlomieju commented on May 2, 2024 1

Probably yes, I'm still trying to figure it out. But if you look for example at deno.open it's asynchronous, so making most of the handlers would be asynchronous operation. AFAIK you can't do asynchronous stuff in class constructor, so it might be rewritten to: await new FileHandler().setup({ filename })

from deno_std.

bartlomieju avatar bartlomieju commented on May 2, 2024 1

@djKooks you can track progress in #51

from deno_std.

bartlomieju avatar bartlomieju commented on May 2, 2024 1

I reckon log implementation is good enough now we can close this.

from deno_std.

ry avatar ry commented on May 2, 2024
  1. I suggest we rename it to "log" - it's shorter.

  2. I think the golang logger has reflected on python's and provides a good design to copy
    https://golang.org/pkg/log/

  3. Currently Deno only has two built-in log-levels: debug and info. These can be in JS or Rust and are triggered by "-D"... Should the log module also be conditioned on "-D" ?

from deno_std.

bartlomieju avatar bartlomieju commented on May 2, 2024
  1. Agreed
  2. IMHO Go's logging module is low level compared to Python's. Do we want to provide simpler solution in standard library and leave it to user libraries to provide more battery-included solution?
  3. I think so, default logging level should display only error and critical messages, while -D set default log level to debug.

from deno_std.

ry avatar ry commented on May 2, 2024
  1. I kinda agree - although we need to provide some support for capturing logs and sending them elsewhere. Out of the box I'd like to be able to do
import * as log from "https://deno.land/std/log.ts";
log.debug("blah");
log.info("foo");

from deno_std.

bartlomieju avatar bartlomieju commented on May 2, 2024

@ry I totally agree. We can expose logging methods in exports, and those methods would call default logger.

Those two snippets would then be equivalent.

import * as log from "https://deno.land/std/log.ts";
log.debug("blah");
log.info("foo");
import * as log from "https://deno.land/std/log.ts";
const myLogger = log.getLogger();
myLogger.debug("blah");
myLogger.info("foo");

Regarding capturing and sending logs somewhere else, that's where Python's implementation shines.
We could do something like this:

import * as log from "https://deno.land/std/log.ts";
await log.config({
    handlers: {
        console: {
            level: 'debug',
            handler: new log.ConsoleHandler(),
        },
        file: {
            level: 'info',
            handler: new log.FileHandler(),
        },
    },
    loggers: {
        deno: {
            level: 'debug',
            handlers: ['console', 'file']
        }
    }
});

const logger = log.getLogger('deno');
logger.debug("blah"); // logged to console only
logger.info("foo");  // logged to both console and file

from deno_std.

kination avatar kination commented on May 2, 2024

@bartlomieju seems good!
Have one question...is log.config need await?

from deno_std.

kination avatar kination commented on May 2, 2024

@bartlomieju please share to me how logger will be implemented when decided. I'll fix my PR by the guide if needed. Thanks for your work.

from deno_std.

bartlomieju avatar bartlomieju commented on May 2, 2024

During chat conversation with @ry we concluded that logging methods should take only one argument msg and leave it to user to format message properly, eg.

import * as deno from 'deno';
import * as log from 'https://deno.land/x/std/logging/index.ts';
const someNum = 100;
const someObj = { a: 1, b: 2 };
// instead of interpolation ...
log.info("Number: %n, object: %o", someNum, someObj);
// just use template strings
log.info(`Number: ${someNum}, object: ${deno.inspect(someObj)}`)

This minimizes the API that has to be implemented.

As for output format of each message, Glog's style was proposed (also here). Note: we're not sure why leading bracket [ is missing in glog's format.

Proposed format:

[Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg

where:

  • L - level of message
  • mmdd - month and day
  • hh:mm:ss.uuuuuu - timestamp
  • threadid - PID of thread/process
  • file:line - filename and line from where message originated. Not sure we can get that info currently.

Example line would look like this:

[D0301 10:04:23:43111 3451 main.ts:30] Some logged message

To be honest I'm not a big fan of this format, I'd prefer to output ISO date like this:

[D 2018-01-03 10:04:23:43111 pid:3451 main.ts:30] Some logged message

from deno_std.

hayd avatar hayd commented on May 2, 2024

Would this be configurable?

from deno_std.

ry avatar ry commented on May 2, 2024

[D0301 10:04:23:43111 3451 main.ts:30] Some logged message

Have you thought about how to extract "main.ts:30" ?

Note: we're not sure why leading bracket [ is missing in glog's format.

If we're going to use glogs format, let's copy it exactly, including the unmatched bracket. It's not a mistake. I just don't know the reason for it.

To be honest I'm not a big fan of this format

Your proposed format is longer...

Would this be configurable?

I'd rather we agree on one format...

from deno_std.

bartlomieju avatar bartlomieju commented on May 2, 2024

Have you thought about how to extract "main.ts:30" ?

My initial idea was to leverage Error.stack but I'm concerned with performance, throwing error at each logged message can't be a good idea.

To be honest I'm not a big fan of this format

Your proposed format is longer...

It is, but glog's format is hard to grep when you see it for first time, especially conjunction of log level and date. But I'm not sticking to it no matter what.

Would this be configurable?

I'd rather we agree on one format...

That's fine for me, but it will bring a need for another logging libraries that allow to configure that.

from deno_std.

bartlomieju avatar bartlomieju commented on May 2, 2024

@ry one more comment on configurable format - tests would be much simpler if format could be manipulated, eg. date could be skipped. Otherwise we'd need some kind of wildcard matching?

from deno_std.

ry avatar ry commented on May 2, 2024

@bartlomieju true good point.

from deno_std.

bartlomieju avatar bartlomieju commented on May 2, 2024

After some consideration I think we might want to change LogRecord and signature of logging methods from:

export interface LogRecord {
  msg: string;
  args: any[];
  datetime: Date;
  level: number;
  levelName: string;
}

debug(msg: string, ...args: any[]) {
    return this._log(LogLevel.DEBUG, msg, ...args);
}

to:

type LogMetadata = {[key: string]: any};

export interface LogRecord {
  msg: string;
  metadata?: LogMetadata;
  datetime: Date;
  level: number;
  levelName: string;
}

debug(msg: string, metadata?: LogMetadata) {
    return this._log(LogLevel.DEBUG, msg, metadata);
}

this object would be placed in LogRecord and be later utilized in custom formatter. Simple but powerful IMHO.

from deno_std.

ry avatar ry commented on May 2, 2024

@bartlomieju That seems like more to type? Or maybe I misunderstand. Can you give some examples of invocation?

from deno_std.

bartlomieju avatar bartlomieju commented on May 2, 2024

Yeah after all it seems so. My initial idea was that args would be interpolated in msg (msg % args), but we already established that we don't want that.

We could keep LogRecord.args and allow to use that instead of metadata

from deno_std.

Related Issues (20)

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.