@jaypie/logger 1.2.10 → 1.2.12

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/dist/esm/index.js CHANGED
@@ -59,6 +59,224 @@ const DATADOG_TRANSPORT = {
59
59
  MAX_BATCH_SIZE: 100,
60
60
  };
61
61
 
62
+ //
63
+ // Key-based pipelines (match on var key name)
64
+ //
65
+ function isAxiosResponse(response) {
66
+ if (typeof response !== "object" || response === null) {
67
+ return false;
68
+ }
69
+ const r = response;
70
+ return !!(r &&
71
+ r.config &&
72
+ r.data &&
73
+ r.headers &&
74
+ r.request &&
75
+ r.status &&
76
+ r.statusText);
77
+ }
78
+ function filterAxiosResponse(response) {
79
+ if (!isAxiosResponse(response)) {
80
+ return response;
81
+ }
82
+ const r = response;
83
+ const newResponse = {
84
+ data: r.data,
85
+ headers: r.headers,
86
+ status: r.status,
87
+ statusText: r.statusText,
88
+ };
89
+ if (r.isAxiosError) {
90
+ newResponse.isAxiosError = r.isAxiosError;
91
+ }
92
+ return newResponse;
93
+ }
94
+ const axiosResponseVarPipeline = {
95
+ filter: filterAxiosResponse,
96
+ key: "response",
97
+ };
98
+ const pipelines = [axiosResponseVarPipeline];
99
+ // Fetch Response
100
+ function isFetchResponse(value) {
101
+ if (typeof value !== "object" || value === null) {
102
+ return false;
103
+ }
104
+ const r = value;
105
+ return !!(typeof r.ok === "boolean" &&
106
+ typeof r.status === "number" &&
107
+ typeof r.statusText === "string" &&
108
+ "headers" in r &&
109
+ "body" in r &&
110
+ typeof r.url === "string" &&
111
+ !("config" in r) &&
112
+ !("request" in r));
113
+ }
114
+ function headersToObject(headers) {
115
+ if (headers &&
116
+ typeof headers === "object" &&
117
+ typeof headers.entries === "function") {
118
+ const result = {};
119
+ for (const [key, value] of headers.entries()) {
120
+ result[key] = value;
121
+ }
122
+ return result;
123
+ }
124
+ return headers;
125
+ }
126
+ function filterFetchResponse(value) {
127
+ const r = value;
128
+ return {
129
+ headers: headersToObject(r.headers),
130
+ ok: r.ok,
131
+ redirected: r.redirected,
132
+ status: r.status,
133
+ statusText: r.statusText,
134
+ type: r.type,
135
+ url: r.url,
136
+ };
137
+ }
138
+ // Error
139
+ function isError(value) {
140
+ if (typeof value !== "object" || value === null) {
141
+ return false;
142
+ }
143
+ if (value instanceof Error) {
144
+ return true;
145
+ }
146
+ const i = value;
147
+ if (i.isProjectError) {
148
+ return true;
149
+ }
150
+ return false;
151
+ }
152
+ function filterError(value) {
153
+ const e = value;
154
+ const newItem = {
155
+ message: e.message,
156
+ name: e.name,
157
+ };
158
+ if (e.cause) {
159
+ newItem.cause = e.cause;
160
+ }
161
+ if (e.stack) {
162
+ newItem.stack = e.stack;
163
+ }
164
+ if (e.isProjectError) {
165
+ newItem.isProjectError = e.isProjectError;
166
+ newItem.title = e.title;
167
+ newItem.detail = e.detail;
168
+ newItem.status = e.status;
169
+ }
170
+ return newItem;
171
+ }
172
+ // Type filter registry (order matters — first match wins)
173
+ const typeFilters = [
174
+ { detect: isFetchResponse, filter: filterFetchResponse },
175
+ { detect: isError, filter: filterError },
176
+ ];
177
+ //
178
+ // Opaque object detection and generic extraction
179
+ //
180
+ function isOpaqueObject(value) {
181
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
182
+ return false;
183
+ }
184
+ // Plain objects are fine
185
+ if (value.constructor === Object || value.constructor === undefined) {
186
+ return false;
187
+ }
188
+ // If JSON.stringify produces "{}" the object has no own enumerable properties
189
+ // and will log as useless "[object Type]"
190
+ try {
191
+ const json = JSON.stringify(value);
192
+ return json === "{}" || json === "[]";
193
+ }
194
+ catch {
195
+ return true;
196
+ }
197
+ }
198
+ function extractOpaqueObject(value) {
199
+ const obj = value;
200
+ const result = {};
201
+ const ctorName = obj.constructor?.name;
202
+ if (ctorName && ctorName !== "Object") {
203
+ result._type = ctorName;
204
+ }
205
+ // If the object itself is map-like (Headers, URLSearchParams, FormData, etc.),
206
+ // convert its entries directly
207
+ const mapLike = obj;
208
+ if (typeof mapLike.entries === "function" &&
209
+ typeof mapLike.forEach === "function") {
210
+ try {
211
+ const entries = Object.fromEntries(mapLike.entries());
212
+ return { ...result, ...entries };
213
+ }
214
+ catch {
215
+ // Fall through to generic extraction
216
+ }
217
+ }
218
+ // Collect readable non-function properties from the prototype chain
219
+ let proto = obj;
220
+ while (proto && proto !== Object.prototype) {
221
+ for (const key of Object.getOwnPropertyNames(proto)) {
222
+ if (key === "constructor" || key in result) {
223
+ continue;
224
+ }
225
+ try {
226
+ const desc = Object.getOwnPropertyDescriptor(proto, key);
227
+ if (!desc)
228
+ continue;
229
+ // Read getters and value properties from the original object
230
+ const val = obj[key];
231
+ if (typeof val === "function" || typeof val === "symbol") {
232
+ continue;
233
+ }
234
+ // Skip streams and other non-serializable objects
235
+ if (val &&
236
+ typeof val === "object" &&
237
+ typeof val.pipe === "function") {
238
+ continue;
239
+ }
240
+ // Convert iterable map-like objects (Headers, URLSearchParams, etc.)
241
+ if (val &&
242
+ typeof val === "object" &&
243
+ typeof val.entries === "function" &&
244
+ typeof val.forEach === "function") {
245
+ result[key] = Object.fromEntries(val.entries());
246
+ continue;
247
+ }
248
+ result[key] = val;
249
+ }
250
+ catch {
251
+ // Property threw on access — skip
252
+ }
253
+ }
254
+ proto = Object.getPrototypeOf(proto);
255
+ }
256
+ return result;
257
+ }
258
+ //
259
+ // Public API
260
+ //
261
+ /**
262
+ * Filter a value by type, regardless of var key name.
263
+ * Tries known type filters first, then falls back to generic
264
+ * opaque object extraction for anything that would log as [object Type].
265
+ */
266
+ function filterByType(value) {
267
+ // Try known type filters
268
+ for (const tf of typeFilters) {
269
+ if (tf.detect(value)) {
270
+ return tf.filter(value);
271
+ }
272
+ }
273
+ // Generic fallback for opaque objects
274
+ if (isOpaqueObject(value)) {
275
+ return extractOpaqueObject(value);
276
+ }
277
+ return value;
278
+ }
279
+
62
280
  //
