UNPKG

9.52 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const color_1 = require("@heroku-cli/color");
4const cli_ux_1 = require("cli-ux");
5exports.COLORS = [
6 s => color_1.default.yellow(s),
7 s => color_1.default.green(s),
8 s => color_1.default.cyan(s),
9 s => color_1.default.magenta(s),
10 s => color_1.default.blue(s),
11 s => color_1.default.bold.green(s),
12 s => color_1.default.bold.cyan(s),
13 s => color_1.default.bold.magenta(s),
14 s => color_1.default.bold.yellow(s),
15 s => color_1.default.bold.blue(s)
16];
17const assignedColors = {};
18function getColorForIdentifier(i) {
19 i = i.split('.')[0];
20 if (assignedColors[i])
21 return assignedColors[i];
22 assignedColors[i] = exports.COLORS[Object.keys(assignedColors).length % exports.COLORS.length];
23 return assignedColors[i];
24}
25// get initial colors so they are the same every time
26getColorForIdentifier('run');
27getColorForIdentifier('router');
28getColorForIdentifier('web');
29getColorForIdentifier('postgres');
30getColorForIdentifier('heroku-postgres');
31let lineRegex = /^(.*?\[([\w-]+)([\d.]+)?]:)(.*)?$/;
32const red = color_1.default.red;
33const dim = i => color_1.default.dim(i);
34const other = dim;
35const path = i => color_1.default.green(i);
36const method = i => color_1.default.bold.magenta(i);
37const status = code => {
38 if (code < 200)
39 return code;
40 if (code < 300)
41 return color_1.default.green(code);
42 if (code < 400)
43 return color_1.default.cyan(code);
44 if (code < 500)
45 return color_1.default.yellow(code);
46 if (code < 600)
47 return color_1.default.red(code);
48 return code;
49};
50const ms = (s) => {
51 const ms = parseInt(s, 10);
52 if (!ms)
53 return s;
54 if (ms < 100)
55 return color_1.default.greenBright(s);
56 if (ms < 500)
57 return color_1.default.green(s);
58 if (ms < 5000)
59 return color_1.default.yellow(s);
60 if (ms < 10000)
61 return color_1.default.yellowBright(s);
62 return color_1.default.red(s);
63};
64function colorizeRouter(body) {
65 const encodeColor = ([k, v]) => {
66 switch (k) {
67 case 'at': return [k, v === 'error' ? red(v) : other(v)];
68 case 'code': return [k, red.bold(v)];
69 case 'method': return [k, method(v)];
70 case 'dyno': return [k, getColorForIdentifier(v)(v)];
71 case 'status': return [k, status(v)];
72 case 'path': return [k, path(v)];
73 case 'connect': return [k, ms(v)];
74 case 'service': return [k, ms(v)];
75 default: return [k, other(v)];
76 }
77 };
78 try {
79 const tokens = body.split(/\s+/).map(sub => {
80 const parts = sub.split('=');
81 if (parts.length === 1) {
82 return parts;
83 }
84 else if (parts.length === 2) {
85 return encodeColor(parts);
86 }
87 else {
88 return encodeColor([parts[0], parts.splice(1).join('=')]);
89 }
90 });
91 return tokens.map(([k, v]) => {
92 if (v === undefined) {
93 return other(k);
94 }
95 return other(k + '=') + v;
96 }).join(' ');
97 }
98 catch (err) {
99 cli_ux_1.default.warn(err);
100 return body;
101 }
102}
103const state = (s) => {
104 switch (s) {
105 case 'down': return red(s);
106 case 'up': return color_1.default.greenBright(s);
107 case 'starting': return color_1.default.yellowBright(s);
108 case 'complete': return color_1.default.greenBright(s);
109 default: return s;
110 }
111};
112function colorizeRun(body) {
113 try {
114 if (body.match(/^Stopping all processes with SIGTERM$/))
115 return color_1.default.red(body);
116 let starting = body.match(/^(Starting process with command )(`.+`)(by user )?(.*)?$/);
117 if (starting) {
118 return [
119 starting[1],
120 color_1.default.cmd(starting[2]),
121 starting[3] || '',
122 color_1.default.green(starting[4] || '')
123 ].join('');
124 }
125 let stateChange = body.match(/^(State changed from )(\w+)( to )(\w+)$/);
126 if (stateChange) {
127 return [
128 stateChange[1],
129 state(stateChange[2]),
130 stateChange[3] || '',
131 state(stateChange[4] || '')
132 ].join('');
133 }
134 let exited = body.match(/^(Process exited with status )(\d+)$/);
135 if (exited) {
136 return [
137 exited[1],
138 exited[2] === '0' ? color_1.default.greenBright(exited[2]) : color_1.default.red(exited[2])
139 ].join('');
140 }
141 }
142 catch (err) {
143 cli_ux_1.default.warn(err);
144 }
145 return body;
146}
147function colorizeWeb(body) {
148 try {
149 if (body.match(/^Unidling$/))
150 return color_1.default.yellow(body);
151 if (body.match(/^Restarting$/))
152 return color_1.default.yellow(body);
153 if (body.match(/^Stopping all processes with SIGTERM$/))
154 return color_1.default.red(body);
155 let starting = body.match(/^(Starting process with command )(`.+`)(by user )?(.*)?$/);
156 if (starting) {
157 return [
158 (starting[1]),
159 color_1.default.cmd(starting[2]),
160 (starting[3] || ''),
161 color_1.default.green(starting[4] || '')
162 ].join('');
163 }
164 let exited = body.match(/^(Process exited with status )(\d+)$/);
165 if (exited) {
166 return [
167 exited[1],
168 exited[2] === '0' ? color_1.default.greenBright(exited[2]) : color_1.default.red(exited[2])
169 ].join('');
170 }
171 let stateChange = body.match(/^(State changed from )(\w+)( to )(\w+)$/);
172 if (stateChange) {
173 return [
174 stateChange[1],
175 state(stateChange[2]),
176 stateChange[3],
177 state(stateChange[4])
178 ].join('');
179 }
180 let apache = body.match(/^(\d+\.\d+\.\d+\.\d+ -[^-]*- \[[^\]]+] ")(\w+)( )([^ ]+)( HTTP\/\d+\.\d+" )(\d+)( .+$)/);
181 if (apache) {
182 const [, ...tokens] = apache;
183 return [
184 other(tokens[0]),
185 method(tokens[1]),
186 other(tokens[2]),
187 path(tokens[3]),
188 other(tokens[4]),
189 status(tokens[5]),
190 other(tokens[6])
191 ].join('');
192 }
193 let route = body.match(/^(.* ")(\w+)(.+)(HTTP\/\d+\.\d+" .*)$/);
194 if (route) {
195 return [
196 route[1],
197 method(route[2]),
198 path(route[3]),
199 route[4]
200 ].join('');
201 }
202 }
203 catch (err) {
204 cli_ux_1.default.warn(err);
205 }
206 return body;
207}
208function colorizeAPI(body) {
209 if (body.match(/^Build succeeded$/))
210 return color_1.default.greenBright(body);
211 if (body.match(/^Build failed/))
212 return color_1.default.red(body);
213 const build = body.match(/^(Build started by user )(.+)$/);
214 if (build) {
215 return [
216 build[1],
217 color_1.default.green(build[2])
218 ].join('');
219 }
220 const deploy = body.match(/^(Deploy )([\w]+)( by user )(.+)$/);
221 if (deploy) {
222 return [
223 deploy[1],
224 color_1.default.cyan(deploy[2]),
225 deploy[3],
226 color_1.default.green(deploy[4])
227 ].join('');
228 }
229 const release = body.match(/^(Release )(v[\d]+)( created by user )(.+)$/);
230 if (release) {
231 return [
232 release[1],
233 color_1.default.magenta(release[2]),
234 release[3],
235 color_1.default.green(release[4])
236 ].join('');
237 }
238 let starting = body.match(/^(Starting process with command )(`.+`)(by user )?(.*)?$/);
239 if (starting) {
240 return [
241 (starting[1]),
242 color_1.default.cmd(starting[2]),
243 (starting[3] || ''),
244 color_1.default.green(starting[4] || '')
245 ].join('');
246 }
247 return body;
248}
249function colorizeRedis(body) {
250 if (body.match(/source=\w+ sample#/)) {
251 body = dim(body);
252 }
253 return body;
254}
255function colorizePG(body) {
256 let create = body.match(/^(\[DATABASE].*)(CREATE TABLE)(.*)$/);
257 if (create) {
258 return [
259 other(create[1]),
260 color_1.default.magenta(create[2]),
261 color_1.default.cyan(create[3])
262 ].join('');
263 }
264 if (body.match(/source=\w+ sample#/)) {
265 body = dim(body);
266 }
267 return body;
268}
269function colorize(line) {
270 if (process.env.HEROKU_LOGS_COLOR === '0')
271 return line;
272 let parsed = line.match(lineRegex);
273 if (!parsed)
274 return line;
275 let header = parsed[1];
276 let identifier = parsed[2];
277 let body = (parsed[4] || '').trim();
278 switch (identifier) {
279 case 'api':
280 body = colorizeAPI(body);
281 break;
282 case 'router':
283 body = colorizeRouter(body);
284 break;
285 case 'run':
286 body = colorizeRun(body);
287 break;
288 case 'web':
289 body = colorizeWeb(body);
290 break;
291 case 'heroku-redis':
292 body = colorizeRedis(body);
293 break;
294 case 'heroku-postgres':
295 case 'postgres':
296 body = colorizePG(body);
297 }
298 return getColorForIdentifier(identifier)(header) + ' ' + body;
299}
300exports.default = colorize;