Skip to main content

· 4 min read
Nacho Vazquez
Lars Gyrup Brink Nielsen

The Lumberjack team is happy to announce @ngworker/lumberjack version 15. This release contains a collection of updates aiming to improve the Lumberjack experience and prepare us for the future. Enough small talk; let's dive into what's new!

TL;DR - Lumberjack version 15 introduces the following updates: internal upgrades like using the latest type-safe inject function or migrating into EcmaScript private fields. Updates to Angular version 15, Nx version 16.3, and Node 18. The most significant announcements are that we've added support for standalone Angular applications; now, you can conveniently include Lumberjack in the bootstrap application function and configure Lumberjack drivers as needed. And, the cherry on top, we launched our docs website, where you are reading this blog post.

Better Type Safety

We've introduced the newest type-safe inject function to Lumberjack's source code, moving away from constructor parameter decorators. This is a small step towards improving our source code's (already great) type safety and aligning our Angular implementations with current standards.

Keeping up to date

We are all excited about everything that's happening in the JavaScript world. That's why we will continue putting efforts into keeping Lumberjack up to date with the latest version of Angular and the rest of tools that are part of the Lumberjack ecosystem.

This time, we have updated to Angular version 15, Nx version 16.3, and Node 18. Please note this will introduce breaking changes.

Please update to at least Angular 15 before upgrading Lumberjack.

We migrated our entire workspace from TypeScript private fields to EcmaScript private fields, and we set to true the useDefineForClassFields flag on our tsconfig. These changes should make Lumberjack source code future-proof and more aligned with the current standards.

Supporting Standalone Angular Applications

Our most exciting announcement is that we've added support for standalone Angular applications. You can include Lumberjack directly in the bootstrap application function. Here's an example of how to use the new APIs:

bootstrapApplication(AppComponent, {
providers: [
// (…)
provideLumberjack(),
// (…)
],
});

Enhanced Driver Configuration

We've also enabled you to enable the standalone providers for the out-of-the-box Lumberjack drivers. Here's how you can do it:

bootstrapApplication(AppComponent, {
providers: [
// (…)
provideLumberjack(),
provideLumberjackConsoleDriver(),
provideLumberjackHttpDriver(withHttpConfig({})),
// (…)
],
});

Advanced Configuration for Those Who Want More

Configuring Lumberjack and the ConsoleDriver with the new API should represent a similar experience to what we have been able to do before with Modules.

We can configure both Lumberjack and the ConsoleDriver without any extra arguments or by passing a configuration object as the single parameter of the provided functions.

bootstrapApplication(AppComponent, {
providers: [
provideLumberjack({ levels: [LumberjackLevel.Error] }),
provideLumberjackConsoleDriver({
levels: [LumberjackLevel.Info, LumberjackLevel.Error],
}),
],
});

The HttpDriver is slightly more advanced since now we need to use the with* config functions for the different configuration types.

We can use the withHttpOptions.

