azify-logger 1.0.34 → 1.0.36

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.
@@ -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
- request.body = safeSerializeBody(req.body)
285
+ requestBody = safeSerializeBody(req.body)
286
+ request.body = requestBody
289
287
  }
290
288
 
291
289
  const meta = {
@@ -294,18 +292,10 @@ 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
  }
300
-
301
- if (config.captureRequestBody && req.body !== undefined && req.body != null) {
302
- const serializedBody = safeSerializeBody(req.body)
303
- if (typeof serializedBody === 'string') {
304
- meta.requestBody = serializedBody
305
- } else {
306
- meta.requestBody = JSON.stringify(serializedBody)
307
- }
308
- }
309
299
  if (serviceObj) meta.service = serviceObj
310
300
  if (config.environment) meta.environment = config.environment
311
301
 
@@ -316,11 +306,6 @@ function createExpressLoggingMiddleware(options = {}) {
316
306
  const originalEnd = res.end.bind(res)
317
307
 
318
308
  res.end = (chunk, encoding) => {
319
- if (logSent) {
320
- return originalEnd(chunk, encoding)
321
- }
322
- logSent = true
323
-
324
309
  const result = originalEnd(chunk, encoding)
325
310
 
326
311
  if (chunk != null && config.captureResponseBody && !responseChunkCaptured) {
@@ -328,46 +313,84 @@ function createExpressLoggingMiddleware(options = {}) {
328
313
  responseChunkCaptured = true
329
314
  }
330
315
 
331
- process.nextTick(() => {
332
- ensureIds()
333
-
334
- const statusCode = res.statusCode || 200
335
- const duration = Date.now() - startTime
336
- const response = { statusCode, durationMs: duration }
337
-
338
- if (config.captureHeaders) {
339
- ensureHeaders()
340
- }
341
-
342
- const requestObj = {
343
- id: requestId,
344
- method,
345
- url,
346
- path,
347
- ip: clientIp
348
- }
349
- if (query) requestObj.query = query
350
- if (config.captureHeaders && cachedHeaders) requestObj.headers = cachedHeaders
316
+ if (!logSent) {
317
+ logSent = true
351
318
 
352
- const meta = {
353
- traceId: reqCtx.traceId,
354
- spanId: reqCtx.spanId,
355
- parentSpanId: reqCtx.parentSpanId || null,
356
- requestId,
357
- request: requestObj,
358
- response,
359
- timestamp: Date.now(),
360
- hostname
361
- }
362
- if (serviceObj) meta.service = serviceObj
363
- if (config.environment) meta.environment = config.environment
364
-
365
- const chunkToProcess = (responseChunk !== null && responseChunkCaptured) ? responseChunk : null
366
- emitResponseLog(meta, chunkToProcess)
367
- })
319
+ process.nextTick(() => {
320
+ try {
321
+ ensureIds()
322
+
323
+ const statusCode = res.statusCode || 200
324
+ const duration = Date.now() - startTime
325
+ const response = { statusCode, durationMs: duration }
326
+
327
+ if (config.captureHeaders) {
328
+ ensureHeaders()
329
+ }
330
+
331
+ const requestObj = {
332
+ id: requestId,
333
+ method,
334
+ url,
335
+ path,
336
+ ip: clientIp
337
+ }
338
+ if (query) requestObj.query = query
339
+ if (config.captureHeaders && cachedHeaders) requestObj.headers = cachedHeaders
340
+
341
+ const meta = {
342
+ traceId: reqCtx.traceId,
343
+ spanId: reqCtx.spanId,
344
+ parentSpanId: reqCtx.parentSpanId || null,
345
+ requestId,
346
+ request: requestObj,
347
+ response,
348
+ timestamp: Date.now(),
349
+ hostname
350
+ }
351
+ if (serviceObj) meta.service = serviceObj
352
+ if (config.environment) meta.environment = config.environment
353
+
354
+ const chunkToProcess = (responseChunk !== null && responseChunkCaptured) ? responseChunk : null
355
+ emitResponseLog(meta, chunkToProcess)
356
+ } catch (err) {
357
+ try {
358
+ ensureIds()
359
+ const statusCode = res.statusCode || 200
360
+ const duration = Date.now() - startTime
361
+ const response = { statusCode, durationMs: duration }
362
+ const requestObj = {
363
+ id: requestId,
364
+ method,
365
+ url,
366
+ path,
367
+ ip: clientIp || 'unknown'
368
+ }
369
+ const meta = {
370
+ traceId: reqCtx?.traceId || traceId,
371
+ spanId: reqCtx?.spanId || spanId,
372
+ parentSpanId: reqCtx?.parentSpanId || parentSpanId || null,
373
+ requestId: requestId || fastUUID(),
374
+ request: requestObj,
375
+ response,
376
+ timestamp: Date.now(),
377
+ hostname
378
+ }
379
+ if (serviceObj) meta.service = serviceObj
380
+ if (config.environment) meta.environment = config.environment
381
+ emitResponseLog(meta, null)
382
+ } catch (_) {
383
+ }
384
+ }
385
+ })
386
+ }
368
387
 
369
388
  return result
370
389
  }
390
+
391
+ runWithRequestContext(ctx, () => {
392
+ next()
393
+ })
371
394
  }
372
395
  }
