azify-logger 1.0.32 → 1.0.34

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.
@@ -297,6 +297,15 @@ function createExpressLoggingMiddleware(options = {}) {
297
297
  timestamp: Date.now(),
298
298
  hostname
299
299
  }
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
+ }
300
309
  if (serviceObj) meta.service = serviceObj
301
310
  if (config.environment) meta.environment = config.environment
302
311
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azify-logger",
3
- "version": "1.0.32",
3
+ "version": "1.0.34",
4
4
  "description": "Azify Logger Client - Centralized logging for OpenSearch",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
package/register.js CHANGED
@@ -84,11 +84,32 @@ try {
84
84
  return
85
85
  }
86
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
+ }
95
+ }
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)
104
+ }
105
+ }
106
+ }
107
+
87
108
  const payload = {
88
109
  level,
89
110
  message,
90
111
  meta: {
91
- ...meta,
112
+ ...metaCopy,
92
113
  service: {
93
114
  name: serviceName,
94
115
  version: (meta && meta.service && meta.service.version) || '1.0.0'
@@ -739,6 +760,7 @@ try {
739
760
  } catch (_) {}
740
761
 
741
762
  try {
763
+
742
764
  if (typeof globalThis.fetch === 'function') {
743
765
  const g = globalThis
744
766
  if (!g.__azifyLoggerFetchPatched) {
@@ -760,6 +782,32 @@ try {
760
782
  return originalFetch(input, init)
761
783
  }
762
784
 
785
+ let url = 'unknown'
786
+ let method = 'GET'
787
+
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 {
798
+ try {
799
+ url = String(input)
800
+ method = (init?.method || 'GET').toUpperCase()
801
+ } catch (_) {
802
+ return originalFetch(input, init)
803
+ }
804
+ }
805
+
806
+ const testMeta = { url }
807
+ if (isLoggerApiCall(testMeta)) {
808
+ return originalFetch(input, init)
809
+ }
810
+
763
811
  let requestBody = null
764
812
  if (init && init.body != null) {
765
813
  try {
@@ -772,36 +820,30 @@ try {
772
820
  requestBody = '[FormData]'
773
821
  } else if (body instanceof URLSearchParams) {
774
822
  requestBody = body.toString()
775
- } else if (typeof body === 'object') {
823
+ } else if (typeof body === 'object' && body !== null) {
776
824
  requestBody = JSON.stringify(body)
777
825
  } else {
778
826
  requestBody = String(body)
779
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
780
836
  } catch (_) {
781
837
  requestBody = null
782
838
  }
783
839
  }
784
840
 
785
- const request = ensureRequest(input, init)
786
- const method = request.method.toUpperCase()
787
- const url = request.url
788
-
789
- const testMeta = { url }
790
- if (isLoggerApiCall(testMeta)) {
791
- return originalFetch(request)
792
- }
793
-
794
841
  const ctx = getRequestContext()
795
842
  const traceId = (ctx?.traceId) || randomUUID()
796
843
  const parentSpanId = (ctx?.spanId) || null
797
844
  const requestId = (ctx?.requestId) || randomUUID()
798
845
  const spanId = randomBytes(8).toString('hex')
799
846
 
800
- request.headers.set('x-trace-id', traceId)
801
- request.headers.set('x-span-id', spanId)
802
- request.headers.set('x-parent-span-id', parentSpanId || '')
803
- request.headers.set('x-request-id', requestId)
804
-
805
847
  const requestMeta = {
806
848
  traceId,
807
849
  spanId,
@@ -809,16 +851,98 @@ try {
809
851
  requestId,
810
852
  method,
811
853
  url,
812
- headers: Object.fromEntries(request.headers.entries())
854
+ headers: {}
813
855
  }
814
856
 
815
857
  if (requestBody != null) {
816
- requestMeta.requestBody = requestBody
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
+ 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)
817
903
  }
818
904
 
819
905
  markSource(requestMeta, 'http-client')
820
- if (HTTP_CLIENT_MODE === 'all') {
821
- sendOutboundLog('info', `[REQUEST] ${method} ${url}`, requestMeta)
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
+ }
822
946
  }
823
947
 
824
948
  const childCtx = {
@@ -837,34 +961,32 @@ try {
837
961
 
838
962
  const duration = Number((performance.now() - start).toFixed(2))
839
963
  const hasTraceHeaders = !!(requestMeta.traceId && requestMeta.spanId)
964
+ const wasRequestLogged = requestWasLogged || HTTP_CLIENT_MODE === 'all' || HTTP_CLIENT_MODE === 'errors' || hasTraceHeaders
840
965
  const shouldLogResponse =
841
966
  HTTP_CLIENT_MODE === 'all' ||
842
- (HTTP_CLIENT_MODE === 'errors' && response.status >= 400) ||
843
- hasTraceHeaders
967
+ (HTTP_CLIENT_MODE === 'errors' && (response.status >= 400 || wasRequestLogged)) ||
968
+ hasTraceHeaders ||
969
+ requestWasLogged
970
+
971
+ let responseCloneForLogging = null
972
+ if (shouldLogResponse) {
973
+ try {
974
+ responseCloneForLogging = response.clone()
975
+ } catch (cloneError) {
976
+ responseCloneForLogging = null
977
+ }
978
+ }
844
979
 
845
980
  if (shouldLogResponse) {
846
981
  const logResponse = async () => {
847
982
  let responseBody = null
848
983
  const contentType = response.headers.get('content-type') || ''
849
984
 
850
- try {
851
- const clonedResponse = response.clone()
852
- if (contentType.includes('application/json') || contentType.includes('text/')) {
853
- const bodyText = await clonedResponse.text()
854
- if (contentType.includes('application/json')) {
855
- try {
856
- responseBody = JSON.parse(bodyText)
857
- } catch (_) {
858
- responseBody = bodyText
859
- }
860
- } else {
861
- responseBody = bodyText
862
- }
863
- }
864
- } catch (cloneError) {
985
+ if (responseCloneForLogging) {
865
986
  try {
987
+ const clonedResponse = responseCloneForLogging
866
988
  if (contentType.includes('application/json') || contentType.includes('text/')) {
867
- const bodyText = await response.text()
989
+ const bodyText = await clonedResponse.text()
868
990
  if (contentType.includes('application/json')) {
869
991
  try {
870
992
  responseBody = JSON.parse(bodyText)
@@ -875,9 +997,26 @@ try {
875
997
  responseBody = bodyText
876
998
  }
877
999
  }
878
- } catch (_) {
879
- responseBody = null
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
+ }
880
1017
  }
1018
+ } else {
1019
+ responseBody = null
881
1020
  }
882
1021
 
883
1022
  try {
@@ -893,7 +1032,37 @@ try {
893
1032
  const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
894
1033
 
895
1034
  const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
896
- sendOutboundLog(level, message, responseMeta)
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)
1042
+ }
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()
1057
+ }
1058
+ }
1059
+ try {
1060
+ transport.enqueue(payload, {
1061
+ 'content-type': 'application/json'
1062
+ })
1063
+ } catch (enqueueErr) {
1064
+ sendOutboundLog(level, message, responseMeta)
1065
+ }
897
1066
  } catch (err) {
898
1067
  try {
899
1068
  const responseMeta = {
@@ -901,20 +1070,67 @@ try {
901
1070
  statusCode: response.status,
902
1071
  responseTimeMs: duration,
903
1072
  responseHeaders: Object.fromEntries(response.headers.entries()),
904
- responseBody: null
1073
+ responseBody: responseBody != null ? String(responseBody) : null
905
1074
  }
906
1075
 
907
1076
  markSource(responseMeta, 'http-client')
908
1077
  const message = `[RESPONSE] ${method} ${url} ${response.status} ${duration}ms`
909
1078
 
910
1079
  const level = response.status >= 500 ? 'error' : response.status >= 400 ? 'warn' : 'info'
911
- sendOutboundLog(level, message, responseMeta)
912
- } catch (_) {
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)
1087
+ }
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()
1101
+ }
1102
+ }
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)
913
1112
  }
914
1113
  }
915
1114
  }
916
1115
 
917
- logResponse().catch(() => {})
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
+ })
918
1134
  }
919
1135
 
920
1136
  return response
@@ -226,6 +226,15 @@ 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
+ }
229
238
  }
