azify-logger 1.0.29 → 1.0.31
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 +144 -10
- package/middleware-express.js +73 -24
- package/middleware-fastify.js +142 -55
- package/middleware-restify.js +59 -10
- package/package.json +17 -4
- package/register-otel.js +110 -2
- package/register.js +214 -95
- package/scripts/redis-worker.js +37 -11
- package/server.js +132 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azify-logger",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.31",
|
|
4
4
|
"description": "Azify Logger Client - Centralized logging for OpenSearch",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -17,7 +17,18 @@
|
|
|
17
17
|
"docker:up": "docker-compose up -d",
|
|
18
18
|
"docker:down": "docker-compose down",
|
|
19
19
|
"docker:logs": "docker-compose logs -f",
|
|
20
|
-
"worker": "node scripts/redis-worker.js"
|
|
20
|
+
"worker": "node scripts/redis-worker.js",
|
|
21
|
+
"validate:retention": "node scripts/validate-retention.js",
|
|
22
|
+
"inspect:zip": "node scripts/inspect-zip.js",
|
|
23
|
+
"retention": "node scripts/retention-manager.js",
|
|
24
|
+
"list:blob": "node scripts/list-blob-files.js",
|
|
25
|
+
"list:blob:recent": "node scripts/download-blob-zip.js",
|
|
26
|
+
"check:old-logs": "node scripts/check-old-logs.js",
|
|
27
|
+
"validate:blob": "node scripts/validate-blob-zip.js",
|
|
28
|
+
"validate:blob:keep": "KEEP_VALIDATION_FILES=true node scripts/validate-blob-zip.js",
|
|
29
|
+
"download:blob": "node scripts/download-blob-zip.js",
|
|
30
|
+
"reimport:logs": "node scripts/reimport-logs.js",
|
|
31
|
+
"check:server-time": "node -e \"const now = new Date(); const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; console.log('🕐 Hora do servidor:', now.toLocaleString('pt-BR', {timeZone: tz})); console.log('🌍 Timezone:', tz); console.log('🕐 Hora em São Paulo:', now.toLocaleString('pt-BR', {timeZone: 'America/Sao_Paulo'})); console.log('\\n💡 Configure RETENTION_RUN_AT_HOUR com a hora do servidor (0-23)');\""
|
|
21
32
|
},
|
|
22
33
|
"keywords": [
|
|
23
34
|
"logging",
|
|
@@ -28,16 +39,19 @@
|
|
|
28
39
|
"author": "Azify",
|
|
29
40
|
"license": "MIT",
|
|
30
41
|
"dependencies": {
|
|
42
|
+
"@azure/storage-blob": "^12.17.0",
|
|
31
43
|
"@opentelemetry/api": "1.0.4",
|
|
32
44
|
"@opentelemetry/auto-instrumentations-node": "0.27.0",
|
|
33
45
|
"@opentelemetry/core": "1.0.1",
|
|
34
|
-
"@opentelemetry/exporter-trace-otlp-http": "0.27.0",
|
|
46
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.27.0",
|
|
35
47
|
"@opentelemetry/instrumentation-express": "0.27.0",
|
|
36
48
|
"@opentelemetry/instrumentation-http": "0.27.0",
|
|
37
49
|
"@opentelemetry/instrumentation-restify": "0.27.0",
|
|
38
50
|
"@opentelemetry/resources": "1.0.1",
|
|
39
51
|
"@opentelemetry/sdk-node": "0.27.0",
|
|
40
52
|
"@opentelemetry/semantic-conventions": "1.0.1",
|
|
53
|
+
"adm-zip": "^0.5.16",
|
|
54
|
+
"archiver": "^6.0.1",
|
|
41
55
|
"axios": "^1.6.0",
|
|
42
56
|
"cors": "^2.8.5",
|
|
43
57
|
"express": "^4.18.2",
|
|
@@ -55,7 +69,6 @@
|
|
|
55
69
|
"@opentelemetry/resources": "1.0.1",
|
|
56
70
|
"@opentelemetry/semantic-conventions": "1.0.1",
|
|
57
71
|
"@opentelemetry/sdk-node": "0.27.0",
|
|
58
|
-
"@opentelemetry/exporter-trace-otlp-http": "0.27.0",
|
|
59
72
|
"@opentelemetry/auto-instrumentations-node": "0.27.0"
|
|
60
73
|
},
|
|
61
74
|
"engines": {
|
package/register-otel.js
CHANGED
|
@@ -3,6 +3,8 @@ try {
|
|
|
3
3
|
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http')
|
|
4
4
|
const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express')
|
|
5
5
|
const { RestifyInstrumentation } = require('@opentelemetry/instrumentation-restify')
|
|
6
|
+
const { Resource } = require('@opentelemetry/resources')
|
|
7
|
+
const { SEMRESATTRS_SERVICE_NAME, SEMRESATTRS_SERVICE_VERSION } = require('@opentelemetry/semantic-conventions')
|
|
6
8
|
|
|
7
9
|
const serviceName = process.env.OTEL_SERVICE_NAME || process.env.APP_NAME || 'app'
|
|
8
10
|
const serviceVersion = process.env.OTEL_SERVICE_VERSION || '1.0.0'
|
|
@@ -10,6 +12,12 @@ try {
|
|
|
10
12
|
process.env.OTEL_SERVICE_NAME = serviceName
|
|
11
13
|
process.env.OTEL_SERVICE_VERSION = serviceVersion
|
|
12
14
|
|
|
15
|
+
const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
|
|
16
|
+
if (otlpEndpoint) {
|
|
17
|
+
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = otlpEndpoint
|
|
18
|
+
process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = otlpEndpoint
|
|
19
|
+
}
|
|
20
|
+
|
|
13
21
|
let collectorHost = null
|
|
14
22
|
let collectorPath = null
|
|
15
23
|
try {
|
|
@@ -62,9 +70,109 @@ try {
|
|
|
62
70
|
enabled: true
|
|
63
71
|
})
|
|
64
72
|
|
|
73
|
+
let traceExporter = null
|
|
74
|
+
if (otlpEndpoint) {
|
|
75
|
+
try {
|
|
76
|
+
let endpointUrl
|
|
77
|
+
try {
|
|
78
|
+
endpointUrl = new URL(otlpEndpoint)
|
|
79
|
+
} catch (urlErr) {
|
|
80
|
+
throw new Error(`URL inválida: ${otlpEndpoint}`)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const http = require('http')
|
|
84
|
+
const url = new URL(otlpEndpoint)
|
|
85
|
+
|
|
86
|
+
traceExporter = {
|
|
87
|
+
export: function(spans, resultCallback) {
|
|
88
|
+
if (!spans || spans.length === 0) {
|
|
89
|
+
if (resultCallback) resultCallback({ code: 0 })
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const resourceSpans = [{
|
|
95
|
+
resource: {
|
|
96
|
+
attributes: [
|
|
97
|
+
{ key: 'service.name', value: { stringValue: serviceName } },
|
|
98
|
+
{ key: 'service.version', value: { stringValue: serviceVersion } }
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
scopeSpans: [{
|
|
102
|
+
spans: spans.map(span => {
|
|
103
|
+
const ctx = span.spanContext()
|
|
104
|
+
return {
|
|
105
|
+
traceId: ctx.traceId.replace(/-/g, '').padStart(32, '0').substring(0, 32),
|
|
106
|
+
spanId: ctx.spanId.replace(/-/g, '').padStart(16, '0').substring(0, 16),
|
|
107
|
+
name: span.name || 'span',
|
|
108
|
+
kind: span.kind || 1,
|
|
109
|
+
startTimeUnixNano: String(span.startTime?.[0] * 1e9 + (span.startTime?.[1] || 0) || Date.now() * 1e6),
|
|
110
|
+
endTimeUnixNano: String(span.endTime?.[0] * 1e9 + (span.endTime?.[1] || 0) || Date.now() * 1e6),
|
|
111
|
+
attributes: Object.entries(span.attributes || {}).map(([k, v]) => ({
|
|
112
|
+
key: k,
|
|
113
|
+
value: { stringValue: String(v) }
|
|
114
|
+
}))
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
}]
|
|
118
|
+
}]
|
|
119
|
+
|
|
120
|
+
const payload = JSON.stringify({ resourceSpans })
|
|
121
|
+
|
|
122
|
+
const options = {
|
|
123
|
+
hostname: url.hostname,
|
|
124
|
+
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
125
|
+
path: url.pathname,
|
|
126
|
+
method: 'POST',
|
|
127
|
+
headers: {
|
|
128
|
+
'Content-Type': 'application/json',
|
|
129
|
+
'Content-Length': Buffer.byteLength(payload)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const req = http.request(options, (res) => {
|
|
134
|
+
let data = ''
|
|
135
|
+
res.on('data', (chunk) => { data += chunk })
|
|
136
|
+
res.on('end', () => {
|
|
137
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
138
|
+
if (resultCallback) resultCallback({ code: 0 })
|
|
139
|
+
} else {
|
|
140
|
+
if (resultCallback) resultCallback({ code: 1, error: new Error(`HTTP ${res.statusCode}`) })
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
req.on('error', (err) => {
|
|
146
|
+
if (resultCallback) resultCallback({ code: 1, error: err })
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
req.write(payload)
|
|
150
|
+
req.end()
|
|
151
|
+
} catch (err) {
|
|
152
|
+
if (resultCallback) resultCallback({ code: 1, error: err })
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
shutdown: function() {
|
|
156
|
+
return Promise.resolve()
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
} catch (err) {
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let spanProcessor = null
|
|
165
|
+
if (traceExporter) {
|
|
166
|
+
const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base')
|
|
167
|
+
spanProcessor = new SimpleSpanProcessor(traceExporter)
|
|
168
|
+
}
|
|
169
|
+
|
|
65
170
|
const sdk = new NodeSDK({
|
|
66
|
-
|
|
67
|
-
|
|
171
|
+
resource: new Resource({
|
|
172
|
+
[SEMRESATTRS_SERVICE_NAME]: serviceName,
|
|
173
|
+
[SEMRESATTRS_SERVICE_VERSION]: serviceVersion
|
|
174
|
+
}),
|
|
175
|
+
spanProcessor,
|
|
68
176
|
instrumentations: [
|
|
69
177
|
httpInstrumentation,
|
|
70
178
|
expressInstrumentation,
|
package/register.js
CHANGED
|
@@ -175,14 +175,17 @@ try {
|
|
|
175
175
|
|
|
176
176
|
logger.info = function(obj, msg, ...args) {
|
|
177
177
|
const ctx = getRequestContext()
|
|
178
|
-
|
|
178
|
+
const otelCtx = !ctx || !ctx.traceId ? getOtelTraceContext() : null
|
|
179
|
+
const traceCtx = ctx || otelCtx
|
|
180
|
+
|
|
181
|
+
if (traceCtx && traceCtx.traceId) {
|
|
179
182
|
if (typeof obj === 'object' && obj !== null) {
|
|
180
|
-
obj.traceId =
|
|
181
|
-
obj.spanId =
|
|
182
|
-
obj.parentSpanId =
|
|
183
|
-
obj.requestId =
|
|
183
|
+
obj.traceId = traceCtx.traceId
|
|
184
|
+
obj.spanId = traceCtx.spanId
|
|
185
|
+
obj.parentSpanId = traceCtx.parentSpanId
|
|
186
|
+
obj.requestId = traceCtx.requestId || ctx?.requestId
|
|
184
187
|
} else {
|
|
185
|
-
obj = { traceId:
|
|
188
|
+
obj = { traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId, msg: obj }
|
|
186
189
|
}
|
|
187
190
|
}
|
|
188
191
|
return originalInfo.call(this, obj, msg, ...args)
|
|
@@ -190,14 +193,17 @@ try {
|
|
|
190
193
|
|
|
191
194
|
logger.error = function(obj, msg, ...args) {
|
|
192
195
|
const ctx = getRequestContext()
|
|
193
|
-
|
|
196
|
+
const otelCtx = !ctx || !ctx.traceId ? getOtelTraceContext() : null
|
|
197
|
+
const traceCtx = ctx || otelCtx
|
|
198
|
+
|
|
199
|
+
if (traceCtx && traceCtx.traceId) {
|
|
194
200
|
if (typeof obj === 'object' && obj !== null) {
|
|
195
|
-
obj.traceId =
|
|
196
|
-
obj.spanId =
|
|
197
|
-
obj.parentSpanId =
|
|
198
|
-
obj.requestId =
|
|
201
|
+
obj.traceId = traceCtx.traceId
|
|
202
|
+
obj.spanId = traceCtx.spanId
|
|
203
|
+
obj.parentSpanId = traceCtx.parentSpanId
|
|
204
|
+
obj.requestId = traceCtx.requestId || ctx?.requestId
|
|
199
205
|
} else {
|
|
200
|
-
obj = { traceId:
|
|
206
|
+
obj = { traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId, msg: obj }
|
|
201
207
|
}
|
|
202
208
|
}
|
|
203
209
|
return originalError.call(this, obj, msg, ...args)
|
|
@@ -205,14 +211,17 @@ try {
|
|
|
205
211
|
|
|
206
212
|
logger.warn = function(obj, msg, ...args) {
|
|
207
213
|
const ctx = getRequestContext()
|
|
208
|
-
|
|
214
|
+
const otelCtx = !ctx || !ctx.traceId ? getOtelTraceContext() : null
|
|
215
|
+
const traceCtx = ctx || otelCtx
|
|
216
|
+
|
|
217
|
+
if (traceCtx && traceCtx.traceId) {
|
|
209
218
|
if (typeof obj === 'object' && obj !== null) {
|
|
210
|
-
obj.traceId =
|
|
211
|
-
obj.spanId =
|
|
212
|
-
obj.parentSpanId =
|
|
213
|
-
obj.requestId =
|
|
219
|
+
obj.traceId = traceCtx.traceId
|
|
220
|
+
obj.spanId = traceCtx.spanId
|
|
221
|
+
obj.parentSpanId = traceCtx.parentSpanId
|
|
222
|
+
obj.requestId = traceCtx.requestId || ctx?.requestId
|
|
214
223
|
} else {
|
|
215
|
-
obj = { traceId:
|
|
224
|
+
obj = { traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId, msg: obj }
|
|
216
225
|
}
|
|
217
226
|
}
|
|
218
227
|
return originalWarn.call(this, obj, msg, ...args)
|
|
@@ -220,14 +229,17 @@ try {
|
|
|
220
229
|
|
|
221
230
|
logger.debug = function(obj, msg, ...args) {
|
|
222
231
|
const ctx = getRequestContext()
|
|
223
|
-
|
|
232
|
+
const otelCtx = !ctx || !ctx.traceId ? getOtelTraceContext() : null
|
|
233
|
+
const traceCtx = ctx || otelCtx
|
|
234
|
+
|
|
235
|
+
if (traceCtx && traceCtx.traceId) {
|
|
224
236
|
if (typeof obj === 'object' && obj !== null) {
|
|
225
|
-
obj.traceId =
|
|
226
|
-
obj.spanId =
|
|
227
|
-
obj.parentSpanId =
|
|
228
|
-
obj.requestId =
|
|
237
|
+
obj.traceId = traceCtx.traceId
|
|
238
|
+
obj.spanId = traceCtx.spanId
|
|
239
|
+
obj.parentSpanId = traceCtx.parentSpanId
|
|
240
|
+
obj.requestId = traceCtx.requestId || ctx?.requestId
|
|
229
241
|
} else {
|
|
230
|
-
obj = { traceId:
|
|
242
|
+
obj = { traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId, msg: obj }
|
|
231
243
|
}
|
|
232
244
|
}
|
|
233
245
|
return originalDebug.call(this, obj, msg, ...args)
|
|
@@ -235,14 +247,17 @@ try {
|
|
|
235
247
|
|
|
236
248
|
logger.fatal = function(obj, msg, ...args) {
|
|
237
249
|
const ctx = getRequestContext()
|
|
238
|
-
|
|
250
|
+
const otelCtx = !ctx || !ctx.traceId ? getOtelTraceContext() : null
|
|
251
|
+
const traceCtx = ctx || otelCtx
|
|
252
|
+
|
|
253
|
+
if (traceCtx && traceCtx.traceId) {
|
|
239
254
|
if (typeof obj === 'object' && obj !== null) {
|
|
240
|
-
obj.traceId =
|
|
241
|
-
obj.spanId =
|
|
242
|
-
obj.parentSpanId =
|
|
243
|
-
obj.requestId =
|
|
255
|
+
obj.traceId = traceCtx.traceId
|
|
256
|
+
obj.spanId = traceCtx.spanId
|
|
257
|
+
obj.parentSpanId = traceCtx.parentSpanId
|
|
258
|
+
obj.requestId = traceCtx.requestId || ctx?.requestId
|
|
244
259
|
} else {
|
|
245
|
-
obj = { traceId:
|
|
260
|
+
obj = { traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId, msg: obj }
|
|
246
261
|
}
|
|
247
262
|
}
|
|
248
263
|
return originalFatal.call(this, obj, msg, ...args)
|
|
@@ -250,14 +265,17 @@ try {
|
|
|
250
265
|
|
|
251
266
|
logger.trace = function(obj, msg, ...args) {
|
|
252
267
|
const ctx = getRequestContext()
|
|
253
|
-
|
|
268
|
+
const otelCtx = !ctx || !ctx.traceId ? getOtelTraceContext() : null
|
|
269
|
+
const traceCtx = ctx || otelCtx
|
|
270
|
+
|
|
271
|
+
if (traceCtx && traceCtx.traceId) {
|
|
254
272
|
if (typeof obj === 'object' && obj !== null) {
|
|
255
|
-
obj.traceId =
|
|
256
|
-
obj.spanId =
|
|
257
|
-
obj.parentSpanId =
|
|
258
|
-
obj.requestId =
|
|
273
|
+
obj.traceId = traceCtx.traceId
|
|
274
|
+
obj.spanId = traceCtx.spanId
|
|
275
|
+
obj.parentSpanId = traceCtx.parentSpanId
|
|
276
|
+
obj.requestId = traceCtx.requestId || ctx?.requestId
|
|
259
277
|
} else {
|
|
260
|
-
obj = { traceId:
|
|
278
|
+
obj = { traceId: traceCtx.traceId, spanId: traceCtx.spanId, parentSpanId: traceCtx.parentSpanId, requestId: traceCtx.requestId || ctx?.requestId, msg: obj }
|
|
261
279
|
}
|
|
262
280
|
}
|
|
263
281
|
return originalTrace.call(this, obj, msg, ...args)
|
|
@@ -562,68 +580,143 @@ try {
|
|
|
562
580
|
|
|
563
581
|
instance.interceptors.response.use(
|
|
564
582
|
(response) => {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
}
|
|
583
|
+
try {
|
|
584
|
+
if (!response || !response.config) {
|
|
585
|
+
return response
|
|
586
|
+
}
|
|
570
587
|
|
|
571
|
-
|
|
572
|
-
|
|
588
|
+
const url = buildUrl(response.config) || response.config?.url || response.request?.responseURL || 'unknown'
|
|
589
|
+
const testMeta = { url }
|
|
590
|
+
if (isLoggerApiCall(testMeta)) {
|
|
591
|
+
return response
|
|
592
|
+
}
|
|
573
593
|
|
|
574
|
-
|
|
575
|
-
const
|
|
594
|
+
const marker = response.config?.__azifyLogger
|
|
595
|
+
const method = (response.config?.method || 'get').toUpperCase()
|
|
596
|
+
const requestHeaders = response.config?.headers || {}
|
|
597
|
+
const hasTraceHeaders = !!(requestHeaders['x-trace-id'] || requestHeaders['X-Trace-ID'] || requestHeaders['x-span-id'] || requestHeaders['X-Span-ID'])
|
|
576
598
|
const shouldLogResponse =
|
|
577
599
|
HTTP_CLIENT_MODE === 'all' ||
|
|
578
600
|
(HTTP_CLIENT_MODE === 'errors' && response.status >= 400)
|
|
579
601
|
|
|
580
|
-
if (shouldLogResponse) {
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
602
|
+
if (shouldLogResponse || hasTraceHeaders) {
|
|
603
|
+
const finalUrl = (url && url !== 'unknown') ? url : (marker?.meta?.url || response.config?.url || response.request?.responseURL || url)
|
|
604
|
+
|
|
605
|
+
if (finalUrl && finalUrl !== 'unknown') {
|
|
606
|
+
let meta
|
|
607
|
+
let duration = 0
|
|
608
|
+
|
|
609
|
+
if (marker && marker.meta) {
|
|
610
|
+
duration = Number((performance.now() - marker.start).toFixed(2))
|
|
611
|
+
meta = {
|
|
612
|
+
...marker.meta,
|
|
613
|
+
url: finalUrl,
|
|
614
|
+
statusCode: response.status,
|
|
615
|
+
responseTimeMs: duration,
|
|
616
|
+
responseHeaders: response.headers,
|
|
617
|
+
responseBody: response.data
|
|
618
|
+
}
|
|
619
|
+
} else {
|
|
620
|
+
const requestHeaders = response.config?.headers || {}
|
|
621
|
+
const ctx = getRequestContext()
|
|
622
|
+
const traceId = requestHeaders['x-trace-id'] || requestHeaders['X-Trace-ID'] || ctx?.traceId || randomUUID()
|
|
623
|
+
const spanId = requestHeaders['x-span-id'] || requestHeaders['X-Span-ID'] || randomBytes(8).toString('hex')
|
|
624
|
+
const parentSpanId = requestHeaders['x-parent-span-id'] || requestHeaders['X-Parent-Span-ID'] || ctx?.spanId || null
|
|
625
|
+
const requestId = requestHeaders['x-request-id'] || requestHeaders['X-Request-ID'] || ctx?.requestId || randomUUID()
|
|
626
|
+
|
|
627
|
+
meta = {
|
|
628
|
+
traceId,
|
|
629
|
+
spanId,
|
|
630
|
+
parentSpanId,
|
|
631
|
+
requestId,
|
|
632
|
+
method,
|
|
633
|
+
url: finalUrl,
|
|
634
|
+
statusCode: response.status,
|
|
635
|
+
responseTimeMs: duration,
|
|
636
|
+
responseHeaders: response.headers,
|
|
637
|
+
responseBody: response.data
|
|
638
|
+
}
|
|
587
639
|
}
|
|
588
640
|
|
|
589
641
|
markSource(meta, 'http-client')
|
|
590
|
-
const message = `[RESPONSE] ${meta.method} ${meta.url} ${response.status} ${
|
|
642
|
+
const message = `[RESPONSE] ${meta.method} ${meta.url} ${response.status} ${meta.responseTimeMs}ms`
|
|
591
643
|
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
592
644
|
|
|
593
645
|
sendOutboundLog(level, message, meta)
|
|
646
|
+
}
|
|
594
647
|
}
|
|
648
|
+
} catch (err) {
|
|
595
649
|
}
|
|
596
650
|
|
|
597
651
|
return response
|
|
598
652
|
},
|
|
599
653
|
(error) => {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
654
|
+
try {
|
|
655
|
+
const config = error?.config
|
|
656
|
+
if (config) {
|
|
657
|
+
const url = buildUrl(config)
|
|
658
|
+
const testMeta = { url }
|
|
659
|
+
if (isLoggerApiCall(testMeta)) {
|
|
660
|
+
return Promise.reject(error)
|
|
661
|
+
}
|
|
606
662
|
}
|
|
607
|
-
}
|
|
608
663
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
664
|
+
const marker = config?.__azifyLogger
|
|
665
|
+
const method = (config?.method || 'get').toUpperCase()
|
|
666
|
+
const url = config ? buildUrl(config) : (error?.request?.responseURL || error?.config?.url || 'unknown')
|
|
667
|
+
const shouldLogError = HTTP_CLIENT_MODE === 'all' || HTTP_CLIENT_MODE === 'errors'
|
|
668
|
+
|
|
669
|
+
if (shouldLogError && url && url !== 'unknown') {
|
|
670
|
+
let meta
|
|
671
|
+
let duration = 0
|
|
672
|
+
|
|
673
|
+
if (marker && marker.meta) {
|
|
674
|
+
duration = Number((performance.now() - marker.start).toFixed(2))
|
|
675
|
+
meta = {
|
|
676
|
+
...marker.meta,
|
|
677
|
+
responseTimeMs: duration,
|
|
678
|
+
error: {
|
|
679
|
+
name: error?.name || 'Error',
|
|
680
|
+
message: error?.message || String(error),
|
|
681
|
+
stack: error?.stack,
|
|
682
|
+
code: error?.code,
|
|
683
|
+
status: error?.response?.status,
|
|
684
|
+
statusText: error?.response?.statusText
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
} else {
|
|
688
|
+
const requestHeaders = config?.headers || {}
|
|
689
|
+
const ctx = getRequestContext()
|
|
690
|
+
const traceId = requestHeaders['x-trace-id'] || requestHeaders['X-Trace-ID'] || ctx?.traceId || randomUUID()
|
|
691
|
+
const spanId = requestHeaders['x-span-id'] || requestHeaders['X-Span-ID'] || randomBytes(8).toString('hex')
|
|
692
|
+
const parentSpanId = requestHeaders['x-parent-span-id'] || requestHeaders['X-Parent-Span-ID'] || ctx?.spanId || null
|
|
693
|
+
const requestId = requestHeaders['x-request-id'] || requestHeaders['X-Request-ID'] || ctx?.requestId || randomUUID()
|
|
694
|
+
|
|
695
|
+
meta = {
|
|
696
|
+
traceId,
|
|
697
|
+
spanId,
|
|
698
|
+
parentSpanId,
|
|
699
|
+
requestId,
|
|
700
|
+
method,
|
|
701
|
+
url,
|
|
702
|
+
responseTimeMs: duration,
|
|
703
|
+
error: {
|
|
704
|
+
name: error?.name || 'Error',
|
|
705
|
+
message: error?.message || String(error),
|
|
706
|
+
stack: error?.stack,
|
|
707
|
+
code: error?.code,
|
|
708
|
+
status: error?.response?.status,
|
|
709
|
+
statusText: error?.response?.statusText
|
|
710
|
+
}
|
|
711
|
+
}
|
|
621
712
|
}
|
|
713
|
+
|
|
714
|
+
markSource(meta, 'http-client')
|
|
715
|
+
const message = `[ERROR] ${meta.method} ${meta.url}`
|
|
716
|
+
|
|
717
|
+
sendOutboundLog('error', message, meta)
|
|
622
718
|
}
|
|
623
|
-
|
|
624
|
-
const message = `[ERROR] ${meta.method} ${meta.url}`
|
|
625
|
-
|
|
626
|
-
sendOutboundLog('error', message, meta)
|
|
719
|
+
} catch (err) {
|
|
627
720
|
}
|
|
628
721
|
|
|
629
722
|
return Promise.reject(error)
|
|
@@ -717,18 +810,19 @@ try {
|
|
|
717
810
|
})
|
|
718
811
|
|
|
719
812
|
const duration = Number((performance.now() - start).toFixed(2))
|
|
813
|
+
const hasTraceHeaders = !!(requestMeta.traceId && requestMeta.spanId)
|
|
720
814
|
const shouldLogResponse =
|
|
721
815
|
HTTP_CLIENT_MODE === 'all' ||
|
|
722
|
-
(HTTP_CLIENT_MODE === 'errors' && response.status >= 400)
|
|
816
|
+
(HTTP_CLIENT_MODE === 'errors' && response.status >= 400) ||
|
|
817
|
+
hasTraceHeaders
|
|
723
818
|
|
|
724
819
|
if (shouldLogResponse) {
|
|
725
|
-
|
|
820
|
+
const logResponse = async () => {
|
|
821
|
+
let responseBody = null
|
|
822
|
+
const contentType = response.headers.get('content-type') || ''
|
|
823
|
+
|
|
726
824
|
try {
|
|
727
825
|
const clonedResponse = response.clone()
|
|
728
|
-
const contentType = response.headers.get('content-type') || ''
|
|
729
|
-
|
|
730
|
-
let responseBody = null
|
|
731
|
-
|
|
732
826
|
if (contentType.includes('application/json') || contentType.includes('text/')) {
|
|
733
827
|
const bodyText = await clonedResponse.text()
|
|
734
828
|
if (contentType.includes('application/json')) {
|
|
@@ -741,7 +835,26 @@ try {
|
|
|
741
835
|
responseBody = bodyText
|
|
742
836
|
}
|
|
743
837
|
}
|
|
838
|
+
} catch (cloneError) {
|
|
839
|
+
try {
|
|
840
|
+
if (contentType.includes('application/json') || contentType.includes('text/')) {
|
|
841
|
+
const bodyText = await response.text()
|
|
842
|
+
if (contentType.includes('application/json')) {
|
|
843
|
+
try {
|
|
844
|
+
responseBody = JSON.parse(bodyText)
|
|
845
|
+
} catch (_) {
|
|
846
|
+
responseBody = bodyText
|
|
847
|
+
}
|
|
848
|
+
} else {
|
|
849
|
+
responseBody = bodyText
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
} catch (_) {
|
|
853
|
+
responseBody = null
|
|
854
|
+
}
|
|
855
|
+
}
|
|
744
856
|
|
|
857
|
+
try {
|
|
745
858
|
const responseMeta = {
|
|
746
859
|
...requestMeta,
|
|
747
860
|
statusCode: response.status,
|
|
@@ -755,21 +868,27 @@ try {
|
|
|
755
868
|
|
|
756
869
|
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
757
870
|
sendOutboundLog(level, message, responseMeta)
|
|
758
|
-
} catch (
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
871
|
+
} catch (err) {
|
|
872
|
+
try {
|
|
873
|
+
const responseMeta = {
|
|
874
|
+
...requestMeta,
|
|
875
|
+
statusCode: response.status,
|
|
876
|
+
responseTimeMs: duration,
|
|
877
|
+
responseHeaders: Object.fromEntries(response.headers.entries()),
|
|
878
|
+
responseBody: null
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
markSource(responseMeta, 'http-client')
|
|
882
|
+
const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
|
|
883
|
+
|
|
884
|
+
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
885
|
+
sendOutboundLog(level, message, responseMeta)
|
|
886
|
+
} catch (_) {
|
|
765
887
|
}
|
|
766
|
-
|
|
767
|
-
markSource(responseMeta, 'http-client')
|
|
768
|
-
const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
|
|
769
|
-
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
770
|
-
sendOutboundLog(level, message, responseMeta)
|
|
771
888
|
}
|
|
772
|
-
}
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
logResponse().catch(() => {})
|
|
773
892
|
}
|
|
774
893
|
|
|
775
894
|
return response
|