queen-mq 0.12.3 → 0.13.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/client-v2/LOGGING.md +63 -30
- package/client-v2/Queen.js +8 -7
- package/client-v2/buffer/BufferManager.js +12 -23
- package/client-v2/builders/QueueBuilder.js +0 -2
- package/client-v2/consumer/ConsumerManager.js +2 -3
- package/client-v2/http/HttpClient.js +0 -1
- package/client-v2/utils/defaults.js +2 -1
- package/client-v2/utils/logger.js +46 -14
- package/package.json +1 -1
- package/test-v2/auth.js +340 -0
- package/test-v2/logger.js +312 -0
- package/test-v2/push.js +275 -0
- package/test-v2/run.js +7 -1
- package/test-v2/watermark.js +507 -0
package/client-v2/LOGGING.md
CHANGED
|
@@ -2,9 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
The Queen Client V2 includes comprehensive operation logging that captures every significant action performed by the client.
|
|
5
|
+
The Queen Client V2 includes comprehensive operation logging that captures every significant action performed by the client. You can either:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
1. **Inject a custom logger** (pino, winston, bunyan, etc.) via the `logger` config option -- recommended for production.
|
|
8
|
+
2. **Use the built-in console logger** gated by the `QUEEN_CLIENT_LOG` environment variable -- handy for quick debugging.
|
|
9
|
+
|
|
10
|
+
## Custom Logger (Recommended)
|
|
11
|
+
|
|
12
|
+
Pass any logger instance that implements `info()`, `warn()`, and `error()` methods. When a custom logger is configured, it is always active (level filtering is controlled by your logger, not by `QUEEN_CLIENT_LOG`).
|
|
13
|
+
|
|
14
|
+
### Pino
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
import pino from 'pino'
|
|
18
|
+
import { Queen } from '@punkish/queen'
|
|
19
|
+
|
|
20
|
+
const queen = new Queen({
|
|
21
|
+
urls: ['http://localhost:6632'],
|
|
22
|
+
logger: pino()
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Winston
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
import winston from 'winston'
|
|
30
|
+
import { Queen } from '@punkish/queen'
|
|
31
|
+
|
|
32
|
+
const winstonLogger = winston.createLogger({
|
|
33
|
+
level: 'info',
|
|
34
|
+
transports: [new winston.transports.Console()]
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const queen = new Queen({
|
|
38
|
+
urls: ['http://localhost:6632'],
|
|
39
|
+
logger: winstonLogger
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Custom implementation
|
|
44
|
+
|
|
45
|
+
Any object with `info`, `warn`, and `error` methods works:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
const queen = new Queen({
|
|
49
|
+
urls: ['http://localhost:6632'],
|
|
50
|
+
logger: {
|
|
51
|
+
info: (msg) => myLogSink('INFO', msg),
|
|
52
|
+
warn: (msg) => myLogSink('WARN', msg),
|
|
53
|
+
error: (msg) => myLogSink('ERROR', msg)
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The `debug()` method is optional. If your logger provides it, verbose internal details (buffer flush progress, server responses, etc.) will be emitted at `debug` level. Otherwise they fall back to `info`.
|
|
59
|
+
|
|
60
|
+
## Built-in Console Logger
|
|
61
|
+
|
|
62
|
+
If no custom logger is provided, the built-in console logger can be enabled via environment variable:
|
|
8
63
|
|
|
9
64
|
```bash
|
|
10
65
|
export QUEEN_CLIENT_LOG=true
|
|
@@ -158,11 +213,13 @@ pm2 restart my-app
|
|
|
158
213
|
|
|
159
214
|
## Performance Impact
|
|
160
215
|
|
|
161
|
-
- **
|
|
162
|
-
- **
|
|
216
|
+
- **No logger configured + `QUEEN_CLIENT_LOG` unset (default)**: Zero performance impact - all logging calls are no-ops
|
|
217
|
+
- **Built-in console logger enabled**: Minimal impact
|
|
218
|
+
- **Custom logger**: Depends on the logger implementation; pino in async mode has negligible overhead
|
|
163
219
|
|
|
164
220
|
## Log Levels
|
|
165
221
|
|
|
222
|
+
- **DEBUG**: Verbose operational details (buffer flush progress, extracted message counts, server responses)
|
|
166
223
|
- **INFO**: Normal operations (most logs)
|
|
167
224
|
- **WARN**: Recoverable issues (retries, failover, network errors)
|
|
168
225
|
- **ERROR**: Operation failures (push failed, ack failed, etc.)
|
|
@@ -191,31 +248,7 @@ QUEEN_CLIENT_LOG=true node app.js 2>&1 | grep "pop"
|
|
|
191
248
|
|
|
192
249
|
## Integration with Log Aggregation
|
|
193
250
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
### Winston
|
|
197
|
-
```javascript
|
|
198
|
-
import winston from 'winston'
|
|
199
|
-
|
|
200
|
-
// Redirect console.log to Winston
|
|
201
|
-
console.log = winston.info
|
|
202
|
-
console.error = winston.error
|
|
203
|
-
console.warn = winston.warn
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### Pino
|
|
207
|
-
```javascript
|
|
208
|
-
import pino from 'pino'
|
|
209
|
-
const logger = pino()
|
|
210
|
-
|
|
211
|
-
console.log = (msg) => logger.info(msg)
|
|
212
|
-
console.error = (msg) => logger.error(msg)
|
|
213
|
-
console.warn = (msg) => logger.warn(msg)
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Datadog, CloudWatch, etc.
|
|
217
|
-
|
|
218
|
-
The ISO 8601 timestamps and JSON format are compatible with most log aggregation services.
|
|
251
|
+
When using a custom logger, integration with log aggregation services (Datadog, CloudWatch, Elastic, etc.) depends on your logger's configuration, not on Queen. For example, pino outputs NDJSON by default which is compatible with most log aggregation pipelines out of the box.
|
|
219
252
|
|
|
220
253
|
## Best Practices
|
|
221
254
|
|
|
@@ -236,5 +269,5 @@ The logging system is implemented in `utils/logger.js` and imported by all major
|
|
|
236
269
|
- `QueueBuilder.js` - Queue operations
|
|
237
270
|
- `TransactionBuilder.js` - Atomic transactions
|
|
238
271
|
|
|
239
|
-
|
|
272
|
+
When a custom logger is configured via `new Queen({ logger })`, all internal logging is routed through it. When no custom logger is provided, logging falls back to the built-in console logger gated by `QUEEN_CLIENT_LOG`.
|
|
240
273
|
|
package/client-v2/Queen.js
CHANGED
|
@@ -23,6 +23,11 @@ export class Queen {
|
|
|
23
23
|
#admin = null
|
|
24
24
|
|
|
25
25
|
constructor(config = {}) {
|
|
26
|
+
// Configure custom logger before anything else
|
|
27
|
+
if (config && typeof config === 'object' && !Array.isArray(config) && config.logger) {
|
|
28
|
+
logger.configure(config.logger)
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
logger.log('Queen.constructor', { config: typeof config === 'object' && !Array.isArray(config) ? { ...config, urls: config.urls?.length || 0 } : { type: typeof config } })
|
|
27
32
|
|
|
28
33
|
// Normalize config
|
|
@@ -117,17 +122,17 @@ export class Queen {
|
|
|
117
122
|
|
|
118
123
|
let signalReceivedCount = 0;
|
|
119
124
|
const shutdown = async (signal) => {
|
|
120
|
-
|
|
125
|
+
logger.log('Queen.shutdown', { signal })
|
|
121
126
|
try {
|
|
122
127
|
signalReceivedCount++;
|
|
123
128
|
if (signalReceivedCount > 1) {
|
|
124
|
-
|
|
129
|
+
logger.warn('Queen.shutdown', 'Received multiple shutdown signals, exiting immediately')
|
|
125
130
|
process.exit(1)
|
|
126
131
|
}
|
|
127
132
|
await this.close()
|
|
128
133
|
process.exit(0)
|
|
129
134
|
} catch (error) {
|
|
130
|
-
|
|
135
|
+
logger.error('Queen.shutdown', { error: error.message })
|
|
131
136
|
process.exit(1)
|
|
132
137
|
}
|
|
133
138
|
}
|
|
@@ -480,16 +485,13 @@ export class Queen {
|
|
|
480
485
|
|
|
481
486
|
async close() {
|
|
482
487
|
logger.log('Queen.close', 'Starting shutdown')
|
|
483
|
-
console.log('Closing Queen client...')
|
|
484
488
|
|
|
485
489
|
// Flush all buffers
|
|
486
490
|
try {
|
|
487
491
|
await this.#bufferManager.flushAllBuffers()
|
|
488
492
|
logger.log('Queen.close', 'All buffers flushed')
|
|
489
|
-
console.log('All buffers flushed')
|
|
490
493
|
} catch (error) {
|
|
491
494
|
logger.error('Queen.close', { error: error.message, phase: 'buffer-flush' })
|
|
492
|
-
console.warn('Error flushing buffers:', error)
|
|
493
495
|
}
|
|
494
496
|
|
|
495
497
|
// Cleanup buffer manager
|
|
@@ -502,7 +504,6 @@ export class Queen {
|
|
|
502
504
|
this.#shutdownHandlers = []
|
|
503
505
|
|
|
504
506
|
logger.log('Queen.close', 'Client closed successfully')
|
|
505
|
-
console.log('Queen client closed')
|
|
506
507
|
}
|
|
507
508
|
}
|
|
508
509
|
|
|
@@ -36,13 +36,11 @@ export class BufferManager {
|
|
|
36
36
|
async #flushBuffer(queueAddress) {
|
|
37
37
|
const buffer = this.#buffers.get(queueAddress)
|
|
38
38
|
if (!buffer || buffer.messageCount === 0) {
|
|
39
|
-
logger.
|
|
40
|
-
console.log(`No buffer or empty buffer for ${queueAddress}`)
|
|
39
|
+
logger.debug('BufferManager.flushBuffer', { queueAddress, status: 'empty' })
|
|
41
40
|
return
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
logger.log('BufferManager.flushBuffer', { queueAddress, messageCount: buffer.messageCount })
|
|
45
|
-
console.log(`Flushing ${buffer.messageCount} messages for ${queueAddress}`)
|
|
46
44
|
buffer.setFlushing(true)
|
|
47
45
|
|
|
48
46
|
// Create a promise for this flush and track it
|
|
@@ -50,13 +48,13 @@ export class BufferManager {
|
|
|
50
48
|
try {
|
|
51
49
|
const messages = buffer.extractMessages()
|
|
52
50
|
|
|
53
|
-
|
|
51
|
+
logger.debug('BufferManager.flushBuffer', { queueAddress, extracted: messages.length })
|
|
54
52
|
|
|
55
53
|
if (messages.length === 0) return
|
|
56
54
|
|
|
57
55
|
// Send to server
|
|
58
56
|
const result = await this.#httpClient.post('/api/v1/push', { items: messages })
|
|
59
|
-
|
|
57
|
+
logger.debug('BufferManager.flushBuffer', { queueAddress, serverResponse: result ? `${result.length || 'N/A'} items` : 'null' })
|
|
60
58
|
|
|
61
59
|
this.#flushCount++
|
|
62
60
|
logger.log('BufferManager.flushBuffer', { queueAddress, status: 'success', messagesSent: messages.length })
|
|
@@ -66,7 +64,6 @@ export class BufferManager {
|
|
|
66
64
|
|
|
67
65
|
} catch (error) {
|
|
68
66
|
logger.error('BufferManager.flushBuffer', { queueAddress, error: error.message })
|
|
69
|
-
console.error(`Flush error for ${queueAddress}:`, error.message)
|
|
70
67
|
buffer.setFlushing(false)
|
|
71
68
|
throw error
|
|
72
69
|
} finally {
|
|
@@ -94,13 +91,13 @@ export class BufferManager {
|
|
|
94
91
|
try {
|
|
95
92
|
const messages = buffer.extractMessages(batchSize)
|
|
96
93
|
|
|
97
|
-
|
|
94
|
+
logger.debug('BufferManager.flushBufferBatch', { queueAddress, extracted: messages.length })
|
|
98
95
|
|
|
99
96
|
if (messages.length === 0) return
|
|
100
97
|
|
|
101
98
|
// Send to server
|
|
102
99
|
const result = await this.#httpClient.post('/api/v1/push', { items: messages })
|
|
103
|
-
|
|
100
|
+
logger.debug('BufferManager.flushBufferBatch', { queueAddress, serverResponse: result ? `${result.length || 'N/A'} items` : 'null' })
|
|
104
101
|
|
|
105
102
|
this.#flushCount++
|
|
106
103
|
|
|
@@ -112,7 +109,7 @@ export class BufferManager {
|
|
|
112
109
|
}
|
|
113
110
|
|
|
114
111
|
} catch (error) {
|
|
115
|
-
|
|
112
|
+
logger.error('BufferManager.flushBufferBatch', { queueAddress, error: error.message })
|
|
116
113
|
buffer.setFlushing(false)
|
|
117
114
|
throw error
|
|
118
115
|
} finally {
|
|
@@ -129,14 +126,10 @@ export class BufferManager {
|
|
|
129
126
|
|
|
130
127
|
async flushBuffer(queueAddress) {
|
|
131
128
|
logger.log('BufferManager.flushBuffer', { queueAddress, activeBuffers: this.#buffers.size, pendingFlushes: this.#pendingFlushes.size })
|
|
132
|
-
console.log(`flushBuffer called for address: ${queueAddress}`)
|
|
133
|
-
console.log(`Active buffers:`, Array.from(this.#buffers.keys()))
|
|
134
|
-
console.log(`Pending flushes:`, this.#pendingFlushes.size)
|
|
135
129
|
|
|
136
130
|
const buffer = this.#buffers.get(queueAddress)
|
|
137
131
|
if (!buffer) {
|
|
138
|
-
logger.
|
|
139
|
-
console.log(`No buffer found for ${queueAddress}`)
|
|
132
|
+
logger.debug('BufferManager.flushBuffer', { queueAddress, status: 'not-found' })
|
|
140
133
|
await this.#waitForPendingFlushes()
|
|
141
134
|
return
|
|
142
135
|
}
|
|
@@ -149,22 +142,20 @@ export class BufferManager {
|
|
|
149
142
|
|
|
150
143
|
// Flush all messages in batches
|
|
151
144
|
while (buffer.messageCount > 0) {
|
|
152
|
-
|
|
145
|
+
logger.debug('BufferManager.flushBuffer', { queueAddress, batchSize, remaining: buffer.messageCount })
|
|
153
146
|
await this.#flushBufferBatch(queueAddress, batchSize)
|
|
154
147
|
}
|
|
155
148
|
|
|
156
149
|
// Wait for all pending flushes to complete
|
|
157
150
|
await this.#waitForPendingFlushes()
|
|
158
151
|
|
|
159
|
-
|
|
152
|
+
logger.debug('BufferManager.flushBuffer', { queueAddress, status: 'completed' })
|
|
160
153
|
}
|
|
161
154
|
|
|
162
155
|
async flushAllBuffers() {
|
|
156
|
+
// Get all queue addresses that have buffers
|
|
163
157
|
const queueAddresses = Array.from(this.#buffers.keys())
|
|
164
158
|
logger.log('BufferManager.flushAllBuffers', { bufferCount: queueAddresses.length, pendingFlushes: this.#pendingFlushes.size })
|
|
165
|
-
console.log(`flushAllBuffers called, pending flushes: ${this.#pendingFlushes.size}`)
|
|
166
|
-
|
|
167
|
-
// Get all queue addresses that have buffers
|
|
168
159
|
|
|
169
160
|
// Flush each buffer in batches
|
|
170
161
|
for (const queueAddress of queueAddresses) {
|
|
@@ -172,15 +163,14 @@ export class BufferManager {
|
|
|
172
163
|
}
|
|
173
164
|
|
|
174
165
|
logger.log('BufferManager.flushAllBuffers', { status: 'completed' })
|
|
175
|
-
console.log(`flushAllBuffers completed`)
|
|
176
166
|
}
|
|
177
167
|
|
|
178
168
|
async #waitForPendingFlushes() {
|
|
179
169
|
if (this.#pendingFlushes.size === 0) return
|
|
180
170
|
|
|
181
|
-
|
|
171
|
+
logger.debug('BufferManager.waitForPendingFlushes', { count: this.#pendingFlushes.size })
|
|
182
172
|
await Promise.all(Array.from(this.#pendingFlushes))
|
|
183
|
-
|
|
173
|
+
logger.debug('BufferManager.waitForPendingFlushes', { status: 'completed' })
|
|
184
174
|
}
|
|
185
175
|
|
|
186
176
|
getStats() {
|
|
@@ -212,4 +202,3 @@ export class BufferManager {
|
|
|
212
202
|
this.#buffers.clear()
|
|
213
203
|
}
|
|
214
204
|
}
|
|
215
|
-
|
|
@@ -306,7 +306,6 @@ export class QueueBuilder {
|
|
|
306
306
|
} catch (error) {
|
|
307
307
|
// Return empty array on error instead of throwing
|
|
308
308
|
logger.error('QueueBuilder.pop', { error: error.message })
|
|
309
|
-
console.warn('Pop failed:', error.message)
|
|
310
309
|
return []
|
|
311
310
|
}
|
|
312
311
|
}
|
|
@@ -745,7 +744,6 @@ class DLQBuilder {
|
|
|
745
744
|
return result || { messages: [], total: 0 }
|
|
746
745
|
} catch (error) {
|
|
747
746
|
logger.error('DLQBuilder.get', { error: error.message })
|
|
748
|
-
console.warn('DLQ query failed:', error.message)
|
|
749
747
|
return { messages: [], total: 0 }
|
|
750
748
|
}
|
|
751
749
|
}
|
|
@@ -222,7 +222,6 @@ export class ConsumerManager {
|
|
|
222
222
|
|
|
223
223
|
if (isNetworkError) {
|
|
224
224
|
logger.warn('ConsumerManager.worker', { workerId, error: 'network', message: error.message })
|
|
225
|
-
console.warn(`Worker ${workerId}: Network error - ${error.message}`)
|
|
226
225
|
// Wait before retry
|
|
227
226
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
228
227
|
continue
|
|
@@ -296,7 +295,7 @@ export class ConsumerManager {
|
|
|
296
295
|
try {
|
|
297
296
|
await this.#queen.renew(messages)
|
|
298
297
|
} catch (error) {
|
|
299
|
-
|
|
298
|
+
logger.error('ConsumerManager.leaseRenewal', { error: error.message })
|
|
300
299
|
}
|
|
301
300
|
}, intervalMillis)
|
|
302
301
|
}
|
|
@@ -367,7 +366,7 @@ export class ConsumerManager {
|
|
|
367
366
|
error: error.message,
|
|
368
367
|
phase: 'trace-failed'
|
|
369
368
|
})
|
|
370
|
-
|
|
369
|
+
logger.warn('ConsumerManager.trace', { transactionId: message.transactionId, error: error.message })
|
|
371
370
|
|
|
372
371
|
return { success: false, error: error.message }
|
|
373
372
|
}
|
|
@@ -196,7 +196,6 @@ export class HttpClient {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
logger.warn('HttpClient.failover', { url, method, path, error: error.message })
|
|
199
|
-
console.warn(`Request failed for ${url}: ${method} ${path} - ${error.message}`)
|
|
200
199
|
|
|
201
200
|
// Don't retry on client errors (4xx)
|
|
202
201
|
if (error.status && error.status >= 400 && error.status < 500) {
|
|
@@ -16,7 +16,8 @@ export const CLIENT_DEFAULTS = {
|
|
|
16
16
|
healthRetryAfterMillis: 5000, // Retry unhealthy backends after 5 seconds
|
|
17
17
|
bearerToken: null, // Bearer token for proxy authentication
|
|
18
18
|
headers: {}, // Custom headers to include in every request
|
|
19
|
-
handleSignals: true
|
|
19
|
+
handleSignals: true, // Register SIGINT/SIGTERM handlers (disable when used as a library)
|
|
20
|
+
logger: null // Custom logger instance (must implement info/warn/error)
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export const QUEUE_DEFAULTS = {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Logger utility for Queen Client v2
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
*
|
|
4
|
+
* Supports pluggable logger backends (pino, winston, bunyan, etc.).
|
|
5
|
+
* When no custom logger is configured, falls back to console-based logging
|
|
6
|
+
* gated by the QUEEN_CLIENT_LOG environment variable (Node.js)
|
|
7
|
+
* or window.QUEEN_CLIENT_LOG (Browser).
|
|
5
8
|
*/
|
|
6
9
|
|
|
7
10
|
const LOG_ENABLED = (() => {
|
|
@@ -16,9 +19,8 @@ const LOG_ENABLED = (() => {
|
|
|
16
19
|
return false
|
|
17
20
|
})()
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*/
|
|
22
|
+
let customLogger = null
|
|
23
|
+
|
|
22
24
|
function getTimestamp() {
|
|
23
25
|
return new Date().toISOString()
|
|
24
26
|
}
|
|
@@ -33,25 +35,56 @@ function formatLog(operation, details, level = 'INFO') {
|
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
/**
|
|
36
|
-
*
|
|
38
|
+
* Configure a custom logger backend.
|
|
39
|
+
* The logger must implement: info(msg), warn(msg), error(msg).
|
|
40
|
+
* debug(msg) is optional and falls back to info(msg) if missing.
|
|
41
|
+
* When a custom logger is set, it is always active (no env var gating).
|
|
42
|
+
* @param {object} logger - Logger instance (e.g. pino(), winston.createLogger())
|
|
37
43
|
*/
|
|
44
|
+
export function configure(logger) {
|
|
45
|
+
if (logger && typeof logger.info !== 'function') {
|
|
46
|
+
throw new Error('Custom logger must implement info(), warn(), and error() methods')
|
|
47
|
+
}
|
|
48
|
+
customLogger = logger
|
|
49
|
+
}
|
|
50
|
+
|
|
38
51
|
export function log(operation, details) {
|
|
52
|
+
if (customLogger) {
|
|
53
|
+
const detailsStr = typeof details === 'object' ? JSON.stringify(details) : details
|
|
54
|
+
customLogger.info(`[${operation}] ${detailsStr}`)
|
|
55
|
+
return
|
|
56
|
+
}
|
|
39
57
|
if (!LOG_ENABLED) return
|
|
40
58
|
console.log(formatLog(operation, details))
|
|
41
59
|
}
|
|
42
60
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
61
|
+
export function debug(operation, details) {
|
|
62
|
+
if (customLogger) {
|
|
63
|
+
const detailsStr = typeof details === 'object' ? JSON.stringify(details) : details
|
|
64
|
+
const fn = customLogger.debug || customLogger.info
|
|
65
|
+
fn.call(customLogger, `[${operation}] ${detailsStr}`)
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
if (!LOG_ENABLED) return
|
|
69
|
+
console.log(formatLog(operation, details, 'DEBUG'))
|
|
70
|
+
}
|
|
71
|
+
|
|
46
72
|
export function warn(operation, details) {
|
|
73
|
+
if (customLogger) {
|
|
74
|
+
const detailsStr = typeof details === 'object' ? JSON.stringify(details) : details
|
|
75
|
+
customLogger.warn(`[${operation}] ${detailsStr}`)
|
|
76
|
+
return
|
|
77
|
+
}
|
|
47
78
|
if (!LOG_ENABLED) return
|
|
48
79
|
console.warn(formatLog(operation, details, 'WARN'))
|
|
49
80
|
}
|
|
50
81
|
|
|
51
|
-
/**
|
|
52
|
-
* Log an error
|
|
53
|
-
*/
|
|
54
82
|
export function error(operation, details) {
|
|
83
|
+
if (customLogger) {
|
|
84
|
+
const detailsStr = typeof details === 'object' ? JSON.stringify(details) : details
|
|
85
|
+
customLogger.error(`[${operation}] ${detailsStr}`)
|
|
86
|
+
return
|
|
87
|
+
}
|
|
55
88
|
if (!LOG_ENABLED) return
|
|
56
89
|
console.error(formatLog(operation, details, 'ERROR'))
|
|
57
90
|
}
|
|
@@ -60,6 +93,5 @@ export function error(operation, details) {
|
|
|
60
93
|
* Check if logging is enabled
|
|
61
94
|
*/
|
|
62
95
|
export function isEnabled() {
|
|
63
|
-
return LOG_ENABLED
|
|
96
|
+
return customLogger != null || LOG_ENABLED
|
|
64
97
|
}
|
|
65
|
-
|