Provides a dependency-injected logger with support for pluggable listeners and log context tracking using Zone.js
npm install @alterior/logging
This module is intended to be used as part of an Alterior application. Several of the higher level first-party Alterior modules use this logger already, so it is a natural fit.
The module provides a Logger
injectable when LoggingModule
is imported into your Alterior application:
@Module({
imports: [ LoggingModule ]
})
export class MyEntryModule { }
Once the module is imported, you can inject Logger
into your services, controllers, tasks, etc:
import { Logger } from '@alterior/logging';
// ...
@Controller('/foo')
export class MyController {
constructor(
private logger : Logger
) {
}
@Get('/')
get() {
this.logger.info('Hello, world!');
}
}
// [2019-03-05T00:12:44Z] [source="MyController"] info: Hello, world!
You may wish to specifically mark logs which came from a particular class (or any other programmatic unit):
import { Logger } from '@alterior/logging';
// ...
@Injectable()
export class MyService {
constructor(
logger : Logger
) {
this.logger = logger.withSource(this)
}
private logger : Logger;
doSomething() {
this.logger.info('Hello, world!');
}
}
// [2019-03-05T00:12:44Z] [source="MyService"] info: Hello, world!
As you can see, withSource(object)
will use the object's constructor name as the source label. You can also pass a string to set the source label to any string you wish.
This library also provides "context tracking" using Zone.js
. When using context tracking, logs which occur inside a code block will be specially marked, even if the code is asynchronous or delayed.
logger.withContext({ myContextData: 123 }, `The data is 123`, () => {
setTimeout(() => logger.info(`Hello, world!`), 1000);
});
// [2019-03-05T00:12:44Z] [context="The data is 123"] info: Hello, world!
This is the mechanism that allows @alterior/web-server
and @alterior/tasks
to include the current request trace inside logs generated by reusable services. This results in logs that are easier to follow,
especially when there is heavy concurrency within a single log file (ie web servers, task runners):
[2019-03-05T00:12:44Z] [source="MyService" context="GET /foo | 1443c985-c4be-47f7-9e9c-941c21913def"] info: Hello, world!
[2019-03-05T00:12:44Z] [source="MyService" context="TaskWorker | MyBackgroundWorker"] info: Hello, world!
To configure the module, import it into your entry module and specify options in the call to configure()
:
@Module({
imports: [ LoggingModule.configure({ /* ... */ }) ]
})
export class MyEntryModule { }
"Listeners" are responsible for reporting logs in one way or another. By default a sensibly-configured ConsoleLogger
is used. If you wish to customize the format, you'll need to specify your own instance of ConsoleLogger
. If an empty set of listeners is specified, logs will effectively be dropped, and the logger itself becomes a no-op.
Log messages are passed to listeners as objects conforming to the LogMessage
interface:
export interface LogMessage {
message : string;
context : any;
contextLabel : string;
sourceLabel : string;
severity : LogSeverity;
date : Date;
}
It is the responsibility of the listener to decide how to format these log message objects. Some listeners may not format the object at all (for instance: recording logs to a collection in an object store like MongoDB).
Some built-in loggers use LogFormatter
to handle transforming a log object into a string suitable for use on a screen, log file, etc. LogFormatter
accepts a format string to determine how to transform the log message object into a string. Bare text is treated literally, and the fields of the LogMessage
can be referenced by surrounding the name of the field with '%'. The default format for builtin listeners is:
%date% [source="%sourceLabel%" context="%contextLabel%"] %severity%: %message%
Outputs the log to the console using console.log()
and friends. Accepts a format string suitable for use with LogFormatter
.
Writes logs to the specified file. Accepts a format string suitable for use with LogFormatter
.
This library also provides @Trace()
, a way to trace execution of one or more class methods
automatically. When used outside of an Alterior application's execution context, tracing is
always enabled. Within an Alterior app, you will have to specify tracing: true
on the
configuration for LoggingModule
in order for @Trace()
to be effective.
The log messages generated by @Trace()
will be output using Logger.current
. By default
this will print to the console, but this can be changed by configuring LoggerModule
in your
application, or by simply constructing a new Logger
and executing your code using logger.run()
.