1 | import { relative } from "node:path";
|
2 | import { fileURLToPath } from "node:url";
|
3 | import { inspect } from "node:util";
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | export function loggerWritePretty(stream, level, timestamp, context, message) {
|
14 | stream.write(`${loggerFormatPretty(level, timestamp, context, message)}\n`);
|
15 | }
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | export function loggerWriteGithubActions(
|
26 | stream,
|
27 | level,
|
28 | timestamp,
|
29 | context,
|
30 | message,
|
31 | ) {
|
32 | if (level === "error") {
|
33 |
|
34 | const { relativePath, column, line } = loggerGetCaller();
|
35 |
|
36 |
|
37 |
|
38 | stream.write(
|
39 | `::error file=${relativePath},line=${line},col=${column}::${loggerFormatPretty(
|
40 | undefined, // Always an error
|
41 | timestamp,
|
42 | context,
|
43 | message,
|
44 | )
|
45 | .replace(/\n/g, "%0A")
|
46 |
|
47 | // Removes ansi color codes from logs
|
48 | // eslint-disable-next-line no-control-regex
|
49 | .replace(/\u001b\[.*?m/g, "")}\n`,
|
50 | );
|
51 | } else {
|
52 | loggerWritePretty(stream, level, timestamp, context, message);
|
53 | }
|
54 | }
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 | export function loggerFormatPretty(level, timestamp, context, message) {
|
64 | let prefix = level
|
65 | ? `${loggerFormatDate(timestamp)} ${loggerFormatLevel(
|
66 | level,
|
67 | context?.type,
|
68 | )} `
|
69 | : "";
|
70 |
|
71 | if (Object.keys(context).length > (context?.type ? 1 : 0)) {
|
72 | prefix += `${loggerFormatMessagePretty(context)} `;
|
73 | }
|
74 |
|
75 | if (message) {
|
76 | return `${prefix + loggerFormatMessagePretty(message)}`;
|
77 | }
|
78 |
|
79 | return prefix;
|
80 | }
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 | function loggerFormatMessagePretty(value) {
|
87 | if (
|
88 | typeof value === "boolean" ||
|
89 | typeof value === "string" ||
|
90 | typeof value === "number"
|
91 | ) {
|
92 | return String(value);
|
93 | }
|
94 |
|
95 | return inspect(value, {
|
96 | colors: true,
|
97 | depth: null,
|
98 | });
|
99 | }
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | function loggerFormatDate(date) {
|
106 | const h = date.getHours().toString(10).padStart(2, "0");
|
107 | const m = date.getMinutes().toString(10).padStart(2, "0");
|
108 | const s = date.getSeconds().toString(10).padStart(2, "0");
|
109 | const ms = date.getMilliseconds().toString(10).padStart(3, "0");
|
110 |
|
111 | return `${h}:${m}:${s}.${ms}`;
|
112 | }
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 | function loggerFormatLevel(level, type) {
|
120 | const str =
|
121 | typeof type === "string" && type.length > 0 ? `${level}[${type}]` : level;
|
122 |
|
123 | return level === "error"
|
124 | ? `\x1b[31m${str}\x1b[39m`
|
125 | : `\x1b[34m${str}\x1b[39m`;
|
126 | }
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 | function loggerGetCaller() {
|
138 | const err = {};
|
139 | Error.captureStackTrace(err);
|
140 |
|
141 | const stackLines = err.stack.split("\n").slice(1);
|
142 |
|
143 | let callerStackLine = stackLines[0].trim();
|
144 | for (const line of stackLines) {
|
145 | if (
|
146 | line.includes("loggerGetCaller") ||
|
147 | line.includes("loggerWriteGithubActions") ||
|
148 | line.includes("Object.write") ||
|
149 | line.includes("Object.error") ||
|
150 | line.includes("Pino.")
|
151 | ) {
|
152 | continue;
|
153 | }
|
154 |
|
155 | callerStackLine = line.trim();
|
156 | break;
|
157 | }
|
158 |
|
159 | const rawLocation =
|
160 | callerStackLine.split(" ")[callerStackLine.includes(" async ") ? 3 : 2];
|
161 |
|
162 | if (callerStackLine.length === 0 || (rawLocation?.length ?? 0) < 5) {
|
163 | return {
|
164 | relativePath: rawLocation,
|
165 | line: 1,
|
166 | column: 1,
|
167 | };
|
168 | }
|
169 |
|
170 | const rawLocationParts = rawLocation
|
171 | .substring(1, rawLocation.length - 1)
|
172 | .split(":");
|
173 |
|
174 | const rawFile = rawLocationParts
|
175 | .splice(0, rawLocationParts.length - 2)
|
176 | .join(":");
|
177 |
|
178 | return {
|
179 | relativePath: relative(process.cwd(), fileURLToPath(rawFile)),
|
180 | line: rawLocationParts[0],
|
181 | column: rawLocationParts[1],
|
182 | };
|
183 | }
|