Skip to content

Commit 6740fa6

Browse files
authored
docs(logger): add notice about mutating attributes in log formatter (#3604)
1 parent 22eda14 commit 6740fa6

File tree

2 files changed

+20
-13
lines changed

2 files changed

+20
-13
lines changed

Diff for: docs/core/logger.md

+6-9
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ If you prefer to log in a specific timezone, you can configure it by setting the
588588

589589
### Using multiple Logger instances across your code
590590

591-
The `createChild` method allows you to create a child instance of the Logger, which inherits all of the attributes from its parent. You have the option to override any of the settings and attributes from the parent logger, including [its settings](#utility-settings), any [extra keys](#appending-additional-keys), and [the log formatter](#custom-log-formatter-bring-your-own-formatter).
591+
The `createChild` method allows you to create a child instance of the Logger, which inherits all of the attributes from its parent. You have the option to override any of the settings and attributes from the parent logger, including [its settings](#utility-settings), any [extra keys](#appending-additional-keys), and [the log formatter](#custom-log-formatter).
592592

593593
Once a child logger is created, the logger and its parent will act as separate instances of the Logger class, and as such any change to one won't be applied to the other.
594594

@@ -754,26 +754,24 @@ Sampling decision happens at the Logger initialization. This means sampling may
754754
}
755755
```
756756

757-
### Custom Log formatter (Bring Your Own Formatter)
757+
### Custom Log formatter
758758

759-
You can customize the structure (keys and values) of your log items by passing a custom log formatter, an object that implements the `LogFormatter` abstract class.
759+
You can customize the structure (keys and values) of your logs by passing a custom log formatter, a class that implements the `LogFormatter` interface, to the `Logger` constructor.
760+
761+
When working with custom log formatters, you take full control over the structure of your logs. This allows you to optionally drop or transform keys, add new ones, or change the format to suit your company's logging standards or use Logger with a third-party logging service.
760762

761763
=== "handler.ts"
762764

763765
```typescript hl_lines="2 6"
764766
--8<-- "examples/snippets/logger/bringYourOwnFormatterHandler.ts"
765767
```
766768

767-
This is how the `MyCompanyLogFormatter` (dummy name) would look like:
768-
769769
=== "utils/formatters/MyCompanyLogFormatter.ts"
770770

771771
```typescript
772772
--8<-- "examples/snippets/logger/bringYourOwnFormatterClass.ts"
773773
```
774774

775-
This is how the printed log would look:
776-
777775
=== "Example CloudWatch Logs excerpt"
778776

779777
```json
@@ -804,8 +802,7 @@ This is how the printed log would look:
804802
}
805803
```
806804

807-
!!! tip "Custom Log formatter and Child loggers"
808-
It is not necessary to pass the `LogFormatter` each time a [child logger](#using-multiple-logger-instances-across-your-code) is created. The parent's LogFormatter will be inherited by the child logger.
805+
Note that when implementing this method, you should avoid mutating the `attributes` and `additionalLogAttributes` objects directly. Instead, create a new object with the desired structure and return it. If mutation is necessary, you can create a [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone) of the object to avoid side effects.
809806

810807
### Bring your own JSON serializer
811808

Diff for: packages/logger/src/formatter/LogFormatter.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@ abstract class LogFormatter {
2525
/**
2626
* Format key-value pairs of log attributes.
2727
*
28-
* You should implement this method in a subclass to define the structure of the log item.
28+
* You should implement this method in a subclass to define the structure of the log item
29+
* and instantiate a new {@link LogItem} object with the formatted attributes.
30+
*
31+
* Note that when implementing this method, you should avoid mutating the `attributes` and
32+
* `additionalLogAttributes` objects directly. Instead, create a new object with the desired
33+
* structure and return it.
34+
*
35+
* If mutation is necessary, you can create a `structuredClone` of the object to avoid side effects.
2936
*
3037
* @example
3138
* ```typescript
@@ -40,7 +47,7 @@ abstract class LogFormatter {
4047
* attributes: UnformattedAttributes,
4148
* additionalLogAttributes: LogAttributes
4249
* ): LogItem {
43-
* const baseAttributes: MyCompanyLog = {
50+
* const baseAttributes = {
4451
* message: attributes.message,
4552
* service: attributes.serviceName,
4653
* environment: attributes.environment,
@@ -116,8 +123,11 @@ abstract class LogFormatter {
116123
: error.cause,
117124
};
118125
for (const key in error) {
119-
if (typeof key === 'string' && !['name', 'message', 'stack', 'cause'].includes(key)) {
120-
formattedError[key] = (errorAttributes as Record<string, unknown>)[key];
126+
if (
127+
typeof key === 'string' &&
128+
!['name', 'message', 'stack', 'cause'].includes(key)
129+
) {
130+
formattedError[key] = (errorAttributes as Record<string, unknown>)[key];
121131
}
122132
}
123133

0 commit comments

Comments
 (0)