@subsquid/logger 0.0.1
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/README.md +71 -0
- package/lib/demo.d.ts +2 -0
- package/lib/demo.d.ts.map +1 -0
- package/lib/demo.js +19 -0
- package/lib/demo.js.map +1 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +25 -0
- package/lib/index.js.map +1 -0
- package/lib/level.d.ts +17 -0
- package/lib/level.d.ts.map +1 -0
- package/lib/level.js +82 -0
- package/lib/level.js.map +1 -0
- package/lib/level.test.d.ts +2 -0
- package/lib/level.test.d.ts.map +1 -0
- package/lib/level.test.js +73 -0
- package/lib/level.test.js.map +1 -0
- package/lib/logger.d.ts +39 -0
- package/lib/logger.d.ts.map +1 -0
- package/lib/logger.js +106 -0
- package/lib/logger.js.map +1 -0
- package/lib/sinks/json.d.ts +3 -0
- package/lib/sinks/json.d.ts.map +1 -0
- package/lib/sinks/json.js +24 -0
- package/lib/sinks/json.js.map +1 -0
- package/lib/sinks/pretty.d.ts +19 -0
- package/lib/sinks/pretty.d.ts.map +1 -0
- package/lib/sinks/pretty.js +244 -0
- package/lib/sinks/pretty.js.map +1 -0
- package/package.json +33 -0
- package/src/demo.ts +23 -0
- package/src/index.ts +17 -0
- package/src/level.test.ts +80 -0
- package/src/level.ts +96 -0
- package/src/logger.ts +146 -0
- package/src/sinks/json.ts +23 -0
- package/src/sinks/pretty.ts +248 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.prettyStderrSink = exports.Printer = void 0;
|
|
7
|
+
const util_internal_hex_1 = require("@subsquid/util-internal-hex");
|
|
8
|
+
const assert_1 = __importDefault(require("assert"));
|
|
9
|
+
const supports_color_1 = require("supports-color");
|
|
10
|
+
const level_1 = require("../level");
|
|
11
|
+
class Printer {
|
|
12
|
+
constructor(out, hasColor) {
|
|
13
|
+
this.out = out;
|
|
14
|
+
this.hasColor = hasColor;
|
|
15
|
+
this.visited = new Set();
|
|
16
|
+
this.seenRecursion = false;
|
|
17
|
+
}
|
|
18
|
+
line(s) {
|
|
19
|
+
if (s && this.hasColor && this.style) {
|
|
20
|
+
s = this.style.open + s + this.style.close;
|
|
21
|
+
}
|
|
22
|
+
if (this.prefix) {
|
|
23
|
+
this.out(this.prefix.prepend(s));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
this.out(s);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
text(text) {
|
|
30
|
+
for (let line of text.split(/\r?\n/)) {
|
|
31
|
+
this.line(line);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
begin(prefix, width) {
|
|
35
|
+
width = width == null ? prefix.length : width;
|
|
36
|
+
if (this.hasColor && this.style) {
|
|
37
|
+
prefix = this.style.open + prefix + this.style.close;
|
|
38
|
+
}
|
|
39
|
+
this.prefix = new Prefix(prefix, width, this.prefix);
|
|
40
|
+
}
|
|
41
|
+
end() {
|
|
42
|
+
(0, assert_1.default)(this.prefix != null);
|
|
43
|
+
this.prefix = this.prefix.prev;
|
|
44
|
+
}
|
|
45
|
+
property(prefix, val) {
|
|
46
|
+
switch (typeof val) {
|
|
47
|
+
case "symbol":
|
|
48
|
+
case "string":
|
|
49
|
+
this.begin(prefix);
|
|
50
|
+
this.text(val.toString());
|
|
51
|
+
this.end();
|
|
52
|
+
break;
|
|
53
|
+
case "boolean":
|
|
54
|
+
case "bigint":
|
|
55
|
+
case "number":
|
|
56
|
+
this.line(`${prefix} ${val}`);
|
|
57
|
+
break;
|
|
58
|
+
case "object":
|
|
59
|
+
if (val instanceof Uint8Array) {
|
|
60
|
+
this.line(`${prefix} ${(0, util_internal_hex_1.toHex)(val)}`);
|
|
61
|
+
}
|
|
62
|
+
else if (val instanceof Date) {
|
|
63
|
+
this.line(`${prefix} ${val}`);
|
|
64
|
+
}
|
|
65
|
+
else if (typeof val?.toJSON == 'function') {
|
|
66
|
+
this.property(prefix, val.toJSON());
|
|
67
|
+
}
|
|
68
|
+
else if (Array.isArray(val)) {
|
|
69
|
+
if (val.length == 0) {
|
|
70
|
+
this.line(`${prefix} []`);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
if (this.visited.has(val)) {
|
|
74
|
+
this.seenRecursion = true;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
this.visited.add(val);
|
|
79
|
+
}
|
|
80
|
+
this.line(prefix);
|
|
81
|
+
for (let item of val) {
|
|
82
|
+
this.property(' -', item);
|
|
83
|
+
}
|
|
84
|
+
this.visited.delete(val);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else if (val == null) {
|
|
88
|
+
this.line(`${prefix} null`);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
if (this.visited.has(val)) {
|
|
92
|
+
this.seenRecursion = true;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
this.visited.add(val);
|
|
97
|
+
}
|
|
98
|
+
let has = false;
|
|
99
|
+
for (let key in val) {
|
|
100
|
+
if (!has) {
|
|
101
|
+
if (prefix == ' -') {
|
|
102
|
+
this.begin(prefix);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
this.line(prefix);
|
|
106
|
+
this.begin(' ');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
has = true;
|
|
110
|
+
this.property(key + ':', val[key]);
|
|
111
|
+
}
|
|
112
|
+
if (has) {
|
|
113
|
+
this.end();
|
|
114
|
+
}
|
|
115
|
+
this.visited.delete(val);
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
print(rec) {
|
|
121
|
+
this.begin(formatHead(rec, this.hasColor), 14 + (rec.ns ? rec.ns.length + 1 : 0));
|
|
122
|
+
if (rec.msg) {
|
|
123
|
+
this.text(rec.msg);
|
|
124
|
+
}
|
|
125
|
+
this.style = { open: '\u001b[2m', close: '\u001b[22m' }; // dim
|
|
126
|
+
if (rec.err instanceof Error) {
|
|
127
|
+
this.text(rec.err.stack || rec.err.toString());
|
|
128
|
+
}
|
|
129
|
+
for (let key in rec) {
|
|
130
|
+
switch (key) {
|
|
131
|
+
case 'time':
|
|
132
|
+
case 'ns':
|
|
133
|
+
case 'level':
|
|
134
|
+
case 'msg':
|
|
135
|
+
break;
|
|
136
|
+
default:
|
|
137
|
+
this.property(key + ':', rec[key]);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
this.end();
|
|
141
|
+
if (this.seenRecursion) {
|
|
142
|
+
this.reset();
|
|
143
|
+
this.print({
|
|
144
|
+
ns: 'sys',
|
|
145
|
+
time: Date.now(),
|
|
146
|
+
level: level_1.LogLevel.ERROR,
|
|
147
|
+
msg: 'Previous record contained recursive data.\n' +
|
|
148
|
+
'Serialisation of such records is not supported in production.'
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
reset() {
|
|
153
|
+
this.visited.clear();
|
|
154
|
+
this.prefix = undefined;
|
|
155
|
+
this.style = undefined;
|
|
156
|
+
this.seenRecursion = false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
exports.Printer = Printer;
|
|
160
|
+
function formatHead(rec, withColor) {
|
|
161
|
+
let time = formatTime(rec.time);
|
|
162
|
+
let level = level_1.LogLevel[rec.level].padEnd(5, ' ');
|
|
163
|
+
let ns = rec.ns;
|
|
164
|
+
if (withColor) {
|
|
165
|
+
level = `\u001b[1m\u001b[${getLevelColor(rec.level)}m${level}\u001b[0m`;
|
|
166
|
+
ns = `\u001b[1m\u001b[34m${ns}\u001b[0m`;
|
|
167
|
+
}
|
|
168
|
+
let head = time + ' ' + level;
|
|
169
|
+
if (rec.ns) {
|
|
170
|
+
head += ' ' + ns;
|
|
171
|
+
}
|
|
172
|
+
return head;
|
|
173
|
+
}
|
|
174
|
+
function getLevelColor(level) {
|
|
175
|
+
switch (level) {
|
|
176
|
+
case level_1.LogLevel.TRACE:
|
|
177
|
+
return 35;
|
|
178
|
+
case level_1.LogLevel.DEBUG:
|
|
179
|
+
return 32;
|
|
180
|
+
case level_1.LogLevel.INFO:
|
|
181
|
+
return 36;
|
|
182
|
+
case level_1.LogLevel.WARN:
|
|
183
|
+
return 33;
|
|
184
|
+
case level_1.LogLevel.ERROR:
|
|
185
|
+
case level_1.LogLevel.FATAL:
|
|
186
|
+
return 31;
|
|
187
|
+
default:
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function formatTime(time) {
|
|
192
|
+
let date = new Date(time);
|
|
193
|
+
let hour = date.getHours().toString().padStart(2, '0');
|
|
194
|
+
let minutes = date.getMinutes().toString().padStart(2, '0');
|
|
195
|
+
let seconds = date.getSeconds().toString().padStart(2, '0');
|
|
196
|
+
return `${hour}:${minutes}:${seconds}`;
|
|
197
|
+
}
|
|
198
|
+
class Prefix {
|
|
199
|
+
constructor(value, width, prev) {
|
|
200
|
+
this.value = value;
|
|
201
|
+
this.prev = prev;
|
|
202
|
+
this.indent = '';
|
|
203
|
+
this.offset = (this.prev?.offset || 0) + width + 1;
|
|
204
|
+
}
|
|
205
|
+
prepend(s) {
|
|
206
|
+
if (this.value) {
|
|
207
|
+
let val = this.value;
|
|
208
|
+
if (this.prev) {
|
|
209
|
+
val = this.prev.prepend(val);
|
|
210
|
+
}
|
|
211
|
+
this.value = '';
|
|
212
|
+
return s ? val + ' ' + s : val;
|
|
213
|
+
}
|
|
214
|
+
else if (s) {
|
|
215
|
+
this.indent = this.indent || ''.padEnd(this.offset, ' ');
|
|
216
|
+
return this.indent + s;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
return s;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const PRINTER = new Printer(line => {
|
|
224
|
+
process.stderr.write(line + '\n');
|
|
225
|
+
}, !!supports_color_1.stderr);
|
|
226
|
+
function prettyStderrSink(rec) {
|
|
227
|
+
try {
|
|
228
|
+
PRINTER.print(rec);
|
|
229
|
+
}
|
|
230
|
+
catch (e) {
|
|
231
|
+
PRINTER.reset();
|
|
232
|
+
PRINTER.print({
|
|
233
|
+
ns: 'sys',
|
|
234
|
+
level: level_1.LogLevel.ERROR,
|
|
235
|
+
time: Date.now(),
|
|
236
|
+
msg: e.stack || e.toString()
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
PRINTER.reset();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
exports.prettyStderrSink = prettyStderrSink;
|
|
244
|
+
//# sourceMappingURL=pretty.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pretty.js","sourceRoot":"","sources":["../../src/sinks/pretty.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@subsquid/logger",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Lightweight library for structured logging",
|
|
5
|
+
"license": "GPL-3.0-or-later",
|
|
6
|
+
"repository": "git@github.com:subsquid/squid.git",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"lib",
|
|
12
|
+
"src"
|
|
13
|
+
],
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@subsquid/util-internal-hex": "^0.0.0",
|
|
17
|
+
"@subsquid/util-internal-json": "^0.1.0",
|
|
18
|
+
"supports-color": "^8.1.1"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/mocha": "^9.1.1",
|
|
22
|
+
"@types/node": "^16.11.22",
|
|
23
|
+
"@types/supports-color": "^8.1.1",
|
|
24
|
+
"expect": "^27.5.1",
|
|
25
|
+
"mocha": "^9.2.2",
|
|
26
|
+
"typescript": "~4.5.5"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "rm -rf lib && tsc",
|
|
30
|
+
"test": "mocha lib/**/*.test.js"
|
|
31
|
+
},
|
|
32
|
+
"readme": "# @subsquid/logger\n\nLightweight structured logger for squid framework.\n\n## Usage\n\n```typescript\nimport {createLogger} from \"@subsquid/logger\"\n\nconst log = createLogger('sqd:demo')\n\nlog.info('message with severity info')\nlog.debug('message with severity debug')\n\nlog.info({foo: 1, bar: 2}, 'message and some additional attributes')\n\n// info message consisting only of attributes\nlog.info({a: 1, b: 2, c: 3, array: [4, 5]}) \n\n// pass an Error object inplace of attributes\nlog.warn(new Error('Some error occured'))\n\n// Error together with some other attributes and message\nlog.error({err: new Error('Another error'), a: 1, b: 2}, 'weird')\n\n// create a child logger instance with namespace `sqd:demo:sql` \n// and `req: 1` attribute attached to every log record\nconst sqlLog = log.child('sql', {req: 1})\nsqlLog.debug('connecting to database')\nsqlLog.debug({sql: 'SELECT max(id) FROM status'})\n```\n\n## Configuration\n\nThere are 6 log levels available: `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL`.\n\nThe log level of each logger instance is solely determined by its namespace and specified\nvia set of `SQD_TRACE`, ..., `SQD_FATAL` environment variables.\nThe default log level is `INFO`. \n\nUsers override the default log level by setting in appropriate \nenvironment variable a pattern which matches the logger's namespace.\n\n* `SQD_DEBUG=*` - sets the log level to `DEBUG` for all loggers.\n* `SQD_DEBUG=foo` - loggers `foo`, `foo:bar`, `foo:a:b`, etc will have a `DEBUG` level.\n* `SQD_DEBUG=a:b*:c,d` - loggers `a:b:c`, `a:baz:c`, `a:baz:c:foo`, `d`, etc will have a `DEBUG` level, logger `a:z:c` will not.\n\nWhen logger is matched by multiple `SQD_*` variables, the match with the highest specificity wins.\nWhen specificities are equal, the most verbose matched log level will be effective.\n\nSpecificity is computed as a number of namespace characters \nwhich are not matched by wildcards and which are not part of a child namespace.\nFor example, given a pattern `foo*bar`, the specificity of `foo:bar:baz:qux`, `foobar` and `foobazbar` is `6`.\n\n## Output\n\nThe logger always writes to `stderr`. \n\nWhen `stderr` is connected to a terminal, log records will be pretty printed.\n\n\n\nOtherwise, log records will be written as JSON lines.\n\n```\n{\"level\":2,\"time\":1650875498437,\"ns\":\"sqd:demo\",\"msg\":\"message with severity info\"}\n{\"level\":2,\"time\":1650875498437,\"ns\":\"sqd:demo\",\"msg\":\"message and some additional attributes\",\"foo\":1,\"bar\":2}\n{\"level\":2,\"time\":1650875498437,\"ns\":\"sqd:demo\",\"a\":1,\"b\":2,\"c\":3,\"array\":[4,5]}\n{\"level\":3,\"time\":1650875498437,\"ns\":\"sqd:demo\",\"err\":{\"stack\":\"Error: Some error occured\\n at Object.<anonymous> (/Users/eldar/dev/squid/util/logger/lib/demo.js:11:10)\\n at Module._compile (node:internal/modules/cjs/loader:1103:14)\\n at Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)\\n at Module.load (node:internal/modules/cjs/loader:981:32)\\n at Function.Module._load (node:internal/modules/cjs/loader:822:12)\\n at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\\n at node:internal/main/run_main_module:17:47\"}}\n{\"level\":4,\"time\":1650875498438,\"ns\":\"sqd:demo\",\"msg\":\"weird\",\"err\":{\"stack\":\"Error: Another error\\n at Object.<anonymous> (/Users/eldar/dev/squid/util/logger/lib/demo.js:13:18)\\n at Module._compile (node:internal/modules/cjs/loader:1103:14)\\n at Object.Module._extensions..js (node:internal/modules/cjs/loader:1155:10)\\n at Module.load (node:internal/modules/cjs/loader:981:32)\\n at Function.Module._load (node:internal/modules/cjs/loader:822:12)\\n at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\\n at node:internal/main/run_main_module:17:47\"},\"a\":1,\"b\":2}\n```\n"
|
|
33
|
+
}
|
package/src/demo.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {createLogger} from "./index"
|
|
2
|
+
|
|
3
|
+
const log = createLogger('sqd:demo')
|
|
4
|
+
|
|
5
|
+
log.info('message with severity info')
|
|
6
|
+
log.debug('message with severity debug')
|
|
7
|
+
|
|
8
|
+
log.info({foo: 1, bar: 2}, 'message and some additional attributes')
|
|
9
|
+
|
|
10
|
+
// info message consisting only of attributes
|
|
11
|
+
log.info({a: 1, b: 2, c: 3, array: [4, 5, {a: 1, b: 2, c: {foo: 'foo', bar: 'bar'}}, {a: 3, b: 4}]})
|
|
12
|
+
|
|
13
|
+
// pass an Error object inplace of attributes
|
|
14
|
+
log.warn(new Error('Some error occured'))
|
|
15
|
+
|
|
16
|
+
// Error together with some other attributes and message
|
|
17
|
+
log.error({err: new Error('Another error'), a: 1, b: 2}, 'weird')
|
|
18
|
+
|
|
19
|
+
// create a child logger instance with namespace `sqd:demo:sql`
|
|
20
|
+
// and `req: 1` attribute attached to every log record
|
|
21
|
+
const sqlLog = log.child('sql', {req: 1})
|
|
22
|
+
sqlLog.debug('connecting to database')
|
|
23
|
+
sqlLog.debug({sql: 'SELECT max(id) FROM status'})
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {Logger} from "./logger"
|
|
2
|
+
import {jsonLinesStderrSink} from "./sinks/json"
|
|
3
|
+
import {prettyStderrSink} from "./sinks/pretty"
|
|
4
|
+
|
|
5
|
+
export {LogLevel} from "./level"
|
|
6
|
+
export * from "./logger"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const ROOT = new Logger(
|
|
10
|
+
process.stderr.isTTY ? prettyStderrSink : jsonLinesStderrSink,
|
|
11
|
+
''
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export function createLogger(ns: string, attributes?: object): Logger {
|
|
16
|
+
return ROOT.child(ns, attributes)
|
|
17
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import assert from "assert"
|
|
2
|
+
import {Levels, LogLevel} from "./level"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
function suite(
|
|
6
|
+
config: [level: LogLevel, pattern: string][],
|
|
7
|
+
tests: [ns: string, level: LogLevel][]
|
|
8
|
+
) {
|
|
9
|
+
let name = config.map(([level, pattern]) => LogLevel[level] + '=' + pattern).join('; ')
|
|
10
|
+
describe(name ? 'with ' + name : 'by default', function() {
|
|
11
|
+
let levels = new Levels()
|
|
12
|
+
config.forEach(([level, pattern]) => {
|
|
13
|
+
levels.configure(level, pattern)
|
|
14
|
+
})
|
|
15
|
+
tests.forEach(([ns, level]) => {
|
|
16
|
+
it(ns + '=' + LogLevel[level], () => {
|
|
17
|
+
assert.strictEqual(levels.get(ns), level)
|
|
18
|
+
})
|
|
19
|
+
})
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
describe("levels", function() {
|
|
25
|
+
suite([], [
|
|
26
|
+
['foo', LogLevel.INFO]
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
suite([
|
|
30
|
+
[LogLevel.DEBUG, '*']
|
|
31
|
+
], [
|
|
32
|
+
['foo', LogLevel.DEBUG],
|
|
33
|
+
['bar', LogLevel.DEBUG]
|
|
34
|
+
])
|
|
35
|
+
|
|
36
|
+
suite([
|
|
37
|
+
[LogLevel.DEBUG, 'foo']
|
|
38
|
+
], [
|
|
39
|
+
['foo', LogLevel.DEBUG],
|
|
40
|
+
['foo:bar', LogLevel.DEBUG],
|
|
41
|
+
['foobar', LogLevel.INFO]
|
|
42
|
+
])
|
|
43
|
+
|
|
44
|
+
suite([
|
|
45
|
+
[LogLevel.DEBUG, 'foo:*']
|
|
46
|
+
], [
|
|
47
|
+
['foo', LogLevel.INFO],
|
|
48
|
+
['foo:bar', LogLevel.DEBUG],
|
|
49
|
+
['foobar', LogLevel.INFO]
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
suite([
|
|
53
|
+
[LogLevel.DEBUG, 'foo*bar']
|
|
54
|
+
], [
|
|
55
|
+
['foobar', LogLevel.DEBUG],
|
|
56
|
+
['foo:bar', LogLevel.DEBUG],
|
|
57
|
+
['foo:baz:bar:qux', LogLevel.DEBUG],
|
|
58
|
+
['foobaz', LogLevel.INFO]
|
|
59
|
+
])
|
|
60
|
+
|
|
61
|
+
suite([
|
|
62
|
+
[LogLevel.DEBUG, '*'],
|
|
63
|
+
[LogLevel.WARN, 'foo'],
|
|
64
|
+
[LogLevel.ERROR, 'foo:*:bar']
|
|
65
|
+
], [
|
|
66
|
+
['bar', LogLevel.DEBUG],
|
|
67
|
+
['foo', LogLevel.WARN],
|
|
68
|
+
['foo:bar', LogLevel.WARN],
|
|
69
|
+
['foo:qux:bar', LogLevel.ERROR]
|
|
70
|
+
])
|
|
71
|
+
|
|
72
|
+
suite([
|
|
73
|
+
[LogLevel.DEBUG, 'foo, foo:*:baz'],
|
|
74
|
+
[LogLevel.WARN, 'foo:*']
|
|
75
|
+
], [
|
|
76
|
+
['foo', LogLevel.DEBUG],
|
|
77
|
+
['foo:bar:baz', LogLevel.DEBUG],
|
|
78
|
+
['foo:bar', LogLevel.WARN]
|
|
79
|
+
])
|
|
80
|
+
})
|
package/src/level.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export enum LogLevel {
|
|
2
|
+
TRACE = 0,
|
|
3
|
+
DEBUG = 1,
|
|
4
|
+
INFO = 2,
|
|
5
|
+
WARN = 3,
|
|
6
|
+
ERROR = 4,
|
|
7
|
+
FATAL = 5
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
type Specificity = number
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
interface NamespaceMatcher {
|
|
15
|
+
(ns: string): Specificity
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
function compileLevelConfig(config: string): NamespaceMatcher {
|
|
20
|
+
let variants = config.split(',').map(ns => {
|
|
21
|
+
ns = ns.trim()
|
|
22
|
+
let regex = new RegExp('^' + ns.split('*').map(escapeRegex).join('(.*)') + '(:.*)?$')
|
|
23
|
+
return function match(ns: string) {
|
|
24
|
+
let m = regex.exec(ns)
|
|
25
|
+
if (!m) return 0
|
|
26
|
+
let specificity = ns.length + 1
|
|
27
|
+
for (let i = 1; i < m.length; i++) {
|
|
28
|
+
specificity -= m[i]?.length || 0
|
|
29
|
+
}
|
|
30
|
+
return specificity
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
return function matchLevel(ns: string): Specificity {
|
|
35
|
+
let specificity = 0
|
|
36
|
+
for (let i = 0; i < variants.length; i++) {
|
|
37
|
+
specificity = Math.max(specificity, variants[i](ns))
|
|
38
|
+
}
|
|
39
|
+
return specificity
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
|
|
45
|
+
function escapeRegex(s: string): string {
|
|
46
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
function noMatch(ns: string): Specificity {
|
|
51
|
+
return 0
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
export class Levels {
|
|
56
|
+
private cache: Record<string, LogLevel> = {}
|
|
57
|
+
private levels: NamespaceMatcher[] = [noMatch, noMatch, noMatch, noMatch, noMatch, noMatch]
|
|
58
|
+
|
|
59
|
+
get(ns: string): LogLevel {
|
|
60
|
+
let level = this.cache[ns]
|
|
61
|
+
if (level == null) {
|
|
62
|
+
return this.cache[ns] = this.determineLevel(ns)
|
|
63
|
+
} else {
|
|
64
|
+
return level
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private determineLevel(ns: string): LogLevel {
|
|
69
|
+
let specificity = 0
|
|
70
|
+
let level = LogLevel.INFO
|
|
71
|
+
for (let i = 0; i < this.levels.length; i++) {
|
|
72
|
+
let s = this.levels[i](ns)
|
|
73
|
+
if (s > specificity) {
|
|
74
|
+
level = i
|
|
75
|
+
specificity = s
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return level
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
configure(level: LogLevel, config: string): void {
|
|
82
|
+
this.levels[level] = compileLevelConfig(config)
|
|
83
|
+
this.cache = {}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
export const LEVELS = new Levels()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
;['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'].forEach((name, level) => {
|
|
92
|
+
let env = process.env[`SQD_${name}`]
|
|
93
|
+
if (env) {
|
|
94
|
+
LEVELS.configure(level, env)
|
|
95
|
+
}
|
|
96
|
+
})
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import {LEVELS, LogLevel} from "./level"
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export interface LogRecord {
|
|
5
|
+
time: number
|
|
6
|
+
level: LogLevel
|
|
7
|
+
ns: string
|
|
8
|
+
msg?: string
|
|
9
|
+
err?: Error
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export type Sink = (rec: LogRecord) => void
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
export class Logger {
|
|
17
|
+
constructor(
|
|
18
|
+
private sink: Sink,
|
|
19
|
+
private ns: string,
|
|
20
|
+
private attributes?: object
|
|
21
|
+
) {
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get level(): LogLevel {
|
|
25
|
+
return LEVELS.get(this.ns)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
child(attributes: object): Logger
|
|
29
|
+
child(ns: string, attributes?: object): Logger
|
|
30
|
+
child(nsOrAttributes: string | object, attributes?: object): Logger {
|
|
31
|
+
let ns = this.ns
|
|
32
|
+
if (typeof nsOrAttributes == 'string') {
|
|
33
|
+
ns = ns ? `${ns}:${nsOrAttributes}` : nsOrAttributes
|
|
34
|
+
} else {
|
|
35
|
+
attributes = nsOrAttributes
|
|
36
|
+
}
|
|
37
|
+
if (this.attributes) {
|
|
38
|
+
if (attributes) {
|
|
39
|
+
attributes = {...this.attributes, ...attributes}
|
|
40
|
+
} else {
|
|
41
|
+
attributes = this.attributes
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return new Logger(this.sink, ns, attributes)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
write(level: LogLevel, msg?: string): void
|
|
48
|
+
write(level: LogLevel, attributes?: object, msg?: string): void
|
|
49
|
+
write(level: LogLevel, attributes?: any, msg?: any) {
|
|
50
|
+
if (attributes == null) return
|
|
51
|
+
if (level < this.level) return
|
|
52
|
+
if (typeof attributes == 'string') {
|
|
53
|
+
msg = attributes
|
|
54
|
+
attributes = null
|
|
55
|
+
}
|
|
56
|
+
if (attributes instanceof Error) {
|
|
57
|
+
attributes = {err: attributes}
|
|
58
|
+
}
|
|
59
|
+
let rec: any = {
|
|
60
|
+
level,
|
|
61
|
+
time: Date.now(),
|
|
62
|
+
ns: this.ns,
|
|
63
|
+
msg
|
|
64
|
+
}
|
|
65
|
+
addAttributes(this.attributes, rec)
|
|
66
|
+
addAttributes(attributes, rec)
|
|
67
|
+
this.sink(rec)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
trace(msg?: string): void
|
|
71
|
+
trace(attributes?: object, msg?: string): void
|
|
72
|
+
trace(attributes?: any, msg?: any): void {
|
|
73
|
+
this.write(LogLevel.TRACE, attributes, msg)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
debug(msg?: string): void
|
|
77
|
+
debug(attributes?: object, msg?: string): void
|
|
78
|
+
debug(attributes?: any, msg?: any): void {
|
|
79
|
+
this.write(LogLevel.DEBUG, attributes, msg)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
info(msg?: string): void
|
|
83
|
+
info(attributes?: object, msg?: string): void
|
|
84
|
+
info(attributes?: any, msg?: any): void {
|
|
85
|
+
this.write(LogLevel.INFO, attributes, msg)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
warn(msg?: string): void
|
|
89
|
+
warn(attributes?: object, msg?: string): void
|
|
90
|
+
warn(attributes?: any, msg?: any): void {
|
|
91
|
+
this.write(LogLevel.WARN, attributes, msg)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
error(msg?: string): void
|
|
95
|
+
error(attributes?: object, msg?: string): void
|
|
96
|
+
error(attributes?: any, msg?: any): void {
|
|
97
|
+
this.write(LogLevel.ERROR, attributes, msg)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
fatal(msg?: string | null): void
|
|
101
|
+
fatal(attributes?: object | null, msg?: string): void
|
|
102
|
+
fatal(attributes?: any, msg?: any): void {
|
|
103
|
+
this.write(LogLevel.FATAL, attributes, msg)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
isTrace(): boolean {
|
|
107
|
+
return this.level <= LogLevel.TRACE
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
isDebug(): boolean {
|
|
111
|
+
return this.level <= LogLevel.DEBUG
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
isInfo(): boolean {
|
|
115
|
+
return this.level <= LogLevel.INFO
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
isWarn(): boolean {
|
|
119
|
+
return this.level <= LogLevel.WARN
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
isError(): boolean {
|
|
123
|
+
return this.level <= LogLevel.ERROR
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
isFatal(): boolean {
|
|
127
|
+
return this.level <= LogLevel.FATAL
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
function addAttributes(src: any, target: any) {
|
|
133
|
+
for (let key in src) {
|
|
134
|
+
let val = src[key]
|
|
135
|
+
switch (key) {
|
|
136
|
+
case 'time':
|
|
137
|
+
case 'level':
|
|
138
|
+
case 'ns':
|
|
139
|
+
case 'msg':
|
|
140
|
+
break
|
|
141
|
+
default:
|
|
142
|
+
target[key] = val
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {toJSON} from "@subsquid/util-internal-json"
|
|
2
|
+
import {LogLevel} from "../level"
|
|
3
|
+
import {LogRecord} from "../logger"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export function jsonLinesStderrSink(rec: LogRecord): void {
|
|
7
|
+
process.stderr.write(stringify(rec) + '\n')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
function stringify(rec: LogRecord): string {
|
|
12
|
+
try {
|
|
13
|
+
return JSON.stringify(toJSON(rec))
|
|
14
|
+
} catch(e: any) {
|
|
15
|
+
return stringify({
|
|
16
|
+
ns: 'sys',
|
|
17
|
+
time: Date.now(),
|
|
18
|
+
level: LogLevel.ERROR,
|
|
19
|
+
msg: `Failed to serialize log record from ${rec.ns}`,
|
|
20
|
+
err: {stack: e.stack || e.toString()} as Error
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
}
|