0
Fork 0
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:
Juan Picado @jotadeveloper 2019-07-21 08:02:46 +02:00
parent 263f051507
commit f4e7149806
No known key found for this signature in database
GPG key ID: 15AA875EF3768142
8 changed files with 124 additions and 90 deletions

View file

@ -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 };

View 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`;
}

View 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`;
}

View file

@ -0,0 +1,5 @@
import {printMessage} from "../formatter";
export function pretty(obj, hasColors): string {
return `${printMessage(obj.level, obj.msg, obj, hasColors)}\n`;
}

View 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);
}
});
}

View file

@ -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
View 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);
}

View file

@ -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";