373
396
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azify-logger",
3
- "version": "1.0.34",
3
+ "version": "1.0.36",
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
- const source = meta && meta.__source
83
- if (!shouldSample(level, source)) {
84
- return
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
- if (metaCopy.meta && metaCopy.meta.requestBody != null) {
99
- if (typeof metaCopy.meta.requestBody !== 'string') {
100
- try {
101
- metaCopy.meta.requestBody = JSON.stringify(metaCopy.meta.requestBody)
102
- } catch (_) {
103
- metaCopy.meta.requestBody = String(metaCopy.meta.requestBody)
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
- const payload = {
109
- level,
110
- message,
111
- meta: {
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
- if (HTTP_CLIENT_MODE === 'all') {
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: response.data
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: response.data
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
- if (typeof Request !== 'undefined' && input instanceof Request) {
775
- return init ? new Request(input, init) : input
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 url = 'unknown'
786
- let method = 'GET'
813
+ let request
814
+ let method = 'UNKNOWN'
815
+ let url = String(input)
787
816
 
788
- if (typeof input === 'string') {
789
- url = input
790
- method = (init?.method || 'GET').toUpperCase()
791
- } else if (input instanceof URL) {
792
- url = input.toString()
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
- url = String(input)
800
- method = (init?.method || 'GET').toUpperCase()
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(input, init)
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,95 +883,18 @@ 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
886
+ try {
887
+ requestMeta.headers = Object.fromEntries(request.headers.entries())
888
+ } catch (_) {
867
889
  }
868
890
 
869
- let request
870
- try {
871
- let headers
872
- if (init?.headers instanceof Headers) {
873
- headers = new Headers(init.headers)
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
- request = ensureRequest(input, init)
891
+ if (requestBodyString !== null) {
892
+ requestMeta.requestBody = requestBodyString
903
893
  }
904
894
 
905
895
  markSource(requestMeta, 'http-client')
906
- const hasTraceHeaders = !!(requestMeta.traceId && requestMeta.spanId)
907
- const shouldLogRequest =
908
- HTTP_CLIENT_MODE === 'all' ||
909
- HTTP_CLIENT_MODE === 'errors' ||
910
- hasTraceHeaders
911
-
912
- let requestWasLogged = false
913
-
914
- if (shouldLogRequest) {
915
- const metaCopy = { ...requestMeta }
916
- if (metaCopy.requestBody != null && typeof metaCopy.requestBody !== 'string') {
917
- try {
918
- metaCopy.requestBody = JSON.stringify(metaCopy.requestBody)
919
- } catch (_) {
920
- metaCopy.requestBody = String(metaCopy.requestBody)
921
- }
922
- }
923
- const payload = {
924
- level: 'info',
925
- message: `[REQUEST] ${method} ${url}`,
926
- meta: {
927
- ...metaCopy,
928
- service: {
929
- name: serviceName,
930
- version: '1.0.0'
931
- },
932
- environment,
933
- timestamp: new Date().toISOString(),
934
- hostname: os.hostname()
935
- }
936
- }
937
- try {
938
- transport.enqueue(payload, {
939
- 'content-type': 'application/json'
940
- })
941
- requestWasLogged = true
942
- } catch (enqueueErr) {
943
- sendOutboundLog('info', `[REQUEST] ${method} ${url}`, requestMeta)
944
- requestWasLogged = true
945
- }
896
+ if (HTTP_CLIENT_MODE !== 'off') {
897
+ sendOutboundLog('info', `[REQUEST] ${method} ${url}`, requestMeta)
946
898
  }
947
899
 
948
900
  const childCtx = {
@@ -954,202 +906,134 @@ try {
954
906
 
955
907
  const start = performance.now()
956
908
 
909
+ let response
957
910
  try {
958
- const response = await runWithRequestContext(childCtx, function() {
911
+ response = await runWithRequestContext(childCtx, function() {
959
912
  return originalFetch(request)
960
913
  })
961
-
914
+ } catch (error) {
962
915
  const duration = Number((performance.now() - start).toFixed(2))
963
- const hasTraceHeaders = !!(requestMeta.traceId && requestMeta.spanId)
964
- const wasRequestLogged = requestWasLogged || HTTP_CLIENT_MODE === 'all' || HTTP_CLIENT_MODE === 'errors' || hasTraceHeaders
965
- const shouldLogResponse =
966
- HTTP_CLIENT_MODE === 'all' ||
967
- (HTTP_CLIENT_MODE === 'errors' && (response.status >= 400 || wasRequestLogged)) ||
968
- hasTraceHeaders ||
969
- requestWasLogged
916
+ try {
917
+ const errorMeta = {
918
+ ...requestMeta,
919
+ responseTimeMs: duration
920
+ }
921
+ markSource(errorMeta, 'http-client')
922
+ const err = error instanceof Error ? error : new Error(String(error))
923
+ errorMeta.error = {
924
+ name: err.name,
925
+ message: err.message,
926
+ stack: err.stack
927
+ }
928
+ sendOutboundLog('error', `[ERROR] ${method} ${url}`, errorMeta)
929
+ } catch (_) {
930
+ }
931
+ throw error
932
+ }
933
+
934
+ const duration = Number((performance.now() - start).toFixed(2))
935
+ const shouldLogResponse = HTTP_CLIENT_MODE !== 'off'
970
936
 
971
- let responseCloneForLogging = null
972
- if (shouldLogResponse) {
937
+ if (shouldLogResponse && response) {
938
+ const headersToObject = (headers) => {
973
939
  try {
974
- responseCloneForLogging = response.clone()
975
- } catch (cloneError) {
976
- responseCloneForLogging = null
940
+ if (!headers) return {}
941
+ if (typeof headers.entries === 'function') {
942
+ return Object.fromEntries(headers.entries())
943
+ }
944
+ if (typeof headers.forEach === 'function') {
945
+ const out = {}
946
+ headers.forEach((value, key) => {
947
+ out[key] = value
948
+ })
949
+ return out
950
+ }
951
+ if (typeof headers === 'object') {
952
+ return { ...headers }
953
+ }
954
+ } catch (_) {
977
955
  }
956
+ return {}
978
957
  }
979
-
980
- if (shouldLogResponse) {
981
- const logResponse = async () => {
982
- let responseBody = null
983
- const contentType = response.headers.get('content-type') || ''
984
-
985
- if (responseCloneForLogging) {
986
- try {
987
- const clonedResponse = responseCloneForLogging
988
- if (contentType.includes('application/json') || contentType.includes('text/')) {
989
- const bodyText = await clonedResponse.text()
990
- if (contentType.includes('application/json')) {
991
- try {
992
- responseBody = JSON.parse(bodyText)
993
- } catch (_) {
994
- responseBody = bodyText
995
- }
996
- } else {
997
- responseBody = bodyText
998
- }
999
- }
1000
- } catch (cloneError) {
1001
- try {
1002
- if (contentType.includes('application/json') || contentType.includes('text/')) {
1003
- const bodyText = await response.text()
1004
- if (contentType.includes('application/json')) {
1005
- try {
1006
- responseBody = JSON.parse(bodyText)
1007
- } catch (_) {
1008
- responseBody = bodyText
1009
- }
1010
- } else {
1011
- responseBody = bodyText
1012
- }
1013
- }
1014
- } catch (_) {
1015
- responseBody = null
1016
- }
1017
- }
1018
- } else {
1019
- responseBody = null
958
+
959
+ let responseBodyString = null
960
+ let responseHeaders = {}
961
+
962
+ try {
963
+ responseHeaders = headersToObject(response.headers)
964
+ const contentType = response.headers.get('content-type') || ''
965
+ const readBodyWithTimeout = async (resp, timeoutMs) => {
966
+ try {
967
+ const timed = await Promise.race([
968
+ resp.text(),
969
+ new Promise((resolve) => setTimeout(() => resolve(null), timeoutMs))
970
+ ])
971
+ return typeof timed === 'string' ? timed : null
972
+ } catch (_) {
973
+ return null
1020
974
  }
1021
-
975
+ }
976
+
977
+ if (contentType.includes('application/json') || contentType.includes('text/')) {
1022
978
  try {
1023
- const responseMeta = {
1024
- ...requestMeta,
1025
- statusCode: response.status,
1026
- responseTimeMs: duration,
1027
- responseHeaders: Object.fromEntries(response.headers.entries()),
1028
- responseBody: responseBody
1029
- }
1030
-
1031
- markSource(responseMeta, 'http-client')
1032
- const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
1033
-
1034
- const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
1035
-
1036
- const metaCopy = { ...responseMeta }
1037
- if (metaCopy.responseBody != null && typeof metaCopy.responseBody !== 'string') {
1038
- try {
1039
- metaCopy.responseBody = JSON.stringify(metaCopy.responseBody)
1040
- } catch (_) {
1041
- metaCopy.responseBody = String(metaCopy.responseBody)
979
+ const clonedResponse = response.clone()
980
+ const bodyText = await readBodyWithTimeout(clonedResponse, 200)
981
+ if (bodyText) {
982
+ if (contentType.includes('application/json')) {
983
+ try {
984
+ responseBodyString = JSON.stringify(JSON.parse(bodyText))
985
+ } catch (_) {
986
+ responseBodyString = bodyText
987
+ }
988
+ } else {
989
+ responseBodyString = bodyText
1042
990
  }
1043
- }
1044
-
1045
- const payload = {
1046
- level,
1047
- message,
1048
- meta: {
1049
- ...metaCopy,
1050
- service: {
1051
- name: serviceName,
1052
- version: '1.0.0'
1053
- },
1054
- environment,
1055
- timestamp: new Date().toISOString(),
1056
- hostname: os.hostname()
991
+ if (typeof responseBodyString === 'string' && responseBodyString.length > 5000) {
992
+ responseBodyString = responseBodyString.slice(0, 5000)
1057
993
  }
1058
994
  }
995
+ } catch (_) {
1059
996
  try {
1060
- transport.enqueue(payload, {
1061
- 'content-type': 'application/json'
1062
- })
1063
- } catch (enqueueErr) {
1064
- sendOutboundLog(level, message, responseMeta)
1065
- }
1066
- } catch (err) {
1067
- try {
1068
- const responseMeta = {
1069
- ...requestMeta,
1070
- statusCode: response.status,
1071
- responseTimeMs: duration,
1072
- responseHeaders: Object.fromEntries(response.headers.entries()),
1073
- responseBody: responseBody != null ? String(responseBody) : null
1074
- }
1075
-
1076
- markSource(responseMeta, 'http-client')
1077
- const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
1078
-
1079
- const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
1080
-
1081
- const metaCopy = { ...responseMeta }
1082
- if (metaCopy.responseBody != null && typeof metaCopy.responseBody !== 'string') {
1083
- try {
1084
- metaCopy.responseBody = JSON.stringify(metaCopy.responseBody)
1085
- } catch (_) {
1086
- metaCopy.responseBody = String(metaCopy.responseBody)
997
+ const bodyText = await readBodyWithTimeout(response, 200)
998
+ if (bodyText) {
999
+ if (contentType.includes('application/json')) {
1000
+ try {
1001
+ responseBodyString = JSON.stringify(JSON.parse(bodyText))
1002
+ } catch (_) {
1003
+ responseBodyString = bodyText
1004
+ }
1005
+ } else {
1006
+ responseBodyString = bodyText
1087
1007
  }
1088
- }
1089
- const payload = {
1090
- level,
1091
- message,
1092
- meta: {
1093
- ...metaCopy,
1094
- service: {
1095
- name: serviceName,
1096
- version: '1.0.0'
1097
- },
1098
- environment,
1099
- timestamp: new Date().toISOString(),
1100
- hostname: os.hostname()
1008
+ if (typeof responseBodyString === 'string' && responseBodyString.length > 5000) {
1009
+ responseBodyString = responseBodyString.slice(0, 5000)
1101
1010
  }
1102
1011
  }
1103
- try {
1104
- transport.enqueue(payload, {
1105
- 'content-type': 'application/json'
1106
- })
1107
- } catch (enqueueErr) {
1108
- sendOutboundLog(level, message, responseMeta)
1109
- }
1110
- } catch (innerErr) {
1111
- console.error('[azify-logger] Erro ao logar resposta (fallback):', innerErr)
1012
+ } catch (_) {
1112
1013
  }
1113
1014
  }
1114
1015
  }
1115
-
1116
- logResponse().catch((err) => {
1117
- console.error('[azify-logger] Erro ao executar logResponse para', method, url, ':', err)
1118
- const responseMeta = {
1119
- ...requestMeta,
1120
- statusCode: response.status,
1121
- responseTimeMs: duration,
1122
- responseHeaders: Object.fromEntries(response.headers.entries()),
1123
- responseBody: null
1124
- }
1125
- markSource(responseMeta, 'http-client')
1126
- const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
1127
- const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
1128
- try {
1129
- sendOutboundLog(level, message, responseMeta)
1130
- } catch (fallbackErr) {
1131
- console.error('[azify-logger] Erro ao enviar log de fallback:', fallbackErr)
1132
- }
1133
- })
1016
+ } catch (_) {
1134
1017
  }
1135
-
1136
- return response
1137
- } catch (error) {
1138
- const duration = Number((performance.now() - start).toFixed(2))
1139
- const errorMeta = {
1018
+
1019
+ const responseMeta = {
1140
1020
  ...requestMeta,
1141
- responseTimeMs: duration
1021
+ statusCode: response.status,
1022
+ responseTimeMs: duration,
1023
+ responseHeaders
1142
1024
  }
1143
- markSource(errorMeta, 'http-client')
1144
- const err = error instanceof Error ? error : new Error(String(error))
1145
- errorMeta.error = {
1146
- name: err.name,
1147
- message: err.message,
1148
- stack: err.stack
1025
+
1026
+ if (responseBodyString !== null) {
1027
+ responseMeta.responseBody = responseBodyString
1149
1028
  }
1150
- void sendOutboundLog('error', `[ERROR] ${method} ${url}`, errorMeta)
1151
- throw error
1029
+
1030
+ markSource(responseMeta, 'http-client')
1031
+ const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
1032
+ const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
1033
+ sendOutboundLog(level, message, responseMeta)
1152
1034
  }
1035
+
1036
+ return response
1153
1037
  }
1154
1038
  }
1155
1039
  }
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) {
@@ -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
- return bodyValue.toString('utf8')
1703
+ let str = bodyValue.toString('utf8')
1704
+ return str
1705
1705
  } catch (_) {
1706
1706
  return '[Unable to serialize Buffer]'
1707
1707
  }