230
239
 
231
240
  return sanitized
@@ -248,6 +257,18 @@ async function deliver(entry) {
248
257
  sanitizedPayload = entry.payload
249
258
  }
250
259
  }
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
+ }
251
272
 
252
273
  await axios.post(target, sanitizedPayload, {
253
274
  headers: entry.headers || {},
@@ -325,6 +346,16 @@ async function processEntry(raw) {
325
346
  return
326
347
  }
327
348
 
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
+
328
359
  const attempts = Number(entry.attempts || 0)
329
360
  try {
330
361
  await deliver(entry)
package/server.js CHANGED
@@ -154,6 +154,7 @@ async function ensureIndexTemplate() {
154
154
  userAgent: { type: 'text' },
155
155
  environment: { type: 'keyword' },
156
156
  hostname: { type: 'keyword' },
157
+ requestBody: { type: 'text' },
157
158
  responseBody: { type: 'text' },
158
159
  error: {
159
160
  properties: {
@@ -1691,28 +1692,16 @@ async function handleLog(req, res) {
1691
1692
  }
1692
1693
 
1693
1694
  if (typeof bodyValue === 'string') {
1694
- if (bodyValue.trim().startsWith('{') || bodyValue.trim().startsWith('[')) {
1695
- try {
1696
- let parsed = JSON.parse(bodyValue)
1697
- if (typeof parsed === 'object') {
1698
- return parsed
1699
- }
1700
- } catch (_) { }
1701
- }
1702
1695
  return bodyValue
1703
1696
  } else if (typeof bodyValue === 'object' && bodyValue !== null) {
1704
- return bodyValue
1697
+ try {
1698
+ return JSON.stringify(bodyValue)
1699
+ } catch (_) {
1700
+ return String(bodyValue)
1701
+ }
1705
1702
  } else if (Buffer.isBuffer(bodyValue)) {
1706
1703
  try {
1707
- let str = bodyValue.toString('utf8')
1708
- if (str.trim().startsWith('{') || str.trim().startsWith('[')) {
1709
- try {
1710
- return JSON.parse(str)
1711
- } catch (_) {
1712
- return str
1713
- }
1714
- }
1715
- return str
1704
+ return bodyValue.toString('utf8')
1716
1705
  } catch (_) {
1717
1706
  return '[Unable to serialize Buffer]'
1718
1707
  }