bootstrapApplication(AppComponent, {
providers: [
provideLumberjack(),
provideLumberjackHttpDriver(
withHttpOptions({
origin: 'ForestApp',
retryOptions: { maxRetries: 1, delayMs: 250 },
storeUrl: '/API/logs',
}),
),

Or the withHttpConfig

bootstrapApplication(AppComponent, {
providers: [
provideLumberjack(),
provideLumberjackHttpDriver(
withHttpConfig({
levels: [LumberjackLevel.Error],
origin: 'ForestApp',
retryOptions: { maxRetries: 1, delayMs: 250 },
storeUrl: '/API/logs',
}),
),

The big novelty is that now, we can also configure the underlying HttpClient using the second argument of the provideLumberjackHttpDriver function.

bootstrapApplication(AppComponent, {
providers: [
provideLumberjack(),
provideLumberjackHttpDriver(
withHttpConfig({
levels: [LumberjackLevel.Error],
origin: 'ForestApp',
retryOptions: { maxRetries: 1, delayMs: 250 },
storeUrl: '/API/logs',
}),
withInterceptors([
(req, next) => {
const easy = inject(easyToken);
console.log('are interceptors working?', easy);
return next(req);
},
])
),

Continuouing Module Support

We want to assure you that we continue to support modules. The new standalone APIs are a complement, not a replacement. Choose your poison.

New Docs website

And the cherry on top is…

We are launching our dedicated documentation website. A dedicated website should make our documentation more accessible for our users and easier to update for our contributors.

This will be the home of future announcements and articles about the Lumberjack ecosystem.

Wrapping Up

We hope these changes will help your logging journey better and safer. We're grateful for your support, and as always, happy coding!

· 3 min read
Nacho Vazquez
Lars Gyrup Brink Nielsen

We are back, bringing a new version of Lumberjack with deprecations, improvements, and a secret project.

TL;DR - Lumberjack version 16 introduces the following updates: new level-based logging methods for the Lumberjack service, alignment with Angular 16.2, deprecation of all Lumberjack NgModules, and the introduction of a new spin-off project.

New level-based logging methods

In our constant intent to improve the developer experience, we have introduced new level-based logging methods for the Lumberjack service.

Previously, a single log method accepted a LumberjackLog object. This object contained the log message and the log level. We have now introduced a new method for each log level:

Previous:

// (...)
import { LumberjackService, LumberjackTimeService } from '@ngworker/lumberjack';

// (...)
export class MyComponent implements OnInit {
readonly #lumberjack = inject(LumberjackService);
readonly #time = inject(LumberjackTimeService);

// (...)
ngOnInit(): void {
this.#lumberjack.log({
level: LumberjackLevel.Info,
message: 'Hello, World!',
scope: 'MyComponent',
createdAt: this.#time.getUnixEpochTicks(),
});
}
}

New:

// (...)
import { LumberjackService, LumberjackTimeService } from '@ngworker/lumberjack';

// (...)
export class MyComponent implements OnInit {
readonly #lumberjack = inject(LumberjackService);
readonly #time = inject(LumberjackTimeService);

// (...)
ngOnInit(): void {
this.#lumberjack.logInfo('Hello, World!');
}
}

This new API is courtesy of our new contributor, Pierre Bouillon. Thank you, Pierre!

NgModule deprecation

At Lumberjack, we embrace the new standalone APIs as the best way to configure our libraries and applications. That's why we have decided to deprecate all Lumberjack NgModules.

NgModules will be available until Lumberjack v18. After that, we will remove them from the library.

As an additional benefit, after deleting the NgModules in version 18, we will receive a nice reduction in our bundle size.

We remove all usage of NgModule in our internal codebase and are happy with the result. We hope you will be too.

Ambitious Secret Project

Since version 15, we have been playing with an idea: what if we could create the best framework agnostic logging library? For that, we created a PR (now closed) where we experimented with extracting the agnostic API of Lumberjack. There are also a few discussions that you can read here and here.

However, we noticed that we were prisoners of our old API and wanted to try something new. That's why we decided to create a new spin-off project called LumberjackJS.

We will offer more information when we are ready, but we are excited about the future of this project.

The idea is to merge the two projects eventually and have a single library that can be used in any framework. But there is much work and experimentation to be done before that.

Community

We are proud and thrilled to have Pierre Bouillon contributing to our project.

DEV

Starting from this blog post, we will cross-post all our articles and release notes in our newly created DEV organization

Please give it a follow.

Wrapping Up

Our goal for 2024 is to keep updating Lumberjack at the same rate as Angular. That's why we will release very shortly Lumberjack v17 with Angular 17 support.

The remaining of our efforts will be on improving the Lumberjack Developer experience and documentation. But the main chunk of our time will be spent on LumberjackJS.

· 2 min read
Nacho Vazquez

As promised, we are getting up to speed with Angular versions. We are happy to announce that Lumberjack v17 is here.

TL;DR - Lumberjack version 17 introduces the following: Support for string literal unions as log levels, deprecation of enum-based log levels, alignment with Angular 17 upgrading to the latest Nx, and a special new contributor.

String Literal Unions Log Levels

In our continued pursuit of DX happiness, we are happy to introduce string literal unions as log levels.

String literal unions are less verbose than enums, and since they don't have a runtime implementation, they also make our bundle size lighter.

The new log levels are:

export type Level = 'critical' | 'debug' | 'error' | 'info' | 'trace' | 'verbose' | 'warn';

You can use the new API anywhere you were using the enum-based log levels:

Before:

this.#lumberjack.log({
level: LumberjackLevel.Info,
message: 'Hello, World!',
scope: 'MyComponent',
createdAt: this.#time.getUnixEpochTicks(),
});

Now:

this.#lumberjack.log({
level: 'info',
message: 'Hello, World!',
scope: 'MyComponent',
createdAt: this.#time.getUnixEpochTicks(),
});

Enum-based Log levels deprecation

As part of the introduction to string literal unions, we are deprecating the enum-based log levels.

Once removed in version 19, we can reduce the bundle size and simplify the API.

Community

On this version, we had the star collaboration of Diego Julião core maintainer of ngx-deploy-npm.

Diego helped us upgrade our deployment process to use the latest version of ngx-deploy-npm.

Thanks, Diego!

Wrapping Up

That's it, folks. Last time, we promised to release a new version of Lumberjack quickly, and we did it. We are happy to be able to keep our promises. Now that we are up to date with Angular, you should expect more news on our secret project soon