cross-org/log

Feature Request: Support for libraries

NfNitLoop opened this issue · 3 comments

So far, all the docs seem to point to instantiating a single Log object, which is configured with all of its Loggers. And applications just call methods on that.

Are there any plans to support log instrumentation by libraries?

Common features I expect in that space, are:

  • Library author creates a named logger, and uses it within their library. By default, the logger isn't necessarily configured to output anything.
  • The application author that eventually uses the library configures a root/global/default logger with log levels, which may enable logging for various libraries. They can optionally filter by library, so they might have something like, "library foo has log-level info, but library bar has log level debug"
  • Library code that calls log methods has some way to send lazily-evaluated messages, which are only executed/formatted if the log level/filters would result in outputting that message.

Very interesting! The library could have two options,

propagate: Boolean; // <- default: false, set to true in libraries
ingest: Boolean;  // <- default: false, set to true in the main application process to ingest propagated logs

... if propagation is enabled, @cross/log would check (for example) globalThis.__crossLogPropagationHandlers_v1 for registered handlers, and call them

... if ingestion is enabled, @cross/log would register a handler on globalThis.__crossLogPropagationHandlers_v1` to receive propagated messages. The handler could expect (and validate) exactly one object, with the interface:

interface PropagatedMessage {
   severity: "DEBUG" | "INFO" | "LOG" | "WARN" | "ERROR" | string,
   scope: string,
   data: unknown,
   timestamp: number
}

Thoughts?

Thoughts?

TBH, I haven't implemented something like this in JS before. I don't mind how it's implemented as long as I get an API that lets me instrument my library (with negligible performance impact), and lets someone else decide whether/how to output those logs.

You might want to have a look at the Log4J API docs if you haven't used them before. (Whatever your feelings about Java as a language, Log4J was IMO one of the nice things from that ecosystem.) In particular, the idea of separating the logging API (interface) from the implementation. (see: https://logging.apache.org/log4j/2.x/manual/api-separation.html)

I tried using the Log4js NPM package before I found @cross/log, and it seems they've followed that pattern and have a separate log4js-api package. It didn't work well for me in Deno. (It immediately asked for permissions to read environment variables and node_modules.) But it might be a good implementation to look at for inspiration for the implementation.

For other similar APIs to draw ideas from, see the tracing_subscriber and tracing crates in Rust. ("tracing" is the interface, "_subscriber" is the output implementation.)