1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const stream_1 = require("stream");
|
4 | const util = require("util");
|
5 | const colors_1 = require("./colors");
|
6 | const format_1 = require("./format");
|
7 | const utils_1 = require("./utils");
|
8 | exports.LOGGER_LEVELS = Object.freeze({
|
9 | DEBUG: 10,
|
10 | INFO: 20,
|
11 | WARN: 30,
|
12 | ERROR: 40,
|
13 | });
|
14 | exports.LOGGER_LEVEL_NAMES = new Map([
|
15 | [exports.LOGGER_LEVELS.DEBUG, 'DEBUG'],
|
16 | [exports.LOGGER_LEVELS.INFO, 'INFO'],
|
17 | [exports.LOGGER_LEVELS.WARN, 'WARN'],
|
18 | [exports.LOGGER_LEVELS.ERROR, 'ERROR'],
|
19 | ]);
|
20 | function getLoggerLevelName(level) {
|
21 | if (level) {
|
22 | const levelName = exports.LOGGER_LEVEL_NAMES.get(level);
|
23 | if (levelName) {
|
24 | return levelName;
|
25 | }
|
26 | }
|
27 | }
|
28 | exports.getLoggerLevelName = getLoggerLevelName;
|
29 | function getLoggerLevelColor(colors, level) {
|
30 | const levelName = getLoggerLevelName(level);
|
31 | if (levelName) {
|
32 | return colors.log[levelName];
|
33 | }
|
34 | }
|
35 | exports.getLoggerLevelColor = getLoggerLevelColor;
|
36 | class StreamHandler {
|
37 | constructor({ stream, filter, formatter }) {
|
38 | this.stream = stream;
|
39 | this.filter = filter;
|
40 | this.formatter = formatter;
|
41 | }
|
42 | clone(opts) {
|
43 | const { stream, filter, formatter } = this;
|
44 | return new StreamHandler({ stream, filter, formatter, ...opts });
|
45 | }
|
46 | handle(record) {
|
47 | if (this.filter && !this.filter(record)) {
|
48 | return;
|
49 | }
|
50 | const msg = this.formatter && record.format !== false ? this.formatter(record) : record.msg;
|
51 | this.stream.write(utils_1.enforceLF(msg));
|
52 | }
|
53 | }
|
54 | exports.StreamHandler = StreamHandler;
|
55 | const stdoutLogRecordFilter = (record) => !record.level || record.level === exports.LOGGER_LEVELS.INFO;
|
56 | const stderrLogRecordFilter = (record) => !!record.level && record.level !== exports.LOGGER_LEVELS.INFO;
|
57 | exports.DEFAULT_LOGGER_HANDLERS = new Set([
|
58 | new StreamHandler({ stream: process.stdout, filter: stdoutLogRecordFilter }),
|
59 | new StreamHandler({ stream: process.stderr, filter: stderrLogRecordFilter }),
|
60 | ]);
|
61 | class Logger {
|
62 | constructor({ level = exports.LOGGER_LEVELS.INFO, handlers } = {}) {
|
63 | this.level = level;
|
64 | this.handlers = handlers ? handlers : Logger.cloneHandlers(exports.DEFAULT_LOGGER_HANDLERS);
|
65 | }
|
66 | static cloneHandlers(handlers) {
|
67 | return new Set([...handlers].map(handler => handler.clone()));
|
68 | }
|
69 | |
70 |
|
71 |
|
72 |
|
73 |
|
74 | clone(opts = {}) {
|
75 | const { level, handlers } = this;
|
76 | return new Logger({ level, handlers: Logger.cloneHandlers(handlers), ...opts });
|
77 | }
|
78 | |
79 |
|
80 |
|
81 |
|
82 |
|
83 | msg(msg) {
|
84 | this.log(this.createRecord(msg));
|
85 | }
|
86 | |
87 |
|
88 |
|
89 |
|
90 |
|
91 | debug(msg) {
|
92 | this.log(this.createRecord(msg, exports.LOGGER_LEVELS.DEBUG));
|
93 | }
|
94 | |
95 |
|
96 |
|
97 |
|
98 |
|
99 | info(msg) {
|
100 | this.log(this.createRecord(msg, exports.LOGGER_LEVELS.INFO));
|
101 | }
|
102 | |
103 |
|
104 |
|
105 |
|
106 |
|
107 | warn(msg) {
|
108 | this.log(this.createRecord(msg, exports.LOGGER_LEVELS.WARN));
|
109 | }
|
110 | |
111 |
|
112 |
|
113 |
|
114 |
|
115 | error(msg) {
|
116 | this.log(this.createRecord(msg, exports.LOGGER_LEVELS.ERROR));
|
117 | }
|
118 | createRecord(msg, level, format) {
|
119 | return {
|
120 |
|
121 |
|
122 | msg: util.format(msg),
|
123 | level,
|
124 | logger: this,
|
125 | format,
|
126 | };
|
127 | }
|
128 | |
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 | nl(num = 1, level) {
|
135 | this.log({ ...this.createRecord('\n'.repeat(num), level), format: false });
|
136 | }
|
137 | |
138 |
|
139 |
|
140 | log(record) {
|
141 | if (typeof record.level === 'number' && this.level > record.level) {
|
142 | return;
|
143 | }
|
144 | for (const handler of this.handlers) {
|
145 | handler.handle(record);
|
146 | }
|
147 | }
|
148 | createWriteStream(level, format) {
|
149 | const self = this;
|
150 | return new class extends stream_1.Writable {
|
151 | _write(chunk, encoding, callback) {
|
152 | self.log(self.createRecord(chunk.toString(), level, format));
|
153 | callback();
|
154 | }
|
155 | }();
|
156 | }
|
157 | }
|
158 | exports.Logger = Logger;
|
159 | function createTaggedFormatter({ colors = colors_1.NO_COLORS, prefix = '', titleize, wrap } = {}) {
|
160 | return ({ msg, level, format }) => {
|
161 | if (format === false) {
|
162 | return msg;
|
163 | }
|
164 | const { strong, weak } = colors;
|
165 | const [firstLine, ...lines] = msg.split('\n');
|
166 | const levelName = getLoggerLevelName(level);
|
167 | const levelColor = getLoggerLevelColor(colors, level);
|
168 | const tag = ((typeof prefix === 'function' ? prefix() : prefix) +
|
169 | (levelName ? `${weak('[')}\x1b[40m${strong(levelColor ? levelColor(levelName) : levelName)}\x1b[49m${weak(']')}` : ''));
|
170 | const title = titleize && lines.length > 0 ? `${strong(levelColor ? levelColor(firstLine) : firstLine)}\n` : firstLine;
|
171 | const indentation = tag ? format_1.stringWidth(tag) + 1 : 0;
|
172 | const pulledLines = utils_1.dropWhile(lines, l => l === '');
|
173 | return ((tag ? `${tag} ` : '') +
|
174 | (wrap
|
175 | ? format_1.wordWrap([title, ...pulledLines].join('\n'), { indentation, ...(typeof wrap === 'object' ? wrap : {}) })
|
176 | : [title, ...pulledLines.map(l => l ? ' '.repeat(indentation) + l : '')].join('\n')));
|
177 | };
|
178 | }
|
179 | exports.createTaggedFormatter = createTaggedFormatter;
|
180 | function createPrefixedFormatter(prefix) {
|
181 | return ({ msg, format }) => {
|
182 | if (format === false) {
|
183 | return msg;
|
184 | }
|
185 | return `${typeof prefix === 'function' ? prefix() : prefix} ${msg}`;
|
186 | };
|
187 | }
|
188 | exports.createPrefixedFormatter = createPrefixedFormatter;
|