@logtape/logtape 1.0.0-dev.246 → 1.0.0-dev.248

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/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logtape/logtape",
3
- "version": "1.0.0-dev.246+c7630de7",
3
+ "version": "1.0.0-dev.248+f96c618d",
4
4
  "license": "MIT",
5
5
  "exports": "./mod.ts",
6
6
  "imports": {
@@ -32,6 +32,123 @@ const inspect = typeof document !== "undefined" || typeof navigator !== "undefin
32
32
  maxStringLength: Infinity,
33
33
  ...opts
34
34
  }) : (v) => JSON.stringify(v);
35
+ function padZero(num) {
36
+ return num < 10 ? `0${num}` : `${num}`;
37
+ }
38
+ function padThree(num) {
39
+ return num < 10 ? `00${num}` : num < 100 ? `0${num}` : `${num}`;
40
+ }
41
+ const timestampFormatters = {
42
+ "date-time-timezone": (ts) => {
43
+ const d = new Date(ts);
44
+ const year = d.getUTCFullYear();
45
+ const month = padZero(d.getUTCMonth() + 1);
46
+ const day = padZero(d.getUTCDate());
47
+ const hour = padZero(d.getUTCHours());
48
+ const minute = padZero(d.getUTCMinutes());
49
+ const second = padZero(d.getUTCSeconds());
50
+ const ms = padThree(d.getUTCMilliseconds());
51
+ return `${year}-${month}-${day} ${hour}:${minute}:${second}.${ms} +00:00`;
52
+ },
53
+ "date-time-tz": (ts) => {
54
+ const d = new Date(ts);
55
+ const year = d.getUTCFullYear();
56
+ const month = padZero(d.getUTCMonth() + 1);
57
+ const day = padZero(d.getUTCDate());
58
+ const hour = padZero(d.getUTCHours());
59
+ const minute = padZero(d.getUTCMinutes());
60
+ const second = padZero(d.getUTCSeconds());
61
+ const ms = padThree(d.getUTCMilliseconds());
62
+ return `${year}-${month}-${day} ${hour}:${minute}:${second}.${ms} +00`;
63
+ },
64
+ "date-time": (ts) => {
65
+ const d = new Date(ts);
66
+ const year = d.getUTCFullYear();
67
+ const month = padZero(d.getUTCMonth() + 1);
68
+ const day = padZero(d.getUTCDate());
69
+ const hour = padZero(d.getUTCHours());
70
+ const minute = padZero(d.getUTCMinutes());
71
+ const second = padZero(d.getUTCSeconds());
72
+ const ms = padThree(d.getUTCMilliseconds());
73
+ return `${year}-${month}-${day} ${hour}:${minute}:${second}.${ms}`;
74
+ },
75
+ "time-timezone": (ts) => {
76
+ const d = new Date(ts);
77
+ const hour = padZero(d.getUTCHours());
78
+ const minute = padZero(d.getUTCMinutes());
79
+ const second = padZero(d.getUTCSeconds());
80
+ const ms = padThree(d.getUTCMilliseconds());
81
+ return `${hour}:${minute}:${second}.${ms} +00:00`;
82
+ },
83
+ "time-tz": (ts) => {
84
+ const d = new Date(ts);
85
+ const hour = padZero(d.getUTCHours());
86
+ const minute = padZero(d.getUTCMinutes());
87
+ const second = padZero(d.getUTCSeconds());
88
+ const ms = padThree(d.getUTCMilliseconds());
89
+ return `${hour}:${minute}:${second}.${ms} +00`;
90
+ },
91
+ "time": (ts) => {
92
+ const d = new Date(ts);
93
+ const hour = padZero(d.getUTCHours());
94
+ const minute = padZero(d.getUTCMinutes());
95
+ const second = padZero(d.getUTCSeconds());
96
+ const ms = padThree(d.getUTCMilliseconds());
97
+ return `${hour}:${minute}:${second}.${ms}`;
98
+ },
99
+ "date": (ts) => {
100
+ const d = new Date(ts);
101
+ const year = d.getUTCFullYear();
102
+ const month = padZero(d.getUTCMonth() + 1);
103
+ const day = padZero(d.getUTCDate());
104
+ return `${year}-${month}-${day}`;
105
+ },
106
+ "rfc3339": (ts) => new Date(ts).toISOString(),
107
+ "none": () => null
108
+ };
109
+ const levelRenderersCache = {
110
+ ABBR: levelAbbreviations,
111
+ abbr: {
112
+ trace: "trc",
113
+ debug: "dbg",
114
+ info: "inf",
115
+ warning: "wrn",
116
+ error: "err",
117
+ fatal: "ftl"
118
+ },
119
+ FULL: {
120
+ trace: "TRACE",
121
+ debug: "DEBUG",
122
+ info: "INFO",
123
+ warning: "WARNING",
124
+ error: "ERROR",
125
+ fatal: "FATAL"
126
+ },
127
+ full: {
128
+ trace: "trace",
129
+ debug: "debug",
130
+ info: "info",
131
+ warning: "warning",
132
+ error: "error",
133
+ fatal: "fatal"
134
+ },
135
+ L: {
136
+ trace: "T",
137
+ debug: "D",
138
+ info: "I",
139
+ warning: "W",
140
+ error: "E",
141
+ fatal: "F"
142
+ },
143
+ l: {
144
+ trace: "t",
145
+ debug: "d",
146
+ info: "i",
147
+ warning: "w",
148
+ error: "e",
149
+ fatal: "f"
150
+ }
151
+ };
35
152
  /**
36
153
  * Get a text formatter with the specified options. Although it's flexible
37
154
  * enough to create a custom formatter, if you want more control, you can
@@ -50,15 +167,39 @@ const inspect = typeof document !== "undefined" || typeof navigator !== "undefin
50
167
  * @since 0.6.0
51
168
  */
