Write a Logger
Extend LumberjackLogger
(or ScopedLumberjackLogger)
so each log message lives once, with a fixed level and optional scope/payload.
Call sites stay one-liners and are easy to spy on in tests.
Before you start
Section titled “Before you start”- Lumberjack registered with a driver (Quick start).
-
Create a scoped logger class
import { Injectable } from '@angular/core'; import { ScopedLumberjackLogger } from '@ngworker/lumberjack'; @Injectable({ providedIn: 'root' }) export class AppLogger extends ScopedLumberjackLogger { readonly scope = 'Forest App'; readonly helloForest = this.createInfoLogger('Hello, Forest!').build(); readonly forestOnFire = this.createCriticalLogger('The forest is on fire!').build(); }build()returns a zero-arg function that emits the log when called. -
Inject and call it
import { Component, inject, OnInit } from '@angular/core'; import { AppLogger } from './app.logger'; @Component({ selector: 'app-root', template: ``, }) export class AppComponent implements OnInit { readonly #logger = inject(AppLogger); ngOnInit(): void { this.#logger.helloForest(); } }
Variations
Section titled “Variations”Without a shared scope
Section titled “Without a shared scope”Extend LumberjackLogger and set scope per builder:
import { Injectable } from '@angular/core';
import { LumberjackLogger } from '@ngworker/lumberjack';
@Injectable({ providedIn: 'root' })
export class AppLogger extends LumberjackLogger {
readonly helloForest = this.createInfoLogger('Hello, Forest!').withScope('Forest App').build();
}
With a static payload
Section titled “With a static payload”import { Injectable, VERSION } from '@angular/core';
import { LumberjackLogPayload, ScopedLumberjackLogger } from '@ngworker/lumberjack';
interface LogPayload extends LumberjackLogPayload {
readonly angularVersion: string;
}
@Injectable({ providedIn: 'root' })
export class AppLogger extends ScopedLumberjackLogger<LogPayload> {
readonly scope = 'Forest App';
readonly helloForest = this.createInfoLogger('Hello, Forest!').withPayload({ angularVersion: VERSION.full }).build();
}
Drivers that understand the payload can read log.payload on
LumberjackLogDriverLog. See How log drivers work.
Dynamic payload at call time
Section titled “Dynamic payload at call time”Skip withPayload on a logger typed with a payload. The built function takes
the payload as its argument:
import { Injectable, VERSION } from '@angular/core';
import { LumberjackLogPayload, ScopedLumberjackLogger } from '@ngworker/lumberjack';
interface LogPayload extends LumberjackLogPayload {
readonly angularVersion: string;
}
@Injectable({ providedIn: 'root' })
export class AppLogger extends ScopedLumberjackLogger<LogPayload> {
readonly scope = 'Forest App';
readonly helloForest = this.createInfoLogger('Hello, Forest!').build();
}
// call site
this.#logger.helloForest({ angularVersion: VERSION.full });
Verify
Section titled “Verify”Trigger the call path and confirm the console (or HTTP store) shows the fixed message and scope.
Next steps
Section titled “Next steps”- Log with LumberjackService — when a factory or one-off log is enough
- Create a custom driver
- Reference: ScopedLumberjackLogger