mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-04-01 02:42:23 -05:00
refactor: add formatters
This commit is contained in:
parent
263f051507
commit
f4e7149806
8 changed files with 124 additions and 90 deletions
src/lib
test/unit/modules/logger
|
@ -1,15 +1,13 @@
|
|||
/* eslint-disable */
|
||||
|
||||
import { pad } from './utils';
|
||||
|
||||
import { fillInMsgTemplate } from './logger/parser';
|
||||
import {calculateLevel, levels, subsystems} from "./logger/levels";
|
||||
import {prettyTimestamped} from "./logger/format/pretty-timestamped";
|
||||
import {pretty} from "./logger/format/pretty";
|
||||
import {jsonFormat} from "./logger/format/json";
|
||||
|
||||
const cluster = require('cluster');
|
||||
const Logger = require('bunyan');
|
||||
const Error = require('http-errors');
|
||||
const Stream = require('stream');
|
||||
const { red, yellow, cyan, magenta, green, white } = require('kleur');
|
||||
const pkgJSON = require('../../package.json');
|
||||
const _ = require('lodash');
|
||||
const dayjs = require('dayjs');
|
||||
|
@ -20,24 +18,33 @@ const dayjs = require('dayjs');
|
|||
class VerdaccioRotatingFileStream extends Logger.RotatingFileStream {
|
||||
// We depend on mv so that this is there
|
||||
write(obj) {
|
||||
const msg = fillInMsgTemplate(obj.msg, obj, false);
|
||||
super.write(JSON.stringify({ ...obj, msg }, Logger.safeCycles()) + '\n');
|
||||
super.write(jsonFormat(obj, false));
|
||||
}
|
||||
}
|
||||
|
||||
let logger;
|
||||
|
||||
export interface LoggerTarget {
|
||||
type?: string;
|
||||
format?: string;
|
||||
level?: string;
|
||||
options?: any;
|
||||
path?: string;
|
||||
}
|
||||
|
||||
const DEFAULT_LOGGER_CONF = [{ type: 'stdout', format: 'pretty', level: 'http' }];
|
||||
|
||||
/**
|
||||
* Setup the Buyan logger
|
||||
* @param {*} logs list of log configuration
|
||||
*/
|
||||
function setup(logs) {
|
||||
const streams = [];
|
||||
const streams: any = [];
|
||||
if (logs == null) {
|
||||
logs = [{ type: 'stdout', format: 'pretty', level: 'http' }];
|
||||
logs = DEFAULT_LOGGER_CONF;
|
||||
}
|
||||
|
||||
logs.forEach(function(target) {
|
||||
logs.forEach(function(target: LoggerTarget) {
|
||||
let level = target.level || 35;
|
||||
if (level === 'http') {
|
||||
level = 35;
|
||||
|
@ -63,14 +70,16 @@ function setup(logs) {
|
|||
)
|
||||
);
|
||||
|
||||
streams.push({
|
||||
const rotateStream: any = {
|
||||
// @ts-ignore
|
||||
type: 'raw',
|
||||
// @ts-ignore
|
||||
level,
|
||||
// @ts-ignore
|
||||
stream,
|
||||
});
|
||||
};
|
||||
|
||||
streams.push(rotateStream);
|
||||
} else {
|
||||
const stream = new Stream();
|
||||
stream.writable = true;
|
||||
|
@ -93,17 +102,16 @@ function setup(logs) {
|
|||
if (target.format === 'pretty') {
|
||||
// making fake stream for pretty printing
|
||||
stream.write = obj => {
|
||||
destination.write(`${print(obj.level, obj.msg, obj, destinationIsTTY)}\n`);
|
||||
destination.write(pretty(obj, destinationIsTTY));
|
||||
};
|
||||
} else if (target.format === 'pretty-timestamped') {
|
||||
// making fake stream for pretty printing
|
||||
stream.write = obj => {
|
||||
destination.write(`[${dayjs(obj.time).format('YYYY-MM-DD HH:mm:ss')}] ${print(obj.level, obj.msg, obj, destinationIsTTY)}\n`);
|
||||
destination.write(prettyTimestamped(obj, destinationIsTTY));
|
||||
};
|
||||
} else {
|
||||
stream.write = obj => {
|
||||
const msg = fillInMsgTemplate(obj.msg, obj, destinationIsTTY);
|
||||
destination.write(`${JSON.stringify({ ...obj, msg }, Logger.safeCycles())}\n`);
|
||||
destination.write(jsonFormat(obj, destinationIsTTY));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -134,39 +142,4 @@ function setup(logs) {
|
|||
});
|
||||
}
|
||||
|
||||
// adopted from socket.io
|
||||
// this part was converted to coffee-script and back again over the years,
|
||||
// so it might look weird
|
||||
|
||||
let max = 0;
|
||||
for (const l in levels) {
|
||||
if (Object.prototype.hasOwnProperty.call(levels, l)) {
|
||||
max = Math.max(max, l.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply colors to a string based on level parameters.
|
||||
* @param {*} type
|
||||
* @param {*} msg
|
||||
* @param {*} obj
|
||||
* @param {*} colors
|
||||
* @return {String}
|
||||
*/
|
||||
function print(type, msg, obj, colors) {
|
||||
if (typeof type === 'number') {
|
||||
type = calculateLevel(type);
|
||||
}
|
||||
const finalMessage = fillInMsgTemplate(msg, obj, colors);
|
||||
|
||||
|
||||
|
||||
const sub = subsystems[colors ? 0 : 1][obj.sub] || subsystems[+!colors].default;
|
||||
if (colors) {
|
||||
return ` ${levels[type](pad(type, max))}${white(`${sub} ${finalMessage}`)}`;
|
||||
} else {
|
||||
return ` ${pad(type, max)}${sub} ${finalMessage}`;
|
||||
}
|
||||
}
|
||||
|
||||
export { setup, logger };
|
||||
|
|
10
src/lib/logger/format/json.ts
Normal file
10
src/lib/logger/format/json.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
import {fillInMsgTemplate} from "../formatter";
|
||||
|
||||
const Logger = require('bunyan');
|
||||
|
||||
export function jsonFormat(obj, hasColors): string {
|
||||
const msg = fillInMsgTemplate(obj.msg, obj, hasColors);
|
||||
|
||||
return `${JSON.stringify({ ...obj, msg }, Logger.safeCycles())}\n`;
|
||||
}
|
6
src/lib/logger/format/pretty-timestamped.ts
Normal file
6
src/lib/logger/format/pretty-timestamped.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import {formatLoggingDate} from "../utils";
|
||||
import {printMessage} from "../formatter";
|
||||
|
||||
export function prettyTimestamped(obj, hasColors): string {
|
||||
return `[${formatLoggingDate(obj.time)}] ${printMessage(obj.level, obj.msg, obj, hasColors)}\n`;
|
||||
}
|
5
src/lib/logger/format/pretty.ts
Normal file
5
src/lib/logger/format/pretty.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import {printMessage} from "../formatter";
|
||||
|
||||
export function pretty(obj, hasColors): string {
|
||||
return `${printMessage(obj.level, obj.msg, obj, hasColors)}\n`;
|
||||
}
|
71
src/lib/logger/formatter.ts
Normal file
71
src/lib/logger/formatter.ts
Normal file
|
@ -0,0 +1,71 @@
|
|||
import { inspect } from 'util';
|
||||
import { isObject, pad } from '../utils';
|
||||
import { red, green } from 'kleur';
|
||||
|
||||
import { white } from 'kleur';
|
||||
import {calculateLevel, levels, subsystems} from "./levels";
|
||||
|
||||
let LEVEL_VALUE_MAX = 0;
|
||||
for (const l in levels) {
|
||||
if (Object.prototype.hasOwnProperty.call(levels, l)) {
|
||||
LEVEL_VALUE_MAX = Math.max(LEVEL_VALUE_MAX, l.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply colors to a string based on level parameters.
|
||||
* @param {*} type
|
||||
* @param {*} msg
|
||||
* @param {*} templateObjects
|
||||
* @param {*} hasColors
|
||||
* @return {String}
|
||||
*/
|
||||
export function printMessage(type, msg, templateObjects, hasColors) {
|
||||
if (typeof type === 'number') {
|
||||
type = calculateLevel(type);
|
||||
}
|
||||
|
||||
const finalMessage = fillInMsgTemplate(msg, templateObjects, hasColors);
|
||||
|
||||
const sub = subsystems[hasColors ? 0 : 1][templateObjects.sub] || subsystems[+!hasColors].default;
|
||||
if (hasColors) {
|
||||
return ` ${levels[type](pad(type, LEVEL_VALUE_MAX))}${white(`${sub} ${finalMessage}`)}`;
|
||||
} else {
|
||||
return ` ${pad(type, LEVEL_VALUE_MAX)}${sub} ${finalMessage}`;
|
||||
}
|
||||
}
|
||||
|
||||
export function fillInMsgTemplate(msg, obj: unknown, colors): string {
|
||||
return msg.replace(/@{(!?[$A-Za-z_][$0-9A-Za-z\._]*)}/g, (_, name): string => {
|
||||
|
||||
let str = obj;
|
||||
let is_error;
|
||||
if (name[0] === '!') {
|
||||
name = name.substr(1);
|
||||
is_error = true;
|
||||
}
|
||||
|
||||
const _ref = name.split('.');
|
||||
for (let _i = 0; _i < _ref.length; _i++) {
|
||||
const id = _ref[_i];
|
||||
if (isObject(str)) {
|
||||
// @ts-ignore
|
||||
str = str[id];
|
||||
} else {
|
||||
str = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof str === 'string') {
|
||||
if (!colors || (str as string).includes('\n')) {
|
||||
return str;
|
||||
} else if (is_error) {
|
||||
return red(str);
|
||||
} else {
|
||||
return green(str);
|
||||
}
|
||||
} else {
|
||||
return inspect(str, undefined, null, colors);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
import { inspect } from 'util';
|
||||
import { isObject } from '../utils';
|
||||
import { red, green } from 'kleur';
|
||||
|
||||
export function fillInMsgTemplate(msg, obj: unknown, colors): string {
|
||||
return msg.replace(/@{(!?[$A-Za-z_][$0-9A-Za-z\._]*)}/g, (_, name): string => {
|
||||
|
||||
let str = obj;
|
||||
let is_error;
|
||||
if (name[0] === '!') {
|
||||
name = name.substr(1);
|
||||
is_error = true;
|
||||
}
|
||||
|
||||
const _ref = name.split('.');
|
||||
for (let _i = 0; _i < _ref.length; _i++) {
|
||||
const id = _ref[_i];
|
||||
if (isObject(str)) {
|
||||
// @ts-ignore
|
||||
str = str[id];
|
||||
} else {
|
||||
str = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof str === 'string') {
|
||||
if (!colors || (str as string).includes('\n')) {
|
||||
return str;
|
||||
} else if (is_error) {
|
||||
return red(str);
|
||||
} else {
|
||||
return green(str);
|
||||
}
|
||||
} else {
|
||||
return inspect(str, undefined, null, colors);
|
||||
}
|
||||
});
|
||||
}
|
7
src/lib/logger/utils.ts
Normal file
7
src/lib/logger/utils.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import dayjs from 'dayjs';
|
||||
|
||||
export const FORMAT_DATE = 'YYYY-MM-DD HH:mm:ss';
|
||||
|
||||
export function formatLoggingDate(time: string): string {
|
||||
return dayjs(time).format(FORMAT_DATE);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { fillInMsgTemplate } from "../../../../src/lib/logger/parser";
|
||||
import { fillInMsgTemplate } from "../../../../src/lib/logger/formatter";
|
||||
import {LOG_VERDACCIO_ERROR, LOG_VERDACCIO_BYTES} from "../../../../src/api/middleware";
|
||||
import { HTTP_STATUS } from "@verdaccio/commons-api";
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue