azify-logger 1.0.33 → 1.0.35
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/middleware-express.js +8 -5
- package/package.json +2 -2
- package/register.js +248 -280
- package/sampling.js +3 -0
- package/scripts/redis-worker.js +0 -31
- package/server.js +2 -2
package/middleware-express.js
CHANGED
|
@@ -210,10 +210,6 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
210
210
|
|
|
211
211
|
const ctx = ensureRequestContext()
|
|
212
212
|
|
|
213
|
-
runWithRequestContext(ctx, () => {
|
|
214
|
-
next()
|
|
215
|
-
})
|
|
216
|
-
|
|
217
213
|
const logWithContext = (level, message, meta) => {
|
|
218
214
|
const otelCtx = getOtelTraceContext()
|
|
219
215
|
const ctx = getRequestContext() || ensureRequestContext()
|
|
@@ -284,8 +280,10 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
284
280
|
}
|
|
285
281
|
if (query) request.query = query
|
|
286
282
|
if (config.captureHeaders && cachedHeaders) request.headers = cachedHeaders
|
|
283
|
+
let requestBody = null
|
|
287
284
|
if (config.captureRequestBody && req.body !== undefined && req.body != null) {
|
|
288
|
-
|
|
285
|
+
requestBody = safeSerializeBody(req.body)
|
|
286
|
+
request.body = requestBody
|
|
289
287
|
}
|
|
290
288
|
|
|
291
289
|
const meta = {
|
|
@@ -294,6 +292,7 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
294
292
|
parentSpanId: reqCtx.parentSpanId || null,
|
|
295
293
|
requestId,
|
|
296
294
|
request,
|
|
295
|
+
requestBody,
|
|
297
296
|
timestamp: Date.now(),
|
|
298
297
|
hostname
|
|
299
298
|
}
|
|
@@ -359,6 +358,10 @@ function createExpressLoggingMiddleware(options = {}) {
|
|
|
359
358
|
|
|
360
359
|
return result
|
|
361
360
|
}
|
|
361
|
+
|
|
362
|
+
runWithRequestContext(ctx, () => {
|
|
363
|
+
next()
|
|
364
|
+
})
|
|
362
365
|
}
|
|
363
366
|
}
|
|
364
367
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azify-logger",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.35",
|
|
4
4
|
"description": "Azify Logger Client - Centralized logging for OpenSearch",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"validate:retention": "node scripts/validate-retention.js",
|
|
22
22
|
"inspect:zip": "node scripts/inspect-zip.js",
|
|
23
23
|
"retention": "node scripts/retention-manager.js",
|
|
24
|
-
"list:blob": "node scripts/list-blob-files.js",
|
|
24
|
+
"list:blob": "bash -c 'set -a && source env/app.env && set +a && node scripts/list-blob-files.js'",
|
|
25
25
|
"list:blob:recent": "node scripts/download-blob-zip.js",
|
|
26
26
|
"check:old-logs": "node scripts/check-old-logs.js",
|
|
27
27
|
"validate:blob": "node scripts/validate-blob-zip.js",
|
package/register.js
CHANGED
|
@@ -79,50 +79,34 @@ try {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
function sendOutboundLog(level, message, meta) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const metaCopy = { ...meta }
|
|
88
|
-
if (metaCopy.requestBody != null) {
|
|
89
|
-
if (typeof metaCopy.requestBody !== 'string') {
|
|
90
|
-
try {
|
|
91
|
-
metaCopy.requestBody = JSON.stringify(metaCopy.requestBody)
|
|
92
|
-
} catch (_) {
|
|
93
|
-
metaCopy.requestBody = String(metaCopy.requestBody)
|
|
94
|
-
}
|
|
82
|
+
try {
|
|
83
|
+
const source = meta && meta.__source
|
|
84
|
+
if (!shouldSample(level, source)) {
|
|
85
|
+
return
|
|
95
86
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
87
|
+
|
|
88
|
+
const payload = {
|
|
89
|
+
level,
|
|
90
|
+
message,
|
|
91
|
+
meta: {
|
|
92
|
+
...meta,
|
|
93
|
+
service: {
|
|
94
|
+
name: serviceName,
|
|
95
|
+
version: (meta && meta.service && meta.service.version) || '1.0.0'
|
|
96
|
+
},
|
|
97
|
+
environment,
|
|
98
|
+
timestamp: new Date().toISOString(),
|
|
99
|
+
hostname: os.hostname()
|
|
104
100
|
}
|
|
105
101
|
}
|
|
106
|
-
}
|
|
107
102
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
...metaCopy,
|
|
113
|
-
service: {
|
|
114
|
-
name: serviceName,
|
|
115
|
-
version: (meta && meta.service && meta.service.version) || '1.0.0'
|
|
116
|
-
},
|
|
117
|
-
environment,
|
|
118
|
-
timestamp: new Date().toISOString(),
|
|
119
|
-
hostname: os.hostname()
|
|
103
|
+
if (transport && typeof transport.enqueue === 'function') {
|
|
104
|
+
transport.enqueue(payload, {
|
|
105
|
+
'content-type': 'application/json'
|
|
106
|
+
})
|
|
120
107
|
}
|
|
108
|
+
} catch (err) {
|
|
121
109
|
}
|
|
122
|
-
|
|
123
|
-
transport.enqueue(payload, {
|
|
124
|
-
'content-type': 'application/json'
|
|
125
|
-
})
|
|
126
110
|
}
|
|
127
111
|
|
|
128
112
|
function normalizePath(path) {
|
|
@@ -173,6 +157,10 @@ try {
|
|
|
173
157
|
return logger
|
|
174
158
|
}
|
|
175
159
|
|
|
160
|
+
const getOtelTraceContext = () => {
|
|
161
|
+
return null
|
|
162
|
+
}
|
|
163
|
+
|
|
176
164
|
try {
|
|
177
165
|
const Module = require('module')
|
|
178
166
|
const originalRequire = Module.prototype.require
|
|
@@ -590,7 +578,12 @@ try {
|
|
|
590
578
|
const childCtx = { traceId, spanId, parentSpanId, requestId }
|
|
591
579
|
config.__azifyChildCtx = childCtx
|
|
592
580
|
|
|
593
|
-
|
|
581
|
+
const shouldLogRequest =
|
|
582
|
+
HTTP_CLIENT_MODE === 'all' ||
|
|
583
|
+
HTTP_CLIENT_MODE === 'errors' ||
|
|
584
|
+
!!traceId
|
|
585
|
+
|
|
586
|
+
if (shouldLogRequest) {
|
|
594
587
|
sendOutboundLog('info', `[REQUEST] ${method} ${url}`, requestMeta)
|
|
595
588
|
}
|
|
596
589
|
|
|
@@ -626,16 +619,34 @@ try {
|
|
|
626
619
|
if (finalUrl && finalUrl !== 'unknown') {
|
|
627
620
|
let meta
|
|
628
621
|
let duration = 0
|
|
622
|
+
|
|
623
|
+
const stringifyBody = (value) => {
|
|
624
|
+
if (value == null) return null
|
|
625
|
+
if (typeof value === 'string') return value
|
|
626
|
+
try {
|
|
627
|
+
return JSON.stringify(value)
|
|
628
|
+
} catch (_) {
|
|
629
|
+
try {
|
|
630
|
+
return String(value)
|
|
631
|
+
} catch (_) {
|
|
632
|
+
return null
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
629
636
|
|
|
630
637
|
if (marker && marker.meta) {
|
|
631
638
|
duration = Number((performance.now() - marker.start).toFixed(2))
|
|
639
|
+
let responseBodyString = stringifyBody(response.data)
|
|
640
|
+
if (typeof responseBodyString === 'string' && responseBodyString.length > 5000) {
|
|
641
|
+
responseBodyString = responseBodyString.slice(0, 5000)
|
|
642
|
+
}
|
|
632
643
|
meta = {
|
|
633
644
|
...marker.meta,
|
|
634
645
|
url: finalUrl,
|
|
635
646
|
statusCode: response.status,
|
|
636
647
|
responseTimeMs: duration,
|
|
637
648
|
responseHeaders: response.headers,
|
|
638
|
-
responseBody:
|
|
649
|
+
responseBody: responseBodyString
|
|
639
650
|
}
|
|
640
651
|
} else {
|
|
641
652
|
const requestHeaders = response.config?.headers || {}
|
|
@@ -644,6 +655,10 @@ try {
|
|
|
644
655
|
const spanId = requestHeaders['x-span-id'] || requestHeaders['X-Span-ID'] || randomBytes(8).toString('hex')
|
|
645
656
|
const parentSpanId = requestHeaders['x-parent-span-id'] || requestHeaders['X-Parent-Span-ID'] || ctx?.spanId || null
|
|
646
657
|
const requestId = requestHeaders['x-request-id'] || requestHeaders['X-Request-ID'] || ctx?.requestId || randomUUID()
|
|
658
|
+
let responseBodyString = stringifyBody(response.data)
|
|
659
|
+
if (typeof responseBodyString === 'string' && responseBodyString.length > 5000) {
|
|
660
|
+
responseBodyString = responseBodyString.slice(0, 5000)
|
|
661
|
+
}
|
|
647
662
|
|
|
648
663
|
meta = {
|
|
649
664
|
traceId,
|
|
@@ -655,7 +670,7 @@ try {
|
|
|
655
670
|
statusCode: response.status,
|
|
656
671
|
responseTimeMs: duration,
|
|
657
672
|
responseHeaders: response.headers,
|
|
658
|
-
responseBody:
|
|
673
|
+
responseBody: responseBodyString
|
|
659
674
|
}
|
|
660
675
|
}
|
|
661
676
|
|
|
@@ -760,7 +775,6 @@ try {
|
|
|
760
775
|
} catch (_) {}
|
|
761
776
|
|
|
762
777
|
try {
|
|
763
|
-
|
|
764
778
|
if (typeof globalThis.fetch === 'function') {
|
|
765
779
|
const g = globalThis
|
|
766
780
|
if (!g.__azifyLoggerFetchPatched) {
|
|
@@ -771,10 +785,24 @@ try {
|
|
|
771
785
|
const originalFetch = globalThis.fetch.bind(globalThis)
|
|
772
786
|
|
|
773
787
|
function ensureRequest(input, init) {
|
|
774
|
-
|
|
775
|
-
|
|
788
|
+
try {
|
|
789
|
+
if (typeof Request !== 'undefined' && input instanceof Request) {
|
|
790
|
+
if (init) {
|
|
791
|
+
return new Request(input, init)
|
|
792
|
+
}
|
|
793
|
+
return input
|
|
794
|
+
}
|
|
795
|
+
if (init) {
|
|
796
|
+
return new Request(input, init)
|
|
797
|
+
}
|
|
798
|
+
return new Request(input, {})
|
|
799
|
+
} catch (err) {
|
|
800
|
+
try {
|
|
801
|
+
return new Request(input, init || {})
|
|
802
|
+
} catch (err2) {
|
|
803
|
+
return new Request(String(input), {})
|
|
804
|
+
}
|
|
776
805
|
}
|
|
777
|
-
return new Request(input, init)
|
|
778
806
|
}
|
|
779
807
|
|
|
780
808
|
globalThis.fetch = async function patchedFetch(input, init) {
|
|
@@ -782,60 +810,35 @@ try {
|
|
|
782
810
|
return originalFetch(input, init)
|
|
783
811
|
}
|
|
784
812
|
|
|
785
|
-
let
|
|
786
|
-
let method = '
|
|
813
|
+
let request
|
|
814
|
+
let method = 'UNKNOWN'
|
|
815
|
+
let url = String(input)
|
|
787
816
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
method =
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
method = (init?.method || 'GET').toUpperCase()
|
|
794
|
-
} else if (typeof Request !== 'undefined' && input instanceof Request) {
|
|
795
|
-
url = input.url
|
|
796
|
-
method = input.method.toUpperCase()
|
|
797
|
-
} else {
|
|
817
|
+
try {
|
|
818
|
+
request = ensureRequest(input, init)
|
|
819
|
+
method = request.method.toUpperCase()
|
|
820
|
+
url = request.url
|
|
821
|
+
} catch (err) {
|
|
798
822
|
try {
|
|
799
|
-
|
|
800
|
-
|
|
823
|
+
const basicMeta = {
|
|
824
|
+
traceId: randomUUID(),
|
|
825
|
+
spanId: randomBytes(8).toString('hex'),
|
|
826
|
+
parentSpanId: null,
|
|
827
|
+
requestId: randomUUID(),
|
|
828
|
+
method: (init && init.method) ? String(init.method).toUpperCase() : 'UNKNOWN',
|
|
829
|
+
url: String(input),
|
|
830
|
+
headers: {}
|
|
831
|
+
}
|
|
832
|
+
markSource(basicMeta, 'http-client')
|
|
833
|
+
sendOutboundLog('info', `[REQUEST] ${basicMeta.method} ${basicMeta.url}`, basicMeta)
|
|
801
834
|
} catch (_) {
|
|
802
|
-
return originalFetch(input, init)
|
|
803
835
|
}
|
|
836
|
+
return originalFetch(input, init)
|
|
804
837
|
}
|
|
805
|
-
|
|
838
|
+
|
|
806
839
|
const testMeta = { url }
|
|
807
840
|
if (isLoggerApiCall(testMeta)) {
|
|
808
|
-
return originalFetch(
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
let requestBody = null
|
|
812
|
-
if (init && init.body != null) {
|
|
813
|
-
try {
|
|
814
|
-
const body = init.body
|
|
815
|
-
if (typeof body === 'string') {
|
|
816
|
-
requestBody = body
|
|
817
|
-
} else if (Buffer.isBuffer(body)) {
|
|
818
|
-
requestBody = body.toString('utf8')
|
|
819
|
-
} else if (body instanceof FormData) {
|
|
820
|
-
requestBody = '[FormData]'
|
|
821
|
-
} else if (body instanceof URLSearchParams) {
|
|
822
|
-
requestBody = body.toString()
|
|
823
|
-
} else if (typeof body === 'object' && body !== null) {
|
|
824
|
-
requestBody = JSON.stringify(body)
|
|
825
|
-
} else {
|
|
826
|
-
requestBody = String(body)
|
|
827
|
-
}
|
|
828
|
-
} catch (error) {
|
|
829
|
-
requestBody = null
|
|
830
|
-
}
|
|
831
|
-
} else if (typeof Request !== 'undefined' && input instanceof Request && input.body && !input.bodyUsed) {
|
|
832
|
-
try {
|
|
833
|
-
const cloned = input.clone()
|
|
834
|
-
const text = await cloned.text()
|
|
835
|
-
requestBody = text
|
|
836
|
-
} catch (_) {
|
|
837
|
-
requestBody = null
|
|
838
|
-
}
|
|
841
|
+
return originalFetch(request)
|
|
839
842
|
}
|
|
840
843
|
|
|
841
844
|
const ctx = getRequestContext()
|
|
@@ -844,6 +847,32 @@ try {
|
|
|
844
847
|
const requestId = (ctx?.requestId) || randomUUID()
|
|
845
848
|
const spanId = randomBytes(8).toString('hex')
|
|
846
849
|
|
|
850
|
+
try {
|
|
851
|
+
request.headers.set('x-trace-id', traceId)
|
|
852
|
+
request.headers.set('x-span-id', spanId)
|
|
853
|
+
request.headers.set('x-parent-span-id', parentSpanId || '')
|
|
854
|
+
request.headers.set('x-request-id', requestId)
|
|
855
|
+
} catch (_) {
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
let requestBodyString = null
|
|
859
|
+
if (init && init.body !== null && init.body !== undefined) {
|
|
860
|
+
try {
|
|
861
|
+
if (typeof init.body === 'string') {
|
|
862
|
+
requestBodyString = init.body
|
|
863
|
+
} else if (init.body instanceof FormData || init.body instanceof URLSearchParams) {
|
|
864
|
+
requestBodyString = '[FormData/URLSearchParams]'
|
|
865
|
+
} else if (typeof init.body === 'object' && !(init.body instanceof Blob) && !(init.body instanceof ArrayBuffer)) {
|
|
866
|
+
try {
|
|
867
|
+
requestBodyString = JSON.stringify(init.body)
|
|
868
|
+
} catch (_) {
|
|
869
|
+
requestBodyString = String(init.body)
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
} catch (_) {
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
847
876
|
const requestMeta = {
|
|
848
877
|
traceId,
|
|
849
878
|
spanId,
|
|
@@ -854,127 +883,20 @@ try {
|
|
|
854
883
|
headers: {}
|
|
855
884
|
}
|
|
856
885
|
|
|
857
|
-
if (requestBody != null) {
|
|
858
|
-
let finalRequestBody = requestBody
|
|
859
|
-
if (typeof requestBody !== 'string') {
|
|
860
|
-
try {
|
|
861
|
-
finalRequestBody = JSON.stringify(requestBody)
|
|
862
|
-
} catch (_) {
|
|
863
|
-
finalRequestBody = String(requestBody)
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
requestMeta.requestBody = finalRequestBody
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
let request
|
|
870
886
|
try {
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
} else if (init?.headers) {
|
|
875
|
-
headers = new Headers(init.headers)
|
|
876
|
-
} else {
|
|
877
|
-
headers = new Headers()
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
headers.set('x-trace-id', traceId)
|
|
881
|
-
headers.set('x-span-id', spanId)
|
|
882
|
-
headers.set('x-parent-span-id', parentSpanId || '')
|
|
883
|
-
headers.set('x-request-id', requestId)
|
|
884
|
-
|
|
885
|
-
requestMeta.headers = Object.fromEntries(headers.entries())
|
|
886
|
-
|
|
887
|
-
request = ensureRequest(input, {
|
|
888
|
-
...init,
|
|
889
|
-
headers: headers
|
|
890
|
-
})
|
|
891
|
-
} catch (error) {
|
|
892
|
-
if (init?.headers) {
|
|
893
|
-
try {
|
|
894
|
-
requestMeta.headers = typeof init.headers === 'object' && !(init.headers instanceof Headers)
|
|
895
|
-
? init.headers
|
|
896
|
-
: Object.fromEntries(new Headers(init.headers).entries())
|
|
897
|
-
} catch (_) {
|
|
898
|
-
requestMeta.headers = {}
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
markSource(requestMeta, 'http-client')
|
|
903
|
-
const hasTraceHeaders = !!(requestMeta.traceId && requestMeta.spanId)
|
|
904
|
-
const shouldLogRequest =
|
|
905
|
-
HTTP_CLIENT_MODE === 'all' ||
|
|
906
|
-
hasTraceHeaders
|
|
887
|
+
requestMeta.headers = Object.fromEntries(request.headers.entries())
|
|
888
|
+
} catch (_) {
|
|
889
|
+
}
|
|
907
890
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
const metaCopy = { ...requestMeta }
|
|
911
|
-
if (metaCopy.requestBody != null && typeof metaCopy.requestBody !== 'string') {
|
|
912
|
-
try {
|
|
913
|
-
metaCopy.requestBody = JSON.stringify(metaCopy.requestBody)
|
|
914
|
-
} catch (_) {
|
|
915
|
-
metaCopy.requestBody = String(metaCopy.requestBody)
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
const payload = {
|
|
919
|
-
level: 'info',
|
|
920
|
-
message: `[REQUEST] ${method} ${url}`,
|
|
921
|
-
meta: {
|
|
922
|
-
...metaCopy,
|
|
923
|
-
service: {
|
|
924
|
-
name: serviceName,
|
|
925
|
-
version: '1.0.0'
|
|
926
|
-
},
|
|
927
|
-
environment,
|
|
928
|
-
timestamp: new Date().toISOString(),
|
|
929
|
-
hostname: os.hostname()
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
transport.enqueue(payload, {
|
|
933
|
-
'content-type': 'application/json'
|
|
934
|
-
})
|
|
935
|
-
} else {
|
|
936
|
-
sendOutboundLog('info', `[REQUEST] ${method} ${url}`, requestMeta)
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
return originalFetch(input, init)
|
|
891
|
+
if (requestBodyString !== null) {
|
|
892
|
+
requestMeta.requestBody = requestBodyString
|
|
941
893
|
}
|
|
942
894
|
|
|
943
895
|
markSource(requestMeta, 'http-client')
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
HTTP_CLIENT_MODE === 'all' ||
|
|
947
|
-
hasTraceHeaders
|
|
948
|
-
|
|
949
|
-
if (shouldLogRequest) {
|
|
950
|
-
if (hasTraceHeaders) {
|
|
951
|
-
const metaCopy = { ...requestMeta }
|
|
952
|
-
if (metaCopy.requestBody != null && typeof metaCopy.requestBody !== 'string') {
|
|
953
|
-
try {
|
|
954
|
-
metaCopy.requestBody = JSON.stringify(metaCopy.requestBody)
|
|
955
|
-
} catch (_) {
|
|
956
|
-
metaCopy.requestBody = String(metaCopy.requestBody)
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
const payload = {
|
|
960
|
-
level: 'info',
|
|
961
|
-
message: `[REQUEST] ${method} ${url}`,
|
|
962
|
-
meta: {
|
|
963
|
-
...metaCopy,
|
|
964
|
-
service: {
|
|
965
|
-
name: serviceName,
|
|
966
|
-
version: '1.0.0'
|
|
967
|
-
},
|
|
968
|
-
environment,
|
|
969
|
-
timestamp: new Date().toISOString(),
|
|
970
|
-
hostname: os.hostname()
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
transport.enqueue(payload, {
|
|
974
|
-
'content-type': 'application/json'
|
|
975
|
-
})
|
|
976
|
-
} else {
|
|
896
|
+
if (HTTP_CLIENT_MODE !== 'off') {
|
|
897
|
+
try {
|
|
977
898
|
sendOutboundLog('info', `[REQUEST] ${method} ${url}`, requestMeta)
|
|
899
|
+
} catch (_) {
|
|
978
900
|
}
|
|
979
901
|
}
|
|
980
902
|
|
|
@@ -987,110 +909,156 @@ try {
|
|
|
987
909
|
|
|
988
910
|
const start = performance.now()
|
|
989
911
|
|
|
912
|
+
let response
|
|
990
913
|
try {
|
|
991
|
-
|
|
914
|
+
response = await runWithRequestContext(childCtx, function() {
|
|
992
915
|
return originalFetch(request)
|
|
993
916
|
})
|
|
994
|
-
|
|
917
|
+
} catch (error) {
|
|
995
918
|
const duration = Number((performance.now() - start).toFixed(2))
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
919
|
+
try {
|
|
920
|
+
const errorMeta = {
|
|
921
|
+
...requestMeta,
|
|
922
|
+
responseTimeMs: duration
|
|
923
|
+
}
|
|
924
|
+
markSource(errorMeta, 'http-client')
|
|
925
|
+
const err = error instanceof Error ? error : new Error(String(error))
|
|
926
|
+
errorMeta.error = {
|
|
927
|
+
name: err.name,
|
|
928
|
+
message: err.message,
|
|
929
|
+
stack: err.stack
|
|
930
|
+
}
|
|
931
|
+
sendOutboundLog('error', `[ERROR] ${method} ${url}`, errorMeta)
|
|
932
|
+
} catch (_) {
|
|
933
|
+
}
|
|
934
|
+
throw error
|
|
935
|
+
}
|
|
1001
936
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
937
|
+
const duration = Number((performance.now() - start).toFixed(2))
|
|
938
|
+
const shouldLogResponse = HTTP_CLIENT_MODE !== 'off'
|
|
939
|
+
|
|
940
|
+
if (shouldLogResponse) {
|
|
941
|
+
const headersToObject = (headers) => {
|
|
942
|
+
try {
|
|
943
|
+
if (!headers) return {}
|
|
944
|
+
if (typeof headers.entries === 'function') {
|
|
945
|
+
return Object.fromEntries(headers.entries())
|
|
946
|
+
}
|
|
947
|
+
if (typeof headers.forEach === 'function') {
|
|
948
|
+
const out = {}
|
|
949
|
+
headers.forEach((value, key) => {
|
|
950
|
+
out[key] = value
|
|
951
|
+
})
|
|
952
|
+
return out
|
|
953
|
+
}
|
|
954
|
+
if (typeof headers === 'object') {
|
|
955
|
+
return { ...headers }
|
|
956
|
+
}
|
|
957
|
+
} catch (_) {
|
|
958
|
+
}
|
|
959
|
+
return {}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
let responseBodyString = null
|
|
963
|
+
let responseHeaders = {}
|
|
964
|
+
|
|
965
|
+
try {
|
|
966
|
+
responseHeaders = headersToObject(response.headers)
|
|
967
|
+
const contentType = response.headers.get('content-type') || ''
|
|
968
|
+
const readBodyWithTimeout = async (resp, timeoutMs) => {
|
|
969
|
+
try {
|
|
970
|
+
const timed = await Promise.race([
|
|
971
|
+
resp.text(),
|
|
972
|
+
new Promise((resolve) => setTimeout(() => resolve(null), timeoutMs))
|
|
973
|
+
])
|
|
974
|
+
return typeof timed === 'string' ? timed : null
|
|
975
|
+
} catch (_) {
|
|
976
|
+
return null
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
if (contentType.includes('application/json') || contentType.includes('text/')) {
|
|
1007
981
|
try {
|
|
1008
982
|
const clonedResponse = response.clone()
|
|
1009
|
-
|
|
1010
|
-
|
|
983
|
+
const bodyText = await readBodyWithTimeout(clonedResponse, 200)
|
|
984
|
+
if (bodyText) {
|
|
1011
985
|
if (contentType.includes('application/json')) {
|
|
1012
986
|
try {
|
|
1013
|
-
|
|
987
|
+
responseBodyString = JSON.stringify(JSON.parse(bodyText))
|
|
1014
988
|
} catch (_) {
|
|
1015
|
-
|
|
989
|
+
responseBodyString = bodyText
|
|
1016
990
|
}
|
|
1017
991
|
} else {
|
|
1018
|
-
|
|
992
|
+
responseBodyString = bodyText
|
|
993
|
+
}
|
|
994
|
+
if (typeof responseBodyString === 'string' && responseBodyString.length > 5000) {
|
|
995
|
+
responseBodyString = responseBodyString.slice(0, 5000)
|
|
1019
996
|
}
|
|
1020
997
|
}
|
|
1021
|
-
} catch (
|
|
998
|
+
} catch (_) {
|
|
1022
999
|
try {
|
|
1023
|
-
|
|
1024
|
-
|
|
1000
|
+
const bodyText = await readBodyWithTimeout(response, 200)
|
|
1001
|
+
if (bodyText) {
|
|
1025
1002
|
if (contentType.includes('application/json')) {
|
|
1026
1003
|
try {
|
|
1027
|
-
|
|
1004
|
+
responseBodyString = JSON.stringify(JSON.parse(bodyText))
|
|
1028
1005
|
} catch (_) {
|
|
1029
|
-
|
|
1006
|
+
responseBodyString = bodyText
|
|
1030
1007
|
}
|
|
1031
1008
|
} else {
|
|
1032
|
-
|
|
1009
|
+
responseBodyString = bodyText
|
|
1010
|
+
}
|
|
1011
|
+
if (typeof responseBodyString === 'string' && responseBodyString.length > 5000) {
|
|
1012
|
+
responseBodyString = responseBodyString.slice(0, 5000)
|
|
1033
1013
|
}
|
|
1034
1014
|
}
|
|
1035
|
-
} catch (_) {
|
|
1036
|
-
responseBody = null
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
try {
|
|
1041
|
-
const responseMeta = {
|
|
1042
|
-
...requestMeta,
|
|
1043
|
-
statusCode: response.status,
|
|
1044
|
-
responseTimeMs: duration,
|
|
1045
|
-
responseHeaders: Object.fromEntries(response.headers.entries()),
|
|
1046
|
-
responseBody: responseBody
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
markSource(responseMeta, 'http-client')
|
|
1050
|
-
const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
|
|
1051
|
-
|
|
1052
|
-
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
1053
|
-
sendOutboundLog(level, message, responseMeta)
|
|
1054
|
-
} catch (err) {
|
|
1055
|
-
try {
|
|
1056
|
-
const responseMeta = {
|
|
1057
|
-
...requestMeta,
|
|
1058
|
-
statusCode: response.status,
|
|
1059
|
-
responseTimeMs: duration,
|
|
1060
|
-
responseHeaders: Object.fromEntries(response.headers.entries()),
|
|
1061
|
-
responseBody: null
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
markSource(responseMeta, 'http-client')
|
|
1065
|
-
const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
|
|
1066
|
-
|
|
1067
|
-
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
1068
|
-
sendOutboundLog(level, message, responseMeta)
|
|
1069
1015
|
} catch (_) {
|
|
1070
1016
|
}
|
|
1071
1017
|
}
|
|
1072
1018
|
}
|
|
1073
|
-
|
|
1074
|
-
logResponse().catch(() => {})
|
|
1019
|
+
} catch (_) {
|
|
1075
1020
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
} catch (error) {
|
|
1079
|
-
const duration = Number((performance.now() - start).toFixed(2))
|
|
1080
|
-
const errorMeta = {
|
|
1021
|
+
|
|
1022
|
+
const responseMeta = {
|
|
1081
1023
|
...requestMeta,
|
|
1082
|
-
|
|
1024
|
+
statusCode: response.status,
|
|
1025
|
+
responseTimeMs: duration,
|
|
1026
|
+
responseHeaders
|
|
1083
1027
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1028
|
+
|
|
1029
|
+
if (responseBodyString !== null) {
|
|
1030
|
+
responseMeta.responseBody = responseBodyString
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
try {
|
|
1034
|
+
markSource(responseMeta, 'http-client')
|
|
1035
|
+
const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
|
|
1036
|
+
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
1037
|
+
sendOutboundLog(level, message, responseMeta)
|
|
1038
|
+
} catch (err) {
|
|
1039
|
+
try {
|
|
1040
|
+
const fallbackMeta = {
|
|
1041
|
+
traceId: requestMeta.traceId || randomUUID(),
|
|
1042
|
+
spanId: requestMeta.spanId || randomBytes(8).toString('hex'),
|
|
1043
|
+
parentSpanId: requestMeta.parentSpanId || null,
|
|
1044
|
+
requestId: requestMeta.requestId || randomUUID(),
|
|
1045
|
+
method,
|
|
1046
|
+
url,
|
|
1047
|
+
statusCode: response.status,
|
|
1048
|
+
responseTimeMs: duration,
|
|
1049
|
+
headers: requestMeta.headers || {},
|
|
1050
|
+
responseHeaders: {}
|
|
1051
|
+
}
|
|
1052
|
+
markSource(fallbackMeta, 'http-client')
|
|
1053
|
+
const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
|
|
1054
|
+
const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
|
|
1055
|
+
sendOutboundLog(level, message, fallbackMeta)
|
|
1056
|
+
} catch (_) {
|
|
1057
|
+
}
|
|
1090
1058
|
}
|
|
1091
|
-
void sendOutboundLog('error', `[ERROR] ${method} ${url}`, errorMeta)
|
|
1092
|
-
throw error
|
|
1093
1059
|
}
|
|
1060
|
+
|
|
1061
|
+
return response
|
|
1094
1062
|
}
|
|
1095
1063
|
}
|
|
1096
1064
|
}
|
package/sampling.js
CHANGED
|
@@ -45,6 +45,9 @@ const sourceSampleRates = {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const shouldSample = (level, source) => {
|
|
48
|
+
if (source === 'http-client') {
|
|
49
|
+
return true
|
|
50
|
+
}
|
|
48
51
|
const key = typeof level === 'string' ? level.toLowerCase() : 'info'
|
|
49
52
|
let rate = levelSampleRates[key] ?? levelSampleRates.default
|
|
50
53
|
if (source && sourceSampleRates[source] !== undefined) {
|
package/scripts/redis-worker.js
CHANGED
|
@@ -226,15 +226,6 @@ function sanitizePayload(payload) {
|
|
|
226
226
|
if (sanitized.meta.responseBody) {
|
|
227
227
|
sanitized.meta.responseBody = sanitizeBody(sanitized.meta.responseBody)
|
|
228
228
|
}
|
|
229
|
-
if (sanitized.meta.requestBody != null) {
|
|
230
|
-
if (typeof sanitized.meta.requestBody !== 'string') {
|
|
231
|
-
try {
|
|
232
|
-
sanitized.meta.requestBody = JSON.stringify(sanitized.meta.requestBody)
|
|
233
|
-
} catch (_) {
|
|
234
|
-
sanitized.meta.requestBody = String(sanitized.meta.requestBody)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
229
|
}
|
|
239
230
|
|
|
240
231
|
return sanitized
|
|
@@ -257,18 +248,6 @@ async function deliver(entry) {
|
|
|
257
248
|
sanitizedPayload = entry.payload
|
|
258
249
|
}
|
|
259
250
|
}
|
|
260
|
-
|
|
261
|
-
if (sanitizedPayload && typeof sanitizedPayload === 'object' && sanitizedPayload.meta) {
|
|
262
|
-
if (sanitizedPayload.meta.requestBody != null) {
|
|
263
|
-
if (typeof sanitizedPayload.meta.requestBody !== 'string') {
|
|
264
|
-
try {
|
|
265
|
-
sanitizedPayload.meta.requestBody = JSON.stringify(sanitizedPayload.meta.requestBody)
|
|
266
|
-
} catch (_) {
|
|
267
|
-
sanitizedPayload.meta.requestBody = String(sanitizedPayload.meta.requestBody)
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
251
|
|
|
273
252
|
await axios.post(target, sanitizedPayload, {
|
|
274
253
|
headers: entry.headers || {},
|
|
@@ -346,16 +325,6 @@ async function processEntry(raw) {
|
|
|
346
325
|
return
|
|
347
326
|
}
|
|
348
327
|
|
|
349
|
-
if (entry && entry.payload && entry.payload.meta && entry.payload.meta.requestBody != null) {
|
|
350
|
-
if (typeof entry.payload.meta.requestBody !== 'string') {
|
|
351
|
-
try {
|
|
352
|
-
entry.payload.meta.requestBody = JSON.stringify(entry.payload.meta.requestBody)
|
|
353
|
-
} catch (_) {
|
|
354
|
-
entry.payload.meta.requestBody = String(entry.payload.meta.requestBody)
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
328
|
const attempts = Number(entry.attempts || 0)
|
|
360
329
|
try {
|
|
361
330
|
await deliver(entry)
|
package/server.js
CHANGED
|
@@ -154,7 +154,6 @@ async function ensureIndexTemplate() {
|
|
|
154
154
|
userAgent: { type: 'text' },
|
|
155
155
|
environment: { type: 'keyword' },
|
|
156
156
|
hostname: { type: 'keyword' },
|
|
157
|
-
requestBody: { type: 'text' },
|
|
158
157
|
responseBody: { type: 'text' },
|
|
159
158
|
error: {
|
|
160
159
|
properties: {
|
|
@@ -1701,7 +1700,8 @@ async function handleLog(req, res) {
|
|
|
1701
1700
|
}
|
|
1702
1701
|
} else if (Buffer.isBuffer(bodyValue)) {
|
|
1703
1702
|
try {
|
|
1704
|
-
|
|
1703
|
+
let str = bodyValue.toString('utf8')
|
|
1704
|
+
return str
|
|
1705
1705
|
} catch (_) {
|
|
1706
1706
|
return '[Unable to serialize Buffer]'
|
|
1707
1707
|
}
|