@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
- Generic logger with intergrations for e.g. Sentry
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
- # level
42
+ ## Configuration
43
+
44
+ ### level
45
+
46
+ default: `info`
30
47
 
31
- default: info
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
- Log only if [`info.level`](#streams-objectmode-and-info-objects) less than or equal to this level
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 see: https://www.npmjs.com/package/winston#logging-levels
58
+ More info: <https://www.npmjs.com/package/winston#logging-levels>
36
59
 
37
- # service
60
+ ### service
38
61
 
39
- default: user-service
62
+ default: `user-service`
40
63
 
41
- # Loggers:
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
- Set of logging targets for `info` messages
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
- Types:
80
+ Available logger types:
55
81
 
56
- * sentry
57
- * errorFile
58
- * combinedFile
59
- * console
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 overruled by the loggers in the `loggers` array.
87
+ **Note:** The default loggers are replaced (not merged) when you provide a `loggers` array.
62
88
 
63
- It use winston transports for all logger types.
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, senty.tracesSampleRate)
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
- More info:
106
+ ### Example
82
107
 
83
- * https://github.com/aandrewww/winston-transport-sentry-node
84
- * https://docs.sentry.io/platforms/node/
85
- * https://docs.sentry.io/platforms/javascript/
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 console)
100
- * format (default: simple, also possible to set to json which is useful for different log systems)
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.2.1",
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": "^9.15.0",
38
+ "eslint": "^10.0.0",
39
39
  "globals": "^17.0.0",
40
40
  "jscpd": "^4.0.0",
41
41
  "prettier": "^3.3.3"
@@ -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(message, sentryLevel)
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
  }