Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions astro.sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ export const sidebar = [
'reference/experimental-flags/svg-optimization',
'reference/experimental-flags/queued-rendering',
'reference/experimental-flags/rust-compiler',
'reference/experimental-flags/logger',
],
}),
'reference/legacy-flags',
Expand Down
218 changes: 218 additions & 0 deletions src/content/docs/en/reference/experimental-flags/logger.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
---
title: Configuring logger
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually put "Experimental" in the title:

Suggested change
title: Configuring logger
title: Experimental logger

Or if you think this is important to keep "configuring" here:

Suggested change
title: Configuring logger
title: Experimental logger configuration

sidebar:
label: Logger
i18nReady: true
---

import Since from '~/components/Since.astro';

<p>

**Type:** `object`<br />
**Default:** `undefined`<br />
<Since v="6.2.0" />
</p>

Enables an experimental, custom logger that can be controlled by the user.

When provided, the user has total control over the logs emitted by Astro. Additionally, the feature comes with some built-in loggers that can be used via the new `logHandlers`.

In the following example, we enable the built-in JSON logger, with a pretty output.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We avoid "we" in docs:

Suggested change
In the following example, we enable the built-in JSON logger, with a pretty output.
The following example enables the built-in JSON logger, with a pretty output:


```js title="astro.config.mjs" {5} ins="logHandlers"
import { defineConfig, logHandlers } from 'astro/config';

export default defineConfig({
experimental: {
logger: logHandlers.json({ pretty: true })
}
});
```

Alternatively, you can enable JSON logging the `dev`, `build` and `sync` commands using the `--experimentalJson` flag:

```shell
astro dev --experimentalJson
astro sync --experimentalJson
astro build --experimentalJson
```


## Built-in loggers

The feature comes with three built-in loggers.

### `logHandlers.json`

A logger that outputs messages in a JSON format. A log would look like this:
```json
{ "message": "<the message>", "label": "router", "level": "info", "time": "<UNIX timestamp>" }
```

The `json` function accepts the following options:

<p>
**Type:** `{ pretty: bool, level: AstroLoggerLevel }`<br />
**Default:** `{ pretty: false, level: 'info' }`
<Since v="6.2.0" />
</p>
Comment on lines +53 to +59
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API block before the list looks a bit weird in the preview. But I get the intent: this is the type for the configuration object not for logHandlers.json().

I wonder if a heading for the options could help here:

Suggested change
The `json` function accepts the following options:
<p>
**Type:** `{ pretty: bool, level: AstroLoggerLevel }`<br />
**Default:** `{ pretty: false, level: 'info' }`
<Since v="6.2.0" />
</p>
#### JSON logger options
<p>
**Type:** `{ pretty: boolean; level: AstroLoggerLevel; }`<br />
**Default:** `{ pretty: false, level: 'info' }`
<Since v="6.2.0" />
</p>
The `json` logger accepts the following options:

What do you think?


- `pretty`: when `true`, the JSON log in printed on multiple lines. Defaults to `false`
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo?

Suggested change
- `pretty`: when `true`, the JSON log in printed on multiple lines. Defaults to `false`
- `pretty`: when `true`, the JSON log is printed on multiple lines. Defaults to `false`

