Getting a child logger
Closed this issue · 5 comments
I'm having a bit of trouble getting a child logger. I don't want to specify the category on every log call, i'm not sure why CategoryServiceFactory.getLogger always needs a root logger? Not sure why I can't do something like this:
import { Category, CategoryLogger, CategoryServiceFactory, CategoryDefaultConfiguration, LogLevel } from "typescript-logging";
// Optionally change default settings, in this example set default logging to Info.
// Without changing configuration, categories will log to Error.
CategoryServiceFactory.setDefaultConfiguration(new CategoryDefaultConfiguration(LogLevel.Info));
// Create categories, they will autoregister themselves.
// This creates one root logger, with 1 child sub category.
export const catRoot = new Category("App");
export const catComponent = new Category("Component", catRoot);
// Get a logger, this can be retrieved for root categories only (in the example above, the "service" category).
export const log: CategoryLogger = CategoryServiceFactory.getLogger(catRoot);
export function getComponentLogger(componentName) {
return CategoryServiceFactory.getLogger(new Category(componentName, catComponent));
};
// In my components
class MyComponent1 {
private readonly logger = getComponentLogger('MyComponent1')
}
Hello @kamshak
Originally when this was designed we decided we wanted to explicitly log over multiple categories, instead of one in our apps (it was more like a horizontal slice over an application when logging, than a vertical one like most loggers - allowing you to enable logging sub-parts of an application based on category). That's where the root logger and it's restrictions originate from.
Looking back, that made sense in some settings but not in all.
In the next major release - 0.5.0, this will be changed - so what you sketch above can be done (or in a similar way). Keep an eye on this bug, it will be updated when ready.
For now, as alternative you could use the log4j variant (see the docs).
Could you give an example of what a horizontal slice would look like? I've done this for now but it feels like a lot of code:
class ComponentLogger implements CategoryLogger {
constructor(private _delegate: CategoryLogger, private category: Category) {}
trace(msg: string | LogData): void {
this._delegate.trace(msg, this.category);
}
debug(msg: string | LogData): void {
this._delegate.debug(msg, this.category);
}
info(msg: string | LogData): void {
this._delegate.info(msg, this.category);
}
warn(msg: string | LogData): void {
this._delegate.warn(msg, this.category);
}
error(msg: string | LogData, error: Error): void {
this._delegate.error(msg, error, this.category);
}
fatal(msg: string | LogData, error: Error): void {
this._delegate.fatal(msg, error, this.category);
}
resolved(msg: string | LogData, error: Error): void {
this._delegate.resolved(msg, error, this.category);
}
log(level: LogLevel, msg: string | LogData, error: Error): void {
this._delegate.log(level, msg, error, this.category);
}
tracec(msg: () => string | LogData): void {
this._delegate.tracec(msg, this.category);
}
debugc(msg: () => string | LogData): void {
this._delegate.debugc(msg, this.category);
}
infoc(msg: () => string | LogData): void {
this._delegate.infoc(msg, this.category);
}
warnc(msg: () => string | LogData): void {
this._delegate.warnc(msg, this.category);
}
errorc(msg: () => string | LogData, error: () => Error): void {
this._delegate.errorc(msg, error, this.category);
}
fatalc(msg: () => string | LogData, error: () => Error): void {
this._delegate.fatalc(msg, error, this.category);
}
resolvedc(msg: () => string | LogData, error: () => Error): void {
this._delegate.resolvedc(msg, error, this.category);
}
logc(level: LogLevel, msg: () => string | LogData, error: () => Error): void {
this._delegate.logc(level, msg, error, this.category);
}
}
export function getComponentLogger(componentName) {
return new ComponentLogger(log, new Category(componentName, catComponent));
};
BTW do you come from a Java Background? The style reminds me very much of it (and is a bit confusing to me tbh).
It depends on your application really if it makes sense or not.
In complex applications you may have e.g. some kind of let's just call it "service" here, service has a back-end (doesn't really matter what in this example) and a front-end part for the user. To make it all work it does a lot of things over many classes e.a (to stick to typescript terminology here). So you'd have a category for "service", that's used throughout it all when logging. In addition there are some rest calls going to server-backend, they are related to service - but also to category "rest-api". In that case they'd log to both categories (hence the categories parameter).
That is a simple example, but gives the gist of it. It allows you to see everything related to "service" by enabling that single category, or if you are interested in only the rest-api by enabling (it's horizontal literally, not for a single class or anything what most loggers usually do).
But as said, simple and straightforward logging using a single category makes sense as well and I am glad you asked for it. I've been playing with the idea to support this, but now it's good to see there's more than me. :)
And yeah I am from a Java background originally, it's that obvious right. ;) I can always tell the opposite too. ;)
One of the reasons the project is still on a 0.x release is also that it allows me to make larger changes still if needed. Once it hits 1.0.0 I cannot do that any more.
As another workaround for you:
You can also create a logger for each root category (so don't use child categories), as loggers always log to their root logger if you do not specify any category in the log statement. Obviously you will lose the tree of categories that way. Otherwise your workaround is sufficient for now.
Hello @kamshak
See issue #25 for the actual changes which are also partially related to this issue. I just published 0.5.0 to npm as well containing these changes.
In short for this issue, you can now log using a category directly (this is new).
const cat = new Category("bla");
cat.debug(..))
You can also get a logger for any category now. Whether you use the logger or category to log is up to you, for the library it is the same.
Good luck, hope this helps!
Great changes, that simplifies the API a lot! Thanks ❤️