52
169
  function getTextFormatter(options = {}) {
53
- const timestampRenderer = options.timestamp == null || options.timestamp === "date-time-timezone" ? (ts) => new Date(ts).toISOString().replace("T", " ").replace("Z", " +00:00") : options.timestamp === "date-time-tz" ? (ts) => new Date(ts).toISOString().replace("T", " ").replace("Z", " +00") : options.timestamp === "date-time" ? (ts) => new Date(ts).toISOString().replace("T", " ").replace("Z", "") : options.timestamp === "time-timezone" ? (ts) => new Date(ts).toISOString().replace(/.*T/, "").replace("Z", " +00:00") : options.timestamp === "time-tz" ? (ts) => new Date(ts).toISOString().replace(/.*T/, "").replace("Z", " +00") : options.timestamp === "time" ? (ts) => new Date(ts).toISOString().replace(/.*T/, "").replace("Z", "") : options.timestamp === "date" ? (ts) => new Date(ts).toISOString().replace(/T.*/, "") : options.timestamp === "rfc3339" ? (ts) => new Date(ts).toISOString() : options.timestamp === "none" || options.timestamp === "disabled" ? () => null : options.timestamp;
170
+ const timestampRenderer = (() => {
171
+ const tsOption = options.timestamp;
172
+ if (tsOption == null) return timestampFormatters["date-time-timezone"];
173
+ else if (tsOption === "disabled") return timestampFormatters["none"];
174
+ else if (typeof tsOption === "string" && tsOption in timestampFormatters) return timestampFormatters[tsOption];
175
+ else return tsOption;
176
+ })();
54
177
  const categorySeparator = options.category ?? "·";
55
178
  const valueRenderer = options.value ?? inspect;
56
- const levelRenderer = options.level == null || options.level === "ABBR" ? (level) => levelAbbreviations[level] : options.level === "abbr" ? (level) => levelAbbreviations[level].toLowerCase() : options.level === "FULL" ? (level) => level.toUpperCase() : options.level === "full" ? (level) => level : options.level === "L" ? (level) => level.charAt(0).toUpperCase() : options.level === "l" ? (level) => level.charAt(0) : options.level;
179
+ const levelRenderer = (() => {
180
+ const levelOption = options.level;
181
+ if (levelOption == null || levelOption === "ABBR") return (level) => levelRenderersCache.ABBR[level];
182
+ else if (levelOption === "abbr") return (level) => levelRenderersCache.abbr[level];
183
+ else if (levelOption === "FULL") return (level) => levelRenderersCache.FULL[level];
184
+ else if (levelOption === "full") return (level) => levelRenderersCache.full[level];
185
+ else if (levelOption === "L") return (level) => levelRenderersCache.L[level];
186
+ else if (levelOption === "l") return (level) => levelRenderersCache.l[level];
187
+ else return levelOption;
188
+ })();
57
189
  const formatter = options.format ?? (({ timestamp, level, category, message }) => `${timestamp ? `${timestamp} ` : ""}[${level}] ${category}: ${message}`);
58
190
  return (record) => {
59
- let message = "";
60
- for (let i = 0; i < record.message.length; i++) if (i % 2 === 0) message += record.message[i];
61
- else message += valueRenderer(record.message[i]);
191
+ const msgParts = record.message;
192
+ const msgLen = msgParts.length;
193
+ let message;
194
+ if (msgLen === 1) message = msgParts[0];
195
+ else if (msgLen <= 6) {
196
+ message = "";
197
+ for (let i = 0; i < msgLen; i++) message += i % 2 === 0 ? msgParts[i] : valueRenderer(msgParts[i]);
198
+ } else {
199
+ const parts = new Array(msgLen);
200
+ for (let i = 0; i < msgLen; i++) parts[i] = i % 2 === 0 ? msgParts[i] : valueRenderer(msgParts[i]);
201
+ message = parts.join("");
202
+ }
62
203
  const timestamp = timestampRenderer(record.timestamp);
63
204
  const level = levelRenderer(record.level);
64
205
  const category = typeof categorySeparator === "function" ? categorySeparator(record.category) : record.category.join(categorySeparator);
@@ -175,25 +316,39 @@ const ansiColorFormatter = getAnsiColorFormatter();
175
316
  * @since 0.11.0
176
317
  */
177
318
  function getJsonLinesFormatter(options = {}) {
319
+ if (!options.categorySeparator && !options.message && !options.properties) return (record) => {
320
+ if (record.message.length === 3) return JSON.stringify({
321
+ "@timestamp": new Date(record.timestamp).toISOString(),
322
+ level: record.level === "warning" ? "WARN" : record.level.toUpperCase(),
323
+ message: record.message[0] + JSON.stringify(record.message[1]) + record.message[2],
324
+ logger: record.category.join("."),
325
+ properties: record.properties
326
+ });
327
+ if (record.message.length === 1) return JSON.stringify({
328
+ "@timestamp": new Date(record.timestamp).toISOString(),
329
+ level: record.level === "warning" ? "WARN" : record.level.toUpperCase(),
330
+ message: record.message[0],
331
+ logger: record.category.join("."),
332
+ properties: record.properties
333
+ });
334
+ let msg = record.message[0];
335
+ for (let i = 1; i < record.message.length; i++) msg += i & 1 ? JSON.stringify(record.message[i]) : record.message[i];
336
+ return JSON.stringify({
337
+ "@timestamp": new Date(record.timestamp).toISOString(),
338
+ level: record.level === "warning" ? "WARN" : record.level.toUpperCase(),
339
+ message: msg,
340
+ logger: record.category.join("."),
341
+ properties: record.properties
342
+ });
343
+ };
344
+ const isTemplateMessage = options.message === "template";
345
+ const propertiesOption = options.properties ?? "nest:properties";
178
346
  let joinCategory;
179
347
  if (typeof options.categorySeparator === "function") joinCategory = options.categorySeparator;
180
348
  else {
181
349
  const separator = options.categorySeparator ?? ".";
182
350
  joinCategory = (category) => category.join(separator);
183
351
  }
184
- let getMessage;
185
- if (options.message === "template") getMessage = (record) => {
186
- if (typeof record.rawMessage === "string") return record.rawMessage;
187
- let msg = "";
188
- for (let i = 0; i < record.rawMessage.length; i++) msg += i % 2 < 1 ? record.rawMessage[i] : "{}";
189
- return msg;
190
- };
191
- else getMessage = (record) => {
192
- let msg = "";
193
- for (let i = 0; i < record.message.length; i++) msg += i % 2 < 1 ? record.message[i] : JSON.stringify(record.message[i]);
194
- return msg;
195
- };
196
- const propertiesOption = options.properties ?? "nest:properties";
197
352
  let getProperties;
198
353
  if (propertiesOption === "flatten") getProperties = (properties) => properties;
199
354
  else if (propertiesOption.startsWith("prepend:")) {
@@ -208,6 +363,20 @@ function getJsonLinesFormatter(options = {}) {
208
363
  const key = propertiesOption.substring(5);
209
364
  getProperties = (properties) => ({ [key]: properties });
210
365
  } else throw new TypeError(`Invalid properties option: ${JSON.stringify(propertiesOption)}. It must be "flatten", "prepend:<prefix>", or "nest:<key>".`);
366
+ let getMessage;
367
+ if (isTemplateMessage) getMessage = (record) => {
368
+ if (typeof record.rawMessage === "string") return record.rawMessage;
369
+ let msg = "";
370
+ for (let i = 0; i < record.rawMessage.length; i++) msg += i % 2 < 1 ? record.rawMessage[i] : "{}";
371
+ return msg;
372
+ };
373
+ else getMessage = (record) => {
374
+ const msgLen = record.message.length;
375
+ if (msgLen === 1) return record.message[0];
376
+ let msg = "";
377
+ for (let i = 0; i < msgLen; i++) msg += i % 2 < 1 ? record.message[i] : JSON.stringify(record.message[i]);
378
+ return msg;
379
+ };
211
380
  return (record) => {
212
381
  return JSON.stringify({
213
382
  "@timestamp": new Date(record.timestamp).toISOString(),
@@ -1 +1 @@
1
- {"version":3,"file":"formatter.d.cts","names":[],"sources":["../formatter.ts"],"sourcesContent":[],"mappings":";;;;;;;AAWA;AA+DA;AA+BA;;;AAuGoB,KArMR,aAAA,GAqMQ,CAAA,MAAA,EArMiB,SAqMjB,EAAA,GAAA,MAAA;AAAe;AAoBnC;;;AAEG,UA5Jc,eAAA,CA4Jd;EAAa;AA6EhB;AAQA;EAyBY,SAAA,EAAA,MAAS,GAAA,IAAA;EA4BJ;;;EAwCW,KAKT,EAAA,MAAA;EAAS;;;EAiBc,QAA1B,EAAA,MAAA;EAAM;;;EA9DiD,OAAA,EAAA,MAAA;EAmFvD;;;EACyB,MACtC,EAnWO,SAmWP;AAAa;AA4DhB;AAMA;AAsDA;;AACW,UArdM,oBAAA,CAqdN;EAA8B;AACzB;AA8FhB;AAUA;AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEArhBe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAyCK;;;;;;;;;;;;;;;;;;;iBAoBJ,gBAAA,WACL,uBACR;;;;;;;;;;;cA6EU,sBAAsB;;;;;KAQvB,SAAA;;;;;KAyBA,SAAA;;;;;UA4BK,yBAAA,SAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAwChC;;;;mBAKA;;;;eAKJ;;;;;;;;;;;gBAYC,OAAO,UAAU;;;;kBAKf;;;;kBAKA;;;;;;;;;;iBAWF,qBAAA,WACL,4BACR;;;;;;;;;;cA4DU,oBAAoB;;;;;UAMhB,yBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDD,qBAAA,WACL,4BACR;;;;;;;;;;;;;;;;;cA8FU,oBAAoB;;;;;;;;;KAUrB,gBAAA,YAA4B;;;;;;;;iBAqBxB,uBAAA,SAAgC"}
1
+ {"version":3,"file":"formatter.d.cts","names":[],"sources":["../formatter.ts"],"sourcesContent":[],"mappings":";;;;;;;AAWA;AA+DA;AA+BA;;;AAuGoB,KArMR,aAAA,GAqMQ,CAAA,MAAA,EArMiB,SAqMjB,EAAA,GAAA,MAAA;AAAe;AAgJnC;;;AAEG,UAxRc,eAAA,CAwRd;EAAa;AAiGhB;AAQA;EAyBY,SAAA,EAAA,MAAS,GAAA,IAAA;EA4BJ;;;EAwCW,KAKT,EAAA,MAAA;EAAS;;;EAiBc,QAA1B,EAAA,MAAA;EAAM;;;EA9DiD,OAAA,EAAA,MAAA;EAmFvD;;;EACyB,MACtC,EAnfO,SAmfP;AAAa;AA4DhB;AAMA;AAsDA;;AACW,UArmBM,oBAAA,CAqmBN;EAA8B;AACzB;AA2JhB;AAUA;AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEAluBe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAyCK;;;;;;;;;;;;;;;;;;;iBAgJJ,gBAAA,WACL,uBACR;;;;;;;;;;;cAiGU,sBAAsB;;;;;KAQvB,SAAA;;;;;KAyBA,SAAA;;;;;UA4BK,yBAAA,SAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAwChC;;;;mBAKA;;;;eAKJ;;;;;;;;;;;gBAYC,OAAO,UAAU;;;;kBAKf;;;;kBAKA;;;;;;;;;;iBAWF,qBAAA,WACL,4BACR;;;;;;;;;;cA4DU,oBAAoB;;;;;UAMhB,yBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDD,qBAAA,WACL,4BACR;;;;;;;;;;;;;;;;;cA2JU,oBAAoB;;;;;;;;;KAUrB,gBAAA,YAA4B;;;;;;;;iBAqBxB,uBAAA,SAAgC"}
@@ -1 +1 @@
1
- {"version":3,"file":"formatter.d.ts","names":[],"sources":["../formatter.ts"],"sourcesContent":[],"mappings":";;;;;;;AAWA;AA+DA;AA+BA;;;AAuGoB,KArMR,aAAA,GAqMQ,CAAA,MAAA,EArMiB,SAqMjB,EAAA,GAAA,MAAA;AAAe;AAoBnC;;;AAEG,UA5Jc,eAAA,CA4Jd;EAAa;AA6EhB;AAQA;EAyBY,SAAA,EAAA,MAAS,GAAA,IAAA;EA4BJ;;;EAwCW,KAKT,EAAA,MAAA;EAAS;;;EAiBc,QAA1B,EAAA,MAAA;EAAM;;;EA9DiD,OAAA,EAAA,MAAA;EAmFvD;;;EACyB,MACtC,EAnWO,SAmWP;AAAa;AA4DhB;AAMA;AAsDA;;AACW,UArdM,oBAAA,CAqdN;EAA8B;AACzB;AA8FhB;AAUA;AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEArhBe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAyCK;;;;;;;;;;;;;;;;;;;iBAoBJ,gBAAA,WACL,uBACR;;;;;;;;;;;cA6EU,sBAAsB;;;;;KAQvB,SAAA;;;;;KAyBA,SAAA;;;;;UA4BK,yBAAA,SAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAwChC;;;;mBAKA;;;;eAKJ;;;;;;;;;;;gBAYC,OAAO,UAAU;;;;kBAKf;;;;kBAKA;;;;;;;;;;iBAWF,qBAAA,WACL,4BACR;;;;;;;;;;cA4DU,oBAAoB;;;;;UAMhB,yBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDD,qBAAA,WACL,4BACR;;;;;;;;;;;;;;;;;cA8FU,oBAAoB;;;;;;;;;KAUrB,gBAAA,YAA4B;;;;;;;;iBAqBxB,uBAAA,SAAgC"}
1
+ {"version":3,"file":"formatter.d.ts","names":[],"sources":["../formatter.ts"],"sourcesContent":[],"mappings":";;;;;;;AAWA;AA+DA;AA+BA;;;AAuGoB,KArMR,aAAA,GAqMQ,CAAA,MAAA,EArMiB,SAqMjB,EAAA,GAAA,MAAA;AAAe;AAgJnC;;;AAEG,UAxRc,eAAA,CAwRd;EAAa;AAiGhB;AAQA;EAyBY,SAAA,EAAA,MAAS,GAAA,IAAA;EA4BJ;;;EAwCW,KAKT,EAAA,MAAA;EAAS;;;EAiBc,QAA1B,EAAA,MAAA;EAAM;;;EA9DiD,OAAA,EAAA,MAAA;EAmFvD;;;EACyB,MACtC,EAnfO,SAmfP;AAAa;AA4DhB;AAMA;AAsDA;;AACW,UArmBM,oBAAA,CAqmBN;EAA8B;AACzB;AA2JhB;AAUA;AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEAluBe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAyCK;;;;;;;;;;;;;;;;;;;iBAgJJ,gBAAA,WACL,uBACR;;;;;;;;;;;cAiGU,sBAAsB;;;;;KAQvB,SAAA;;;;;KAyBA,SAAA;;;;;UA4BK,yBAAA,SAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAwChC;;;;mBAKA;;;;eAKJ;;;;;;;;;;;gBAYC,OAAO,UAAU;;;;kBAKf;;;;kBAKA;;;;;;;;;;iBAWF,qBAAA,WACL,4BACR;;;;;;;;;;cA4DU,oBAAoB;;;;;UAMhB,yBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDD,qBAAA,WACL,4BACR;;;;;;;;;;;;;;;;;cA2JU,oBAAoB;;;;;;;;;KAUrB,gBAAA,YAA4B;;;;;;;;iBAqBxB,uBAAA,SAAgC"}
package/dist/formatter.js CHANGED
@@ -31,6 +31,123 @@ const inspect = typeof document !== "undefined" || typeof navigator !== "undefin
31
31
  maxStringLength: Infinity,
32
32
  ...opts
33
33
  }) : (v) => JSON.stringify(v);
34
+ function padZero(num) {
35
+ return num < 10 ? `0${num}` : `${num}`;
36
+ }
37
+ function padThree(num) {
38
+ return num < 10 ? `00${num}` : num < 100 ? `0${num}` : `${num}`;
39
+ }
40
+ const timestampFormatters = {
41
+ "date-time-timezone": (ts) => {
42
+ const d = new Date(ts);
43
+ const year = d.getUTCFullYear();
44
+ const month = padZero(d.getUTCMonth() + 1);
45
+ const day = padZero(d.getUTCDate());
46
+ const hour = padZero(d.getUTCHours());
47
+ const minute = padZero(d.getUTCMinutes());
48
+ const second = padZero(d.getUTCSeconds());
49
+ const ms = padThree(d.getUTCMilliseconds());
50
+ return `${year}-${month}-${day} ${hour}:${minute}:${second}.${ms} +00:00`;
51
+ },
52
+ "date-time-tz": (ts) => {
53
+ const d = new Date(ts);
54
+ const year = d.getUTCFullYear();
55
+ const month = padZero(d.getUTCMonth() + 1);
56
+ const day = padZero(d.getUTCDate());
57
+ const hour = padZero(d.getUTCHours());
58
+ const minute = padZero(d.getUTCMinutes());
59
+ const second = padZero(d.getUTCSeconds());
60
+ const ms = padThree(d.getUTCMilliseconds());
61
+ return `${year}-${month}-${day} ${hour}:${minute}:${second}.${ms} +00`;
62
+ },
63
+ "date-time": (ts) => {
64
+ const d = new Date(ts);
65
+ const year = d.getUTCFullYear();
66
+ const month = padZero(d.getUTCMonth() + 1);
67
+ const day = padZero(d.getUTCDate());
68
+ const hour = padZero(d.getUTCHours());
69
+ const minute = padZero(d.getUTCMinutes());
70
+ const second = padZero(d.getUTCSeconds());
71
+ const ms = padThree(d.getUTCMilliseconds());
72
+ return `${year}-${month}-${day} ${hour}:${minute}:${second}.${ms}`;
73
+ },
74
+ "time-timezone": (ts) => {
75
+ const d = new Date(ts);
76
+ const hour = padZero(d.getUTCHours());
77
+ const minute = padZero(d.getUTCMinutes());
78
+ const second = padZero(d.getUTCSeconds());
79
+ const ms = padThree(d.getUTCMilliseconds());
80
+ return `${hour}:${minute}:${second}.${ms} +00:00`;
81
+ },
82
+ "time-tz": (ts) => {
83
+ const d = new Date(ts);
84
+ const hour = padZero(d.getUTCHours());
85
+ const minute = padZero(d.getUTCMinutes());
86
+ const second = padZero(d.getUTCSeconds());
87
+ const ms = padThree(d.getUTCMilliseconds());
88
+ return `${hour}:${minute}:${second}.${ms} +00`;
89
+ },
90
+ "time": (ts) => {
91
+ const d = new Date(ts);
92
+ const hour = padZero(d.getUTCHours());
93
+ const minute = padZero(d.getUTCMinutes());
94
+ const second = padZero(d.getUTCSeconds());
95
+ const ms = padThree(d.getUTCMilliseconds());
96
+ return `${hour}:${minute}:${second}.${ms}`;
97
+ },
98
+ "date": (ts) => {
99
+ const d = new Date(ts);
100
+ const year = d.getUTCFullYear();
101
+ const month = padZero(d.getUTCMonth() + 1);
102
+ const day = padZero(d.getUTCDate());
103
+ return `${year}-${month}-${day}`;
104
+ },
105
+ "rfc3339": (ts) => new Date(ts).toISOString(),
106
+ "none": () => null
107
+ };
108
+ const levelRenderersCache = {
109
+ ABBR: levelAbbreviations,
110
+ abbr: {
111
+ trace: "trc",
112
+ debug: "dbg",
113
+ info: "inf",
114
+ warning: "wrn",
115
+ error: "err",
116
+ fatal: "ftl"
117
+ },
118
+ FULL: {
119
+ trace: "TRACE",
120
+ debug: "DEBUG",
121
+ info: "INFO",
122
+ warning: "WARNING",
123
+ error: "ERROR",
124
+ fatal: "FATAL"
125
+ },
126
+ full: {
127
+ trace: "trace",
128
+ debug: "debug",
129
+ info: "info",
130
+ warning: "warning",
131
+ error: "error",
132
+ fatal: "fatal"
133
+ },
134
+ L: {
135
+ trace: "T",
136
+ debug: "D",
137
+ info: "I",
138
+ warning: "W",
139
+ error: "E",
140
+ fatal: "F"
141
+ },
142
+ l: {
143
+ trace: "t",
144
+ debug: "d",
145
+ info: "i",
146
+ warning: "w",
147
+ error: "e",
148
+ fatal: "f"
149
+ }
150
+ };
34
151
  /**
35
152
  * Get a text formatter with the specified options. Although it's flexible
36
153
  * enough to create a custom formatter, if you want more control, you can
@@ -49,15 +166,39 @@ const inspect = typeof document !== "undefined" || typeof navigator !== "undefin
49
166
  * @since 0.6.0
50
167
  */
51
168
  function getTextFormatter(options = {}) {
52
- const timestampRenderer = options.timestamp == null || options.timestamp === "date-time-timezone" ? (ts) => new Date(ts).toISOString().replace("T", " ").replace("Z", " +00:00") : options.timestamp === "date-time-tz" ? (ts) => new Date(ts).toISOString().replace("T", " ").replace("Z", " +00") : options.timestamp === "date-time" ? (ts) => new Date(ts).toISOString().replace("T", " ").replace("Z", "") : options.timestamp === "time-timezone" ? (ts) => new Date(ts).toISOString().replace(/.*T/, "").replace("Z", " +00:00") : options.timestamp === "time-tz" ? (ts) => new Date(ts).toISOString().replace(/.*T/, "").replace("Z", " +00") : options.timestamp === "time" ? (ts) => new Date(ts).toISOString().replace(/.*T/, "").replace("Z", "") : options.timestamp === "date" ? (ts) => new Date(ts).toISOString().replace(/T.*/, "") : options.timestamp === "rfc3339" ? (ts) => new Date(ts).toISOString() : options.timestamp === "none" || options.timestamp === "disabled" ? () => null : options.timestamp;
169
+ const timestampRenderer = (() => {
170
+ const tsOption = options.timestamp;
171
+ if (tsOption == null) return timestampFormatters["date-time-timezone"];
172
+ else if (tsOption === "disabled") return timestampFormatters["none"];
173
+ else if (typeof tsOption === "string" && tsOption in timestampFormatters) return timestampFormatters[tsOption];
174
+ else return tsOption;
175
+ })();
53
176
  const categorySeparator = options.category ?? "·";
54
177
  const valueRenderer = options.value ?? inspect;
55
- const levelRenderer = options.level == null || options.level === "ABBR" ? (level) => levelAbbreviations[level] : options.level === "abbr" ? (level) => levelAbbreviations[level].toLowerCase() : options.level === "FULL" ? (level) => level.toUpperCase() : options.level === "full" ? (level) => level : options.level === "L" ? (level) => level.charAt(0).toUpperCase() : options.level === "l" ? (level) => level.charAt(0) : options.level;
178
+ const levelRenderer = (() => {
179
+ const levelOption = options.level;
180
+ if (levelOption == null || levelOption === "ABBR") return (level) => levelRenderersCache.ABBR[level];
181
+ else if (levelOption === "abbr") return (level) => levelRenderersCache.abbr[level];
182
+ else if (levelOption === "FULL") return (level) => levelRenderersCache.FULL[level];
183
+ else if (levelOption === "full") return (level) => levelRenderersCache.full[level];
184
+ else if (levelOption === "L") return (level) => levelRenderersCache.L[level];
185
+ else if (levelOption === "l") return (level) => levelRenderersCache.l[level];
186
+ else return levelOption;
187
+ })();
56
188
  const formatter = options.format ?? (({ timestamp, level, category, message }) => `${timestamp ? `${timestamp} ` : ""}[${level}] ${category}: ${message}`);
57
189
  return (record) => {
58
- let message = "";
59
- for (let i = 0; i < record.message.length; i++) if (i % 2 === 0) message += record.message[i];
60
- else message += valueRenderer(record.message[i]);
190
+ const msgParts = record.message;
191
+ const msgLen = msgParts.length;
192
+ let message;
193
+ if (msgLen === 1) message = msgParts[0];
194
+ else if (msgLen <= 6) {
195
+ message = "";
196
+ for (let i = 0; i < msgLen; i++) message += i % 2 === 0 ? msgParts[i] : valueRenderer(msgParts[i]);
197
+ } else {
198
+ const parts = new Array(msgLen);
199
+ for (let i = 0; i < msgLen; i++) parts[i] = i % 2 === 0 ? msgParts[i] : valueRenderer(msgParts[i]);
200
+ message = parts.join("");
201
+ }
61
202
  const timestamp = timestampRenderer(record.timestamp);
62
203
  const level = levelRenderer(record.level);
63
204
  const category = typeof categorySeparator === "function" ? categorySeparator(record.category) : record.category.join(categorySeparator);
@@ -174,25 +315,39 @@ const ansiColorFormatter = getAnsiColorFormatter();
174
315
  * @since 0.11.0
175
316
  */
176
317
  function getJsonLinesFormatter(options = {}) {
318
+ if (!options.categorySeparator && !options.message && !options.properties) return (record) => {
319
+ if (record.message.length === 3) return JSON.stringify({
320
+ "@timestamp": new Date(record.timestamp).toISOString(),
321
+ level: record.level === "warning" ? "WARN" : record.level.toUpperCase(),
322
+ message: record.message[0] + JSON.stringify(record.message[1]) + record.message[2],
323
+ logger: record.category.join("."),
324
+ properties: record.properties
325
+ });
326
+ if (record.message.length === 1) return JSON.stringify({
327
+ "@timestamp": new Date(record.timestamp).toISOString(),
328
+ level: record.level === "warning" ? "WARN" : record.level.toUpperCase(),
329
+ message: record.message[0],
330
+ logger: record.category.join("."),
331
+ properties: record.properties
332
+ });
333
+ let msg = record.message[0];
334
+ for (let i = 1; i < record.message.length; i++) msg += i & 1 ? JSON.stringify(record.message[i]) : record.message[i];
335
+ return JSON.stringify({
336
+ "@timestamp": new Date(record.timestamp).toISOString(),
337
+ level: record.level === "warning" ? "WARN" : record.level.toUpperCase(),
338
+ message: msg,
339
+ logger: record.category.join("."),
340
+ properties: record.properties
341
+ });
342
+ };
343
+ const isTemplateMessage = options.message === "template";
344
+ const propertiesOption = options.properties ?? "nest:properties";
177
345
  let joinCategory;
178
346
  if (typeof options.categorySeparator === "function") joinCategory = options.categorySeparator;
179
347
  else {
180
348
  const separator = options.categorySeparator ?? ".";
181
349
  joinCategory = (category) => category.join(separator);
182
350
  }
183
- let getMessage;
184
- if (options.message === "template") getMessage = (record) => {
185
- if (typeof record.rawMessage === "string") return record.rawMessage;
186
- let msg = "";
187
- for (let i = 0; i < record.rawMessage.length; i++) msg += i % 2 < 1 ? record.rawMessage[i] : "{}";
188
- return msg;
189
- };
190
- else getMessage = (record) => {
191
- let msg = "";
192
- for (let i = 0; i < record.message.length; i++) msg += i % 2 < 1 ? record.message[i] : JSON.stringify(record.message[i]);
193
- return msg;
194
- };
195
- const propertiesOption = options.properties ?? "nest:properties";
196
351
  let getProperties;
197
352
  if (propertiesOption === "flatten") getProperties = (properties) => properties;
198
353
  else if (propertiesOption.startsWith("prepend:")) {
@@ -207,6 +362,20 @@ function getJsonLinesFormatter(options = {}) {
207
362
  const key = propertiesOption.substring(5);
208
363
  getProperties = (properties) => ({ [key]: properties });
209
364
  } else throw new TypeError(`Invalid properties option: ${JSON.stringify(propertiesOption)}. It must be "flatten", "prepend:<prefix>", or "nest:<key>".`);
365
+ let getMessage;
366
+ if (isTemplateMessage) getMessage = (record) => {
367
+ if (typeof record.rawMessage === "string") return record.rawMessage;
368
+ let msg = "";
369
+ for (let i = 0; i < record.rawMessage.length; i++) msg += i % 2 < 1 ? record.rawMessage[i] : "{}";
370
+ return msg;
371
+ };
372
+ else getMessage = (record) => {
373
+ const msgLen = record.message.length;
374
+ if (msgLen === 1) return record.message[0];
375
+ let msg = "";
376
+ for (let i = 0; i < msgLen; i++) msg += i % 2 < 1 ? record.message[i] : JSON.stringify(record.message[i]);
377
+ return msg;
378
+ };
210
379
  return (record) => {
211
380
  return JSON.stringify({
212
381
  "@timestamp": new Date(record.timestamp).toISOString(),