@trojs/logger 2.2.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# logger
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
Generic logger with integrations for e.g. Sentry
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
* Multiple transport support (console, files, Sentry)
|
|
8
|
+
* Winston-based logging with custom transports
|
|
9
|
+
* Safe JSON serialization (handles circular references, deep objects, functions)
|
|
10
|
+
* Stackdriver/Google Cloud Logging compatible
|
|
11
|
+
* Automatic exception and rejection handling
|
|
12
|
+
* Configurable log levels per transport
|
|
13
|
+
* Production-ready error tracking with Sentry integration
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
3
16
|
|
|
4
17
|
```javascript
|
|
5
18
|
import makeLogger from '@trojs/logger';
|
|
@@ -26,23 +39,36 @@ try {
|
|
|
26
39
|
}
|
|
27
40
|
```
|
|
28
41
|
|
|
29
|
-
|
|
42
|
+
## Configuration
|
|
43
|
+
|
|
44
|
+
### level
|
|
45
|
+
|
|
46
|
+
default: `info`
|
|
30
47
|
|
|
31
|
-
|
|
48
|
+
Log only messages with a level less than or equal to this level. This acts as a global filter for all loggers unless a logger specifies its own level.
|
|
32
49
|
|
|
33
|
-
|
|
50
|
+
Available levels (in order of priority):
|
|
51
|
+
* `trace` (lowest)
|
|
52
|
+
* `debug`
|
|
53
|
+
* `info`
|
|
54
|
+
* `warn`
|
|
55
|
+
* `error`
|
|
56
|
+
* `fatal` (highest)
|
|
34
57
|
|
|
35
|
-
More info
|
|
58
|
+
More info: <https://www.npmjs.com/package/winston#logging-levels>
|
|
36
59
|
|
|
37
|
-
|
|
60
|
+
### service
|
|
38
61
|
|
|
39
|
-
default: user-service
|
|
62
|
+
default: `user-service`
|
|
40
63
|
|
|
41
|
-
|
|
64
|
+
The service name is used to identify the source of logs. This is particularly useful when aggregating logs from multiple services.
|
|
42
65
|
|
|
43
|
-
|
|
66
|
+
## Loggers
|
|
67
|
+
|
|
68
|
+
Set of logging targets (transports) for log messages. Each logger can have its own configuration and log level.
|
|
69
|
+
|
|
70
|
+
Default configuration:
|
|
44
71
|
|
|
45
|
-
default:
|
|
46
72
|
```javascript
|
|
47
73
|
[
|
|
48
74
|
{
|
|
@@ -51,17 +77,16 @@ default:
|
|
|
51
77
|
]
|
|
52
78
|
```
|
|
53
79
|
|
|
54
|
-
|
|
80
|
+
Available logger types:
|
|
55
81
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
82
|
+
* `console` - Logs to stdout/stderr
|
|
83
|
+
* `errorFile` - Logs errors to a file
|
|
84
|
+
* `combinedFile` - Logs all messages to a file
|
|
85
|
+
* `sentry` - Sends errors to Sentry for tracking
|
|
60
86
|
|
|
61
|
-
The default loggers are
|
|
87
|
+
**Note:** The default loggers are replaced (not merged) when you provide a `loggers` array.
|
|
62
88
|
|
|
63
|
-
|
|
64
|
-
More info see: https://www.npmjs.com/package/winston#transports
|
|
89
|
+
All loggers are implemented as Winston transports. More info: <https://www.npmjs.com/package/winston#transports>
|
|
65
90
|
|
|
66
91
|
## sentry
|
|
67
92
|
|
|
@@ -71,30 +96,156 @@ More info see: https://www.npmjs.com/package/winston#transports
|
|
|
71
96
|
* release (default: unknown, sentry.release)
|
|
72
97
|
* debug (default: false, sentry.debug)
|
|
73
98
|
* sampleRate (default: 1, sentry.sampleRate)
|
|
74
|
-
* tracesSampleRate (default: 1,
|
|
99
|
+
* tracesSampleRate (default: 1, sentry.tracesSampleRate)
|
|
75
100
|
* level (default: info)
|
|
76
101
|
|
|
77
|
-
DSN
|
|
102
|
+
### DSN
|
|
78
103
|
|
|
79
104
|
The DSN tells the SDK where to send the events. If this value is not provided, the SDK will try to read it from the SENTRY_DSN environment variable. If that variable also does not exist, the SDK will just not send any events.
|
|
80
105
|
|
|
81
|
-
|
|
106
|
+
### Example
|
|
82
107
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
108
|
+
```javascript
|
|
109
|
+
const logger = makeLogger({
|
|
110
|
+
loggers: [
|
|
111
|
+
{
|
|
112
|
+
type: 'sentry',
|
|
113
|
+
location: 'https://12345678@234567151173.ingest.sentry.io/1234567',
|
|
114
|
+
environment: 'production',
|
|
115
|
+
release: 'v1.0.0',
|
|
116
|
+
level: 'error'
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
More info:
|
|
123
|
+
|
|
124
|
+
* <https://github.com/aandrewww/winston-transport-sentry-node>
|
|
125
|
+
* <https://docs.sentry.io/platforms/node/>
|
|
126
|
+
* <https://docs.sentry.io/platforms/javascript/>
|
|
86
127
|
|
|
87
128
|
## errorFile
|
|
88
129
|
|
|
89
130
|
* location (default: error.log)
|
|
90
131
|
* level (default: error)
|
|
91
132
|
|
|
133
|
+
Logs error-level messages to a file.
|
|
134
|
+
|
|
135
|
+
### Example
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
const logger = makeLogger({
|
|
139
|
+
loggers: [
|
|
140
|
+
{
|
|
141
|
+
type: 'errorFile',
|
|
142
|
+
location: './logs/error.log',
|
|
143
|
+
level: 'error'
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
})
|
|
147
|
+
```
|
|
148
|
+
|
|
92
149
|
## combinedFile
|
|
93
150
|
|
|
94
151
|
* location (default: combined.log)
|
|
95
152
|
|
|
153
|
+
Logs all messages to a file regardless of level.
|
|
154
|
+
|
|
155
|
+
### Example
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
const logger = makeLogger({
|
|
159
|
+
loggers: [
|
|
160
|
+
{
|
|
161
|
+
type: 'combinedFile',
|
|
162
|
+
location: './logs/combined.log'
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
})
|
|
166
|
+
```
|
|
167
|
+
|
|
96
168
|
## console
|
|
97
169
|
|
|
98
170
|
* level (default: trace)
|
|
99
|
-
* debug (default: false, stacktrace in
|
|
100
|
-
* format (default: simple, also
|
|
171
|
+
* debug (default: false, includes stacktrace in output)
|
|
172
|
+
* format (default: simple, also accepts 'json' for structured logging systems)
|
|
173
|
+
* maxDepth (default: 5, maximum depth for nested objects in JSON format only)
|
|
174
|
+
* maxStringLength (default: 1000, maximum length for strings before truncation in JSON format only)
|
|
175
|
+
|
|
176
|
+
### JSON Format Features
|
|
177
|
+
|
|
178
|
+
When using `format: 'json'`, the console logger includes safe JSON serialization that handles:
|
|
179
|
+
|
|
180
|
+
* **Circular references**: Replaced with `[Circular]` to prevent serialization errors
|
|
181
|
+
* **Deep objects**: Objects exceeding `maxDepth` are replaced with `[Max Depth Exceeded]`
|
|
182
|
+
* **Long strings**: Strings exceeding `maxStringLength` are truncated with `... [truncated]`
|
|
183
|
+
* **Functions**: Replaced with `[Function]` since they cannot be serialized
|
|
184
|
+
* **Errors**: Automatically captures message, stack, and metadata
|
|
185
|
+
* **Stackdriver format**: Compatible with Google Cloud Logging (includes severity, time, pid, hostname)
|
|
186
|
+
|
|
187
|
+
### Examples
|
|
188
|
+
|
|
189
|
+
Simple console logging:
|
|
190
|
+
|
|
191
|
+
```javascript
|
|
192
|
+
const logger = makeLogger({
|
|
193
|
+
loggers: [{ type: 'console' }]
|
|
194
|
+
})
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
JSON format with custom depth limits:
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
const logger = makeLogger({
|
|
201
|
+
loggers: [
|
|
202
|
+
{
|
|
203
|
+
type: 'console',
|
|
204
|
+
format: 'json',
|
|
205
|
+
maxDepth: 3,
|
|
206
|
+
maxStringLength: 500,
|
|
207
|
+
debug: true
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
})
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Combining Multiple Loggers
|
|
214
|
+
|
|
215
|
+
You can use multiple loggers simultaneously with different configurations:
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
const logger = makeLogger({
|
|
219
|
+
level: 'debug',
|
|
220
|
+
service: 'my-api',
|
|
221
|
+
loggers: [
|
|
222
|
+
{
|
|
223
|
+
type: 'console',
|
|
224
|
+
format: 'json',
|
|
225
|
+
level: 'debug'
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
type: 'errorFile',
|
|
229
|
+
location: './logs/error.log',
|
|
230
|
+
level: 'error'
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
type: 'combinedFile',
|
|
234
|
+
location: './logs/combined.log'
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
type: 'sentry',
|
|
238
|
+
location: process.env.SENTRY_DSN,
|
|
239
|
+
environment: process.env.NODE_ENV,
|
|
240
|
+
level: 'error'
|
|
241
|
+
}
|
|
242
|
+
]
|
|
243
|
+
})
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
This configuration will:
|
|
247
|
+
|
|
248
|
+
* Log all debug+ messages to console in JSON format
|
|
249
|
+
* Log only errors to `error.log`
|
|
250
|
+
* Log all messages to `combined.log`
|
|
251
|
+
* Send only errors to Sentry
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trojs/logger",
|
|
3
3
|
"description": "Winston logger for TroJS",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.4.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Pieter Wigboldus",
|
|
7
7
|
"url": "https://trojs.org/"
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@trojs/error": "^5.0.0",
|
|
37
37
|
"@trojs/lint": "^0.4.0",
|
|
38
|
-
"eslint": "^
|
|
38
|
+
"eslint": "^10.0.0",
|
|
39
39
|
"globals": "^17.0.0",
|
|
40
40
|
"jscpd": "^4.0.0",
|
|
41
41
|
"prettier": "^3.3.3"
|
package/src/loggers/console.js
CHANGED
|
@@ -158,7 +158,7 @@ export default ({ winston, logger }) => {
|
|
|
158
158
|
winston.format((info) => {
|
|
159
159
|
// Safe JSON serialization with error handling
|
|
160
160
|
try {
|
|
161
|
-
const serialized = JSON.stringify(info, safeJsonReplacer(5, 1000))
|
|
161
|
+
const serialized = JSON.stringify(info, safeJsonReplacer(logger?.maxDepth ?? 5, logger?.maxStringLength ?? 1000))
|
|
162
162
|
return { ...info, [SYMBOL_MESSAGE]: serialized }
|
|
163
163
|
} catch (error) {
|
|
164
164
|
// Fallback for serialization errors
|
|
@@ -85,6 +85,26 @@ export class SentryTransport extends TransportStream {
|
|
|
85
85
|
|
|
86
86
|
const sentryLevel = this.levelsMap[winstonLevel]
|
|
87
87
|
|
|
88
|
+
// Normalize message to string
|
|
89
|
+
let normalizedMessage = message
|
|
90
|
+
if (!normalizedMessage || normalizedMessage === '') {
|
|
91
|
+
// Try to get message from stack or error
|
|
92
|
+
if (meta.stack) {
|
|
93
|
+
normalizedMessage = (meta.stack.split('\n')[0] || '').trim()
|
|
94
|
+
} else if (meta.error instanceof Error) {
|
|
95
|
+
normalizedMessage = meta.error.message || meta.error.toString()
|
|
96
|
+
} else {
|
|
97
|
+
normalizedMessage = 'Empty log message'
|
|
98
|
+
}
|
|
99
|
+
} else if (typeof normalizedMessage !== 'string') {
|
|
100
|
+
// Stringify non-string messages
|
|
101
|
+
try {
|
|
102
|
+
normalizedMessage = JSON.stringify(normalizedMessage)
|
|
103
|
+
} catch {
|
|
104
|
+
normalizedMessage = String(normalizedMessage)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
88
108
|
return Sentry.withScope((scope) => {
|
|
89
109
|
if (tags !== undefined && SentryTransport.isObject(tags)) {
|
|
90
110
|
scope.setTags(tags)
|
|
@@ -100,11 +120,11 @@ export class SentryTransport extends TransportStream {
|
|
|
100
120
|
if (SentryTransport.shouldLogException(sentryLevel)) {
|
|
101
121
|
const error
|
|
102
122
|
= Object.values(info).find((value) => value instanceof Error)
|
|
103
|
-
?? new ExtendedError(info)
|
|
123
|
+
?? new ExtendedError({ ...info, message: normalizedMessage })
|
|
104
124
|
Sentry.captureException(error, { tags, level: sentryLevel })
|
|
105
125
|
} else {
|
|
106
126
|
// Capturing Messages
|
|
107
|
-
Sentry.captureMessage(
|
|
127
|
+
Sentry.captureMessage(normalizedMessage, sentryLevel)
|
|
108
128
|
}
|
|
109
129
|
})
|
|
110
130
|
}
|
|
@@ -19,6 +19,8 @@ import Level from '../enums/level.js'
|
|
|
19
19
|
* @property {number=} sampleRate
|
|
20
20
|
* @property {number=} tracesSampleRate
|
|
21
21
|
* @property {string=} format
|
|
22
|
+
* @property {number=} maxDepth
|
|
23
|
+
* @property {number=} maxStringLength
|
|
22
24
|
*/
|
|
23
25
|
|
|
24
26
|
export default {
|
|
@@ -33,5 +35,7 @@ export default {
|
|
|
33
35
|
'debug?': Boolean,
|
|
34
36
|
'sampleRate?': Number,
|
|
35
37
|
'tracesSampleRate?': Number,
|
|
36
|
-
'format?': String
|
|
38
|
+
'format?': String,
|
|
39
|
+
'maxDepth?': Number,
|
|
40
|
+
'maxStringLength?': Number
|
|
37
41
|
}
|