63
281
  //
64
282
  // Helper
@@ -403,11 +621,30 @@ function parsesTo(message) {
403
621
  }
404
622
  }
405
623
 
624
+ function resolveLevelField(value) {
625
+ if (value === undefined) {
626
+ const env = process.env.LOG_LEVEL_FIELD;
627
+ if (env === undefined || env === "")
628
+ return false;
629
+ if (env === "false" || env === "0" || env === "no")
630
+ return false;
631
+ if (env === "true" || env === "1" || env === "yes")
632
+ return "level";
633
+ return env;
634
+ }
635
+ if (value === false)
636
+ return false;
637
+ if (value === true)
638
+ return "level";
639
+ return value;
640
+ }
406
641
  class Logger {
407
- constructor({ format = process.env.LOG_FORMAT || DEFAULT.LEVEL, level = process.env.LOG_LEVEL || DEFAULT.LEVEL, tags = {}, varLevel = process.env.LOG_VAR_LEVEL || DEFAULT.VAR_LEVEL, } = {}) {
642
+ constructor({ format = process.env.LOG_FORMAT || DEFAULT.LEVEL, level = process.env.LOG_LEVEL || DEFAULT.LEVEL, levelField, tags = {}, varLevel = process.env.LOG_VAR_LEVEL || DEFAULT.VAR_LEVEL, } = {}) {
643
+ this.levelField = resolveLevelField(levelField);
408
644
  this.options = {
409
645
  format,
410
646
  level,
647
+ levelField: this.levelField || undefined,
411
648
  varLevel,
412
649
  };
413
650
  this.tags = {};
@@ -437,6 +674,9 @@ class Logger {
437
674
  if (parses.parses) {
438
675
  json.data = parses.message;
439
676
  }
677
+ if (this.levelField) {
678
+ json[this.levelField] = logLevel;
679
+ }
440
680
  out(json, { level: logLevel });
441
681
  }
442
682
  else {
@@ -475,7 +715,13 @@ class Logger {
475
715
  }
476
716
  if (format === FORMAT.JSON) {
477
717
  const messageKey = keys[0];
478
- const messageVal = msgObj[messageKey];
718
+ let messageVal = msgObj[messageKey];
719
+ for (const pipeline of pipelines) {
720
+ if (messageKey === pipeline.key) {
721
+ messageVal = pipeline.filter(messageVal);
722
+ }
723
+ }
724
+ messageVal = filterByType(messageVal);
479
725
  const json = {
480
726
  data: parse(messageVal),
481
727
  dataType: typeof messageVal,
@@ -483,6 +729,9 @@ class Logger {
483
729
  var: messageKey,
484
730
  ...this.tags,
485
731
  };
732
+ if (this.levelField) {
733
+ json[this.levelField] = logLevel;
734
+ }
486
735
  if (LEVEL_VALUES[logLevel] <= LEVEL_VALUES[checkLevel]) {
487
736
  out(json, { level: logLevel });
488
737
  }
@@ -594,81 +843,6 @@ function forceVar(key, value) {
594
843
  }
595
844
  }
596
845
 
597
- function isAxiosResponse(response) {
598
- if (typeof response !== "object" || response === null) {
599
- return false;
600
- }
601
- const r = response;
602
- return !!(r &&
603
- r.config &&
604
- r.data &&
605
- r.headers &&
606
- r.request &&
607
- r.status &&
608
- r.statusText);
609
- }
610
- function filterAxiosResponse(response) {
611
- if (!isAxiosResponse(response)) {
612
- return response;
613
- }
614
- const r = response;
615
- const newResponse = {
616
- data: r.data,
617
- headers: r.headers,
618
- status: r.status,
619
- statusText: r.statusText,
620
- };
621
- if (r.isAxiosError) {
622
- newResponse.isAxiosError = r.isAxiosError;
623
- }
624
- return newResponse;
625
- }
626
- const axiosResponseVarPipeline = {
627
- filter: filterAxiosResponse,
628
- key: "response",
629
- };
630
- function isError(item) {
631
- if (typeof item !== "object" || item === null) {
632
- return false;
633
- }
634
- if (item instanceof Error) {
635
- return true;
636
- }
637
- const i = item;
638
- if (i.isProjectError) {
639
- return true;
640
- }
641
- return false;
642
- }
643
- function filterErrorVar(item) {
644
- if (!isError(item)) {
645
- return item;
646
- }
647
- const e = item;
648
- const newItem = {
649
- message: e.message,
650
- name: e.name,
651
- };
652
- if (e.cause) {
653
- newItem.cause = e.cause;
654
- }
655
- if (e.stack) {
656
- newItem.stack = e.stack;
657
- }
658
- if (e.isProjectError) {
659
- newItem.isProjectError = e.isProjectError;
660
- newItem.title = e.title;
661
- newItem.detail = e.detail;
662
- newItem.status = e.status;
663
- }
664
- return newItem;
665
- }
666
- const errorVarPipeline = {
667
- filter: filterErrorVar,
668
- key: "error",
669
- };
670
- const pipelines = [axiosResponseVarPipeline, errorVarPipeline];
671
-
672
846
  function keyValueToArray(keyValue) {
673
847
  const key = Object.keys(keyValue)[0];
674
848
  return [key, keyValue[key]];
@@ -680,6 +854,7 @@ function logVar(key, value) {
680
854
  v = pipeline.filter(v);
681
855
  }
682
856
  }
857
+ v = filterByType(v);
683
858
  return { [k]: v };
684
859
  }
685
860