- `level`: the [level](#log-level) of logs that should be printed.

```js title="astro.config.mjs" {5} ins="json"
import { defineConfig, logHandlers } from 'astro/config';

export default defineConfig({
experimental: {
logger: logHandlers.json({ pretty: true })
}
});
```

### `logHandlers.console`

A logger that print messages using `console` as its destination. Based on the level of the message, it uses different channels:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo and I think we miss a "the" here:

Suggested change
A logger that print messages using `console` as its destination. Based on the level of the message, it uses different channels:
A logger that prints messages using the `console` as its destination. Based on the level of the message, it uses different channels:

- `error` messages are printed using `console.error`
- `warn` messages are printed using `console.warn`
- `info` messages are printed using `console.info`

The function accepts the following options:

<p>
**Type:** `{ level: AstroLoggerLevel }`<br />
**Default:** `{ level: 'info' }`
<Since v="6.2.0" />
</p>
Comment on lines +81 to +87
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before, this currently looks a bit weird in the preview and I wonder if a heading for the options could help here:

Suggested change
The function accepts the following options:
<p>
**Type:** `{ level: AstroLoggerLevel }`<br />
**Default:** `{ level: 'info' }`
<Since v="6.2.0" />
</p>
#### Console logger options
<p>
**Type:** `{ level: AstroLoggerLevel }`<br />
**Default:** `{ level: 'info' }`
<Since v="6.2.0" />
</p>
The `console` logger accepts the following options:


- `level`: the [level](#log-level) of logs that should be printed.

```js title="astro.config.mjs" {5} ins="console"
import { defineConfig, logHandlers } from 'astro/config';

export default defineConfig({
experimental: {
logger: logHandlers.console({ level: 'warn' })
}
});
```

### `logHandlers.node`

A logger that print messages to [`process.stdout`](https://nodejs.org/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/api/process.html#processstderr). Level `error` messages are printed to `stderr`, while the others are printed to `stdout`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo:

Suggested change
A logger that print messages to [`process.stdout`](https://nodejs.org/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/api/process.html#processstderr). Level `error` messages are printed to `stderr`, while the others are printed to `stdout`.
A logger that prints messages to [`process.stdout`](https://nodejs.org/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/api/process.html#processstderr). Level `error` messages are printed to `stderr`, while the others are printed to `stdout`.


This is Astro's default logger.

The function accepts the following options:

<p>
**Type:** `{ level: AstroLoggerLevel }`<br />
**Default:** `{ level: 'info' }`
<Since v="6.2.0" />
</p>
Comment on lines +107 to +113
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before:

Suggested change
The function accepts the following options:
<p>
**Type:** `{ level: AstroLoggerLevel }`<br />
**Default:** `{ level: 'info' }`
<Since v="6.2.0" />
</p>
#### Node logger options
<p>
**Type:** `{ level: AstroLoggerLevel }`<br />
**Default:** `{ level: 'info' }`
<Since v="6.2.0" />
</p>
The `node` logger accepts the following options:


- `level`: the [level](#log-level) of logs that should be printed.

```js title="astro.config.mjs" {5} ins="node"
import { defineConfig, logHandlers } from 'astro/config';

export default defineConfig({
experimental: {
logger: logHandlers.node({ level: 'warn' })
}
});
```

## Custom loggers

You can create a custom logger by providing the correct configuration to the `logger` setting. It accepts an object with a mandatory `entrypoint`, the module where the logger is exported, and an optional configuration to pass to the logger. The configuration must be serializable.

The logger function must be exported as `default`.

When you define a custom logger, you are in charge of all logs, even the ones emitted by Astro.

The following example, a custom logger is defined and exported by the package `@org/custom-logger`, and it accepts an object with only `level` defined.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we miss at least a verb after "the following example". What about something like this:

Suggested change
The following example, a custom logger is defined and exported by the package `@org/custom-logger`, and it accepts an object with only `level` defined.
The following example defines a custom logger exported by the `@org/custom-logger` package and accepting only one parameter to configure the logging `level`:


```js title="astro.config.mjs"
import { defineConfig, logHandlers } from 'astro/config';

export default defineConfig({
experimental: {
logger: {
entrypoint: "@org/custom-logger",
config: {
level: "warn"
}
}
}
});
```

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if the sentence below the code snippet couldn't be moved (and reworded a bit) here to separate the two code snippets and to make it easier to differentiate them:

Suggested change
The following example implements a minimal logger returning an `AstroLoggerDestination` object with the required `write()` function:

```ts title="@org/custom-logger/index.ts"
import type {
AstroLoggerLevel,
AstroLoggerDestination,
AstroLoggerMessage
} from "astro";
import { matchesLevel } from "astro/logger";

type LoggerOptions = {
level: AstroLoggerLevel
}

function orgLogger(options: LoggerOptions = {}): AstroLoggerDestination {
const { level = 'info' } = options;
return {
write(message: AstroLoggerMessage) {
// Use utility to understand if the message should be printed
if (matchesLevel(message.level, level)) {
// log message somewhere and take level into consideration
}
}
}
}

export default orgLogger;
```

Custom loggers must comply with the `AstroLoggerDestination` interface, and the function `write` is mandatory.
Comment on lines +178 to +179
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then, this is no longer necessary:

Suggested change
Custom loggers must comply with the `AstroLoggerDestination` interface, and the function `write` is mandatory.


## Runtime

The types [context object](/en/reference/api-reference/#the-context-object) now expose `logger` object that exposes the following functions:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this is the barrier language but "types" sounds odd to me here. Could we use this instead:

Suggested change
The types [context object](/en/reference/api-reference/#the-context-object) now expose `logger` object that exposes the following functions:
The [context object](/en/reference/api-reference/#the-context-object) now exposes a `logger` object containing the following functions:


- `error()`, which emits an message with `error` level.
- `warn()`, which emits an message with `warn` level.
- `info()`, which emits an message with `info` level.

```astro
---
Astro.logger.error("This is an error");
Astro.logger.warn("This is a warning");
Astro.logger.info("This is an info");
---
```

## Log level

A level is an internal, arbitrary score, assigned to each message. When a logger is configured with a certain level, only the messages with equals level is equal or higher are printed.Custom
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this was the auto completion trying to add something after the dot?

Suggested change
A level is an internal, arbitrary score, assigned to each message. When a logger is configured with a certain level, only the messages with equals level is equal or higher are printed.Custom
A level is an internal, arbitrary score, assigned to each message. When a logger is configured with a certain level, only the messages with equals level is equal or higher are printed.


There are three levels, from the highest to the lowest score:
1. `error`
1. `warn`
1. `info`
Comment on lines +202 to +204
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this is correctly rendered but they all have the same score currently 😅

Suggested change
1. `error`
1. `warn`
1. `info`
1. `error`
2. `warn`
3. `info`


In the following example, we configure the JSON logger to print only messages that have the `warn` level or higher:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as earlier, we avoid "we" in docs:

Suggested change
In the following example, we configure the JSON logger to print only messages that have the `warn` level or higher:
The following example configures the JSON logger to print only messages that have the `warn` level or higher:


```js title="astro.config.mjs" {5} ins='level: "warn"'
import { defineConfig, logHandlers } from 'astro/config';

export default defineConfig({
experimental: {
logger: logHandlers.json({ level: "warn" })
}
});
```


Loading