@tinkoff/logger
Advanced tools
Comparing version 0.10.57 to 0.10.58
@@ -1,449 +0,7 @@ | ||
import toLower from '@tinkoff/utils/string/toLower'; | ||
import eachObj from '@tinkoff/utils/object/each'; | ||
import toArray from '@tinkoff/utils/array/toArray'; | ||
import noop from '@tinkoff/utils/function/noop'; | ||
import pathEq from '@tinkoff/utils/object/pathEq'; | ||
import isString from '@tinkoff/utils/is/string'; | ||
import isObject from '@tinkoff/utils/is/object'; | ||
import isArray from '@tinkoff/utils/is/array'; | ||
import { safeStringifyJSON } from '@tramvai/safe-strings'; | ||
const LEVELS = { | ||
trace: 50, | ||
debug: 40, | ||
info: 30, | ||
warn: 20, | ||
error: 10, | ||
fatal: 0, | ||
silent: -Infinity, | ||
}; | ||
const LEVEL_NAMES = { | ||
50: 'trace', | ||
40: 'debug', | ||
30: 'info', | ||
20: 'warn', | ||
10: 'error', | ||
0: 'fatal', | ||
}; | ||
const createRegexpFromNamespace = (namespace) => { | ||
return new RegExp(`^${namespace.replace(/\*/g, '.*?')}$`); | ||
}; | ||
class Logger { | ||
// eslint-disable-next-line sort-class-members/sort-class-members | ||
constructor(options = { name: '' }) { | ||
this.name = toLower(options.name); | ||
this.key = options.key || this.name; | ||
if (Logger.instances[this.key]) { | ||
return Logger.instances[this.key]; | ||
} | ||
this.beforeReporters = options.beforeReporters || []; | ||
this.reporters = options.reporters || []; | ||
this.filters = options.filters || []; | ||
this.extensions = options.extensions || []; | ||
this.defaults = options.defaults || {}; | ||
if (options.level) { | ||
this.setLevel(LEVELS[options.level]); | ||
} | ||
if (options.enabled) { | ||
this.setLevel(LEVELS.trace); | ||
} | ||
this.checkEnabled(); | ||
Logger.instances[this.key] = this; | ||
eachObj((level, levelName) => { | ||
this[levelName] = (...args) => { | ||
return this.log(level, args); | ||
}; | ||
}, LEVELS); | ||
} | ||
static save() { | ||
var _a; | ||
(_a = Logger.onChange) === null || _a === void 0 ? void 0 : _a.call(Logger, { | ||
level: Logger.level, | ||
enabledName: this.enabledName, | ||
enabledLevel: this.enabledLevel, | ||
}); | ||
} | ||
static load(state) { | ||
Logger.level = state.level; | ||
Logger.enabledName = state.enabledName; | ||
Logger.enabledLevel = state.enabledLevel; | ||
} | ||
static setLevel(newLevel) { | ||
var _a; | ||
Logger.level = (_a = LEVELS[newLevel]) !== null && _a !== void 0 ? _a : Logger.level; | ||
Logger.save(); | ||
} | ||
static setOnChange(onChange) { | ||
Logger.onChange = onChange; | ||
} | ||
static enable(level, namespace) { | ||
const [lvl, ns] = namespace ? [LEVELS[level], namespace] : [LEVELS.trace, level]; | ||
Logger.enabledName.push(ns); | ||
Logger.enabledLevel.push(lvl); | ||
Logger.save(); | ||
const regexp = createRegexpFromNamespace(ns); | ||
eachObj((instance) => { | ||
const { name } = instance; | ||
if (regexp.test(name)) { | ||
instance.setLevel(lvl); | ||
} | ||
}, Logger.instances); | ||
} | ||
static disable(level, namespace) { | ||
const [lvl, ns] = namespace ? [LEVELS[level], namespace] : [LEVELS.silent, level]; | ||
const index = Logger.enabledName.indexOf(ns); | ||
if (index > -1) { | ||
Logger.enabledName.splice(index, 1); | ||
Logger.enabledLevel.splice(index, 1); | ||
} | ||
else { | ||
Logger.enabledName.push(ns); | ||
Logger.enabledLevel.push(lvl); | ||
} | ||
Logger.save(); | ||
const regexp = createRegexpFromNamespace(ns); | ||
eachObj((instance) => { | ||
const { name } = instance; | ||
if (regexp.test(name)) { | ||
instance.setLevel(lvl); | ||
} | ||
}, Logger.instances); | ||
} | ||
static clear() { | ||
Logger.level = LEVELS.silent; | ||
Logger.enabledName = []; | ||
Logger.enabledLevel = []; | ||
Logger.save(); | ||
eachObj((instance) => { | ||
instance.setLevel(undefined); | ||
}, Logger.instances); | ||
} | ||
static setGlobalReporters(reporters) { | ||
const reportersArr = toArray(reporters); | ||
eachObj((instance) => { | ||
// eslint-disable-next-line no-param-reassign | ||
instance.reporters = reportersArr; | ||
}, Logger.instances); | ||
} | ||
child(options) { | ||
const opts = typeof options === 'string' ? { name: options } : options; | ||
const childKey = opts.key || opts.name; | ||
const name = this.name ? `${this.name}.${opts.name}` : opts.name; | ||
const key = this.key ? `${this.key}.${childKey}` : childKey; | ||
return new Logger({ | ||
beforeReporters: this.beforeReporters, | ||
reporters: this.reporters, | ||
filters: this.filters, | ||
extensions: this.extensions, | ||
defaults: this.defaults, | ||
...opts, | ||
name, | ||
key, | ||
}); | ||
} | ||
addBeforeReporter(reporter) { | ||
this.beforeReporters = this.beforeReporters.concat(reporter); | ||
} | ||
setBeforeReporters(reporters) { | ||
this.beforeReporters = toArray(reporters); | ||
} | ||
addReporter(reporter) { | ||
this.reporters = this.reporters.concat(reporter); | ||
} | ||
setReporters(reporters) { | ||
this.reporters = toArray(reporters); | ||
} | ||
addFilter(filter) { | ||
this.filters = this.filters.concat(filter); | ||
} | ||
setFilters(filters) { | ||
this.filters = toArray(filters); | ||
} | ||
addExtension(extension) { | ||
this.extensions = this.extensions.concat(extension); | ||
this.extensions.push(extension); | ||
} | ||
setExtensions(extensions) { | ||
this.extensions = toArray(extensions); | ||
} | ||
setLevel(level) { | ||
this.level = level; | ||
} | ||
checkEnabled() { | ||
const len = Logger.enabledName.length; | ||
for (let i = len - 1; i >= 0; i--) { | ||
const namespace = Logger.enabledName[i]; | ||
const regexp = createRegexpFromNamespace(namespace); | ||
if (regexp.test(this.name)) { | ||
this.setLevel(Logger.enabledLevel[i]); | ||
return; | ||
} | ||
} | ||
} | ||
createLogObj(level, args) { | ||
return { | ||
date: new Date(), | ||
...this.defaults, | ||
name: this.name, | ||
type: LEVEL_NAMES[level], | ||
level, | ||
args, | ||
}; | ||
} | ||
log(level, args) { | ||
let logObj; | ||
if (this.beforeReporters.length) { | ||
logObj = this.createLogObj(level, args); | ||
} | ||
for (const reporter of this.beforeReporters) { | ||
reporter.log(logObj); | ||
} | ||
if (typeof this.level === 'undefined') { | ||
if (level > Logger.level) { | ||
return false; | ||
} | ||
} | ||
else if (level > this.level) { | ||
return false; | ||
} | ||
if (!logObj) { | ||
logObj = this.createLogObj(level, args); | ||
} | ||
for (const filter of this.filters) { | ||
if (filter.filter(logObj) === false) { | ||
return false; | ||
} | ||
} | ||
for (const extension of this.extensions) { | ||
logObj = extension.extend(logObj); | ||
} | ||
for (const reporter of this.reporters) { | ||
reporter.log(logObj); | ||
} | ||
return true; | ||
} | ||
} | ||
Logger.level = LEVELS.silent; | ||
Logger.instances = {}; | ||
Logger.enabledName = []; | ||
Logger.enabledLevel = []; | ||
const bindMethods = [ | ||
'addBeforeReporter', | ||
'setBeforeReporters', | ||
'addReporter', | ||
'setReporters', | ||
'addFilter', | ||
'setFilters', | ||
'addExtension', | ||
'setExtensions', | ||
...Object.keys(LEVELS), | ||
]; | ||
const createLoggerFactory = (options) => { | ||
const instance = new Logger(options); | ||
return Object.assign((opts) => { | ||
return instance.child(opts); | ||
}, bindMethods.reduce((acc, method) => { | ||
if (instance[method]) { | ||
acc[method] = instance[method].bind(instance); | ||
} | ||
return acc; | ||
}, {}), { | ||
setLevel: Logger.setLevel, | ||
setGlobalReporters: Logger.setGlobalReporters, | ||
enable: Logger.enable, | ||
disable: Logger.disable, | ||
clear: Logger.clear, | ||
}); | ||
}; | ||
class BrowserReporter { | ||
constructor() { | ||
this.defaultColor = '#7f8c8d'; // Gray | ||
this.levelColorMap = { | ||
0: '#c00046', | ||
10: '#c0392b', | ||
20: '#f39c12', | ||
30: '#00BCD4', // Cyan | ||
}; | ||
} | ||
log(logObj) { | ||
const consoleLogFn = | ||
// eslint-disable-next-line no-nested-ternary, no-console | ||
logObj.level < 20 ? console.error : logObj.level === 20 ? console.warn : console.log; | ||
// Styles | ||
const color = this.levelColorMap[logObj.level] || this.defaultColor; | ||
const style = ` | ||
background: ${color}; | ||
border-radius: 0.5em; | ||
color: white; | ||
font-weight: bold; | ||
padding: 2px 0.5em; | ||
`; | ||
const badge = `%c${[logObj.name, logObj.type].filter(Boolean).join(':')}`; | ||
// Log to the console | ||
if (typeof logObj.args[0] === 'string') { | ||
consoleLogFn.call(console, `${badge}%c ${logObj.args[0]}`, style, | ||
// Empty string as style resets to default console style | ||
'', ...logObj.args.slice(1)); | ||
} | ||
else { | ||
consoleLogFn.call(console, badge, style, ...logObj.args); | ||
} | ||
} | ||
} | ||
const parseState = (value) => { | ||
if (!value) { | ||
return; | ||
} | ||
const names = value.split(','); | ||
return { | ||
level: LEVELS.silent, | ||
enabledLevel: Array(names.length).fill(LEVELS.trace), | ||
enabledName: names, | ||
}; | ||
}; | ||
const debugGetState = () => { | ||
try { | ||
return parseState(window.localStorage.getItem('debug')); | ||
} | ||
catch (e) { } | ||
}; | ||
const NAME = '_t_logger'; | ||
const DEFAULT_STATE = { level: LEVELS.error, enabledLevel: [], enabledName: [] }; | ||
let ls; | ||
let state; | ||
try { | ||
ls = window.localStorage; | ||
state = JSON.parse(ls.getItem(NAME)); | ||
} | ||
catch (e) { } | ||
if (!state) { | ||
state = debugGetState(); | ||
} | ||
if (process.env.NODE_ENV === 'development' && !state) { | ||
state = DEFAULT_STATE; | ||
} | ||
Logger.setOnChange((cfg) => { | ||
try { | ||
ls.setItem(NAME, JSON.stringify(cfg)); | ||
} | ||
catch (e) { } | ||
}); | ||
state && Logger.load(state); | ||
const logger = createLoggerFactory({ | ||
name: '', | ||
reporters: [new BrowserReporter()], | ||
}); | ||
window.logger = logger; | ||
/* eslint-disable prefer-destructuring */ | ||
const formatError = (error) => { | ||
if (isString(error)) { | ||
// eslint-disable-next-line no-param-reassign | ||
error = new Error(error); | ||
} | ||
return { | ||
...error, | ||
// @ts-ignore | ||
// хотим чтобы всегда был единый формат для error.body и error.code [text] | ||
// игнор потому что в error нет поля body и code | ||
body: safeStringifyJSON(error.body), | ||
// @ts-ignore | ||
code: safeStringifyJSON(error.code), | ||
message: error.message, | ||
stack: error.stack, | ||
}; | ||
}; | ||
const formatJson = (logObj) => { | ||
let fields = null; | ||
let message; | ||
let error; | ||
const { args } = logObj; | ||
if (args[0] instanceof Error) { | ||
error = formatError(args[0]); | ||
if (isString(args[1])) { | ||
message = args[1]; | ||
} | ||
else { | ||
message = args[0].message; | ||
} | ||
} | ||
else if (isObject(args[0]) && !isArray(args[0])) { | ||
fields = args[0]; | ||
error = fields.error && formatError(fields.error); | ||
if (args[0].message) { | ||
message = args[0].message; | ||
} | ||
else if (isString(args[1])) { | ||
message = args[1]; | ||
} | ||
} | ||
else { | ||
message = args[0]; | ||
} | ||
const otherArgs = args.slice(message === args[1] ? 2 : 1).map((arg) => { | ||
if (arg instanceof Error) { | ||
return { error: formatError(arg) }; | ||
} | ||
return arg; | ||
}); | ||
return { | ||
...logObj, | ||
args: otherArgs.length ? otherArgs : undefined, | ||
...fields, | ||
error, | ||
message, | ||
}; | ||
}; | ||
/* eslint-enable prefer-destructuring */ | ||
class RemoteReporter { | ||
constructor({ requestCount, makeRequest, emitLevels, }) { | ||
this.reqCount = 0; | ||
this.queue = []; | ||
this.requestCount = requestCount || 1; | ||
this.makeRequest = makeRequest; | ||
this.emitLevels = emitLevels || { fatal: true }; | ||
} | ||
checkQueue() { | ||
if (this.queue.length && this.reqCount < this.requestCount) { | ||
this.sendRequest(); | ||
} | ||
} | ||
sendRequest() { | ||
const logObj = this.queue.shift(); | ||
// eslint-disable-next-line no-plusplus | ||
this.reqCount++; | ||
// eslint-disable-next-line promise/catch-or-return | ||
this.makeRequest(formatJson(logObj)) | ||
.catch(noop) | ||
.then(() => { | ||
// eslint-disable-next-line no-plusplus | ||
this.reqCount--; | ||
this.checkQueue(); | ||
}); | ||
} | ||
remote(logObj) { | ||
this.queue.push(logObj); | ||
this.checkQueue(); | ||
} | ||
log(logObj) { | ||
const { type, remote } = logObj; | ||
if (remote != null) { | ||
if (remote === true || pathEq(['emitLevels', type], true, remote)) { | ||
this.remote({ ...logObj, remote: undefined }); | ||
} | ||
return; | ||
} | ||
if (this.emitLevels[type]) { | ||
this.remote(logObj); | ||
} | ||
} | ||
} | ||
export { BrowserReporter, LEVELS, LEVEL_NAMES, RemoteReporter, createLoggerFactory, logger as default, formatJson, logger }; | ||
import { logger } from './browser.browser.js'; | ||
export { logger as default, logger } from './browser.browser.js'; | ||
export { createLoggerFactory } from './factory.browser.js'; | ||
export { BrowserReporter } from './reporters/browser/browser.browser.js'; | ||
export { RemoteReporter } from './reporters/remote.browser.js'; | ||
export { LEVELS, LEVEL_NAMES } from './constants.browser.js'; | ||
export { formatJson } from './reporters/utils/formatJson.browser.js'; |
@@ -1,635 +0,10 @@ | ||
import each from '@tinkoff/utils/array/each'; | ||
import split from '@tinkoff/utils/string/split'; | ||
import env from 'std-env'; | ||
import { hostname } from 'os'; | ||
import toLower from '@tinkoff/utils/string/toLower'; | ||
import eachObj from '@tinkoff/utils/object/each'; | ||
import toArray from '@tinkoff/utils/array/toArray'; | ||
import util from 'util'; | ||
import { sep } from 'path'; | ||
import { format } from 'date-fns'; | ||
import figures from 'figures'; | ||
import chalk from 'chalk'; | ||
import { safeStringifyJSON } from '@tramvai/safe-strings'; | ||
import isString from '@tinkoff/utils/is/string'; | ||
import isObject from '@tinkoff/utils/is/object'; | ||
import isArray from '@tinkoff/utils/is/array'; | ||
import noop from '@tinkoff/utils/function/noop'; | ||
import pathEq from '@tinkoff/utils/object/pathEq'; | ||
const LEVELS = { | ||
trace: 50, | ||
debug: 40, | ||
info: 30, | ||
warn: 20, | ||
error: 10, | ||
fatal: 0, | ||
silent: -Infinity, | ||
}; | ||
const LEVEL_NAMES = { | ||
50: 'trace', | ||
40: 'debug', | ||
30: 'info', | ||
20: 'warn', | ||
10: 'error', | ||
0: 'fatal', | ||
}; | ||
const createRegexpFromNamespace = (namespace) => { | ||
return new RegExp(`^${namespace.replace(/\*/g, '.*?')}$`); | ||
}; | ||
class Logger { | ||
// eslint-disable-next-line sort-class-members/sort-class-members | ||
constructor(options = { name: '' }) { | ||
this.name = toLower(options.name); | ||
this.key = options.key || this.name; | ||
if (Logger.instances[this.key]) { | ||
return Logger.instances[this.key]; | ||
} | ||
this.beforeReporters = options.beforeReporters || []; | ||
this.reporters = options.reporters || []; | ||
this.filters = options.filters || []; | ||
this.extensions = options.extensions || []; | ||
this.defaults = options.defaults || {}; | ||
if (options.level) { | ||
this.setLevel(LEVELS[options.level]); | ||
} | ||
if (options.enabled) { | ||
this.setLevel(LEVELS.trace); | ||
} | ||
this.checkEnabled(); | ||
Logger.instances[this.key] = this; | ||
eachObj((level, levelName) => { | ||
this[levelName] = (...args) => { | ||
return this.log(level, args); | ||
}; | ||
}, LEVELS); | ||
} | ||
static save() { | ||
var _a; | ||
(_a = Logger.onChange) === null || _a === void 0 ? void 0 : _a.call(Logger, { | ||
level: Logger.level, | ||
enabledName: this.enabledName, | ||
enabledLevel: this.enabledLevel, | ||
}); | ||
} | ||
static load(state) { | ||
Logger.level = state.level; | ||
Logger.enabledName = state.enabledName; | ||
Logger.enabledLevel = state.enabledLevel; | ||
} | ||
static setLevel(newLevel) { | ||
var _a; | ||
Logger.level = (_a = LEVELS[newLevel]) !== null && _a !== void 0 ? _a : Logger.level; | ||
Logger.save(); | ||
} | ||
static setOnChange(onChange) { | ||
Logger.onChange = onChange; | ||
} | ||
static enable(level, namespace) { | ||
const [lvl, ns] = namespace ? [LEVELS[level], namespace] : [LEVELS.trace, level]; | ||
Logger.enabledName.push(ns); | ||
Logger.enabledLevel.push(lvl); | ||
Logger.save(); | ||
const regexp = createRegexpFromNamespace(ns); | ||
eachObj((instance) => { | ||
const { name } = instance; | ||
if (regexp.test(name)) { | ||
instance.setLevel(lvl); | ||
} | ||
}, Logger.instances); | ||
} | ||
static disable(level, namespace) { | ||
const [lvl, ns] = namespace ? [LEVELS[level], namespace] : [LEVELS.silent, level]; | ||
const index = Logger.enabledName.indexOf(ns); | ||
if (index > -1) { | ||
Logger.enabledName.splice(index, 1); | ||
Logger.enabledLevel.splice(index, 1); | ||
} | ||
else { | ||
Logger.enabledName.push(ns); | ||
Logger.enabledLevel.push(lvl); | ||
} | ||
Logger.save(); | ||
const regexp = createRegexpFromNamespace(ns); | ||
eachObj((instance) => { | ||
const { name } = instance; | ||
if (regexp.test(name)) { | ||
instance.setLevel(lvl); | ||
} | ||
}, Logger.instances); | ||
} | ||
static clear() { | ||
Logger.level = LEVELS.silent; | ||
Logger.enabledName = []; | ||
Logger.enabledLevel = []; | ||
Logger.save(); | ||
eachObj((instance) => { | ||
instance.setLevel(undefined); | ||
}, Logger.instances); | ||
} | ||
static setGlobalReporters(reporters) { | ||
const reportersArr = toArray(reporters); | ||
eachObj((instance) => { | ||
// eslint-disable-next-line no-param-reassign | ||
instance.reporters = reportersArr; | ||
}, Logger.instances); | ||
} | ||
child(options) { | ||
const opts = typeof options === 'string' ? { name: options } : options; | ||
const childKey = opts.key || opts.name; | ||
const name = this.name ? `${this.name}.${opts.name}` : opts.name; | ||
const key = this.key ? `${this.key}.${childKey}` : childKey; | ||
return new Logger({ | ||
beforeReporters: this.beforeReporters, | ||
reporters: this.reporters, | ||
filters: this.filters, | ||
extensions: this.extensions, | ||
defaults: this.defaults, | ||
...opts, | ||
name, | ||
key, | ||
}); | ||
} | ||
addBeforeReporter(reporter) { | ||
this.beforeReporters = this.beforeReporters.concat(reporter); | ||
} | ||
setBeforeReporters(reporters) { | ||
this.beforeReporters = toArray(reporters); | ||
} | ||
addReporter(reporter) { | ||
this.reporters = this.reporters.concat(reporter); | ||
} | ||
setReporters(reporters) { | ||
this.reporters = toArray(reporters); | ||
} | ||
addFilter(filter) { | ||
this.filters = this.filters.concat(filter); | ||
} | ||
setFilters(filters) { | ||
this.filters = toArray(filters); | ||
} | ||
addExtension(extension) { | ||
this.extensions = this.extensions.concat(extension); | ||
this.extensions.push(extension); | ||
} | ||
setExtensions(extensions) { | ||
this.extensions = toArray(extensions); | ||
} | ||
setLevel(level) { | ||
this.level = level; | ||
} | ||
checkEnabled() { | ||
const len = Logger.enabledName.length; | ||
for (let i = len - 1; i >= 0; i--) { | ||
const namespace = Logger.enabledName[i]; | ||
const regexp = createRegexpFromNamespace(namespace); | ||
if (regexp.test(this.name)) { | ||
this.setLevel(Logger.enabledLevel[i]); | ||
return; | ||
} | ||
} | ||
} | ||
createLogObj(level, args) { | ||
return { | ||
date: new Date(), | ||
...this.defaults, | ||
name: this.name, | ||
type: LEVEL_NAMES[level], | ||
level, | ||
args, | ||
}; | ||
} | ||
log(level, args) { | ||
let logObj; | ||
if (this.beforeReporters.length) { | ||
logObj = this.createLogObj(level, args); | ||
} | ||
for (const reporter of this.beforeReporters) { | ||
reporter.log(logObj); | ||
} | ||
if (typeof this.level === 'undefined') { | ||
if (level > Logger.level) { | ||
return false; | ||
} | ||
} | ||
else if (level > this.level) { | ||
return false; | ||
} | ||
if (!logObj) { | ||
logObj = this.createLogObj(level, args); | ||
} | ||
for (const filter of this.filters) { | ||
if (filter.filter(logObj) === false) { | ||
return false; | ||
} | ||
} | ||
for (const extension of this.extensions) { | ||
logObj = extension.extend(logObj); | ||
} | ||
for (const reporter of this.reporters) { | ||
reporter.log(logObj); | ||
} | ||
return true; | ||
} | ||
} | ||
Logger.level = LEVELS.silent; | ||
Logger.instances = {}; | ||
Logger.enabledName = []; | ||
Logger.enabledLevel = []; | ||
const bindMethods = [ | ||
'addBeforeReporter', | ||
'setBeforeReporters', | ||
'addReporter', | ||
'setReporters', | ||
'addFilter', | ||
'setFilters', | ||
'addExtension', | ||
'setExtensions', | ||
...Object.keys(LEVELS), | ||
]; | ||
const createLoggerFactory = (options) => { | ||
const instance = new Logger(options); | ||
return Object.assign((opts) => { | ||
return instance.child(opts); | ||
}, bindMethods.reduce((acc, method) => { | ||
if (instance[method]) { | ||
acc[method] = instance[method].bind(instance); | ||
} | ||
return acc; | ||
}, {}), { | ||
setLevel: Logger.setLevel, | ||
setGlobalReporters: Logger.setGlobalReporters, | ||
enable: Logger.enable, | ||
disable: Logger.disable, | ||
clear: Logger.clear, | ||
}); | ||
}; | ||
const parseState = (value) => { | ||
if (!value) { | ||
return; | ||
} | ||
const names = value.split(','); | ||
return { | ||
level: LEVELS.silent, | ||
enabledLevel: Array(names.length).fill(LEVELS.trace), | ||
enabledName: names, | ||
}; | ||
}; | ||
const debugGetState = () => { | ||
try { | ||
return parseState(process.env.DEBUG); | ||
} | ||
catch (e) { } | ||
}; | ||
function parseStack(stack) { | ||
const cwd = process.cwd() + sep; | ||
const lines = stack | ||
.split('\n') | ||
.splice(1) | ||
.map((l) => l.trim().replace('file://', '').replace(cwd, '')); | ||
return lines; | ||
} | ||
function writeStream(data, stream) { | ||
const write = stream.__write || stream.write; | ||
return write.call(stream, data); | ||
} | ||
function formatDate(timeFormat, date) { | ||
return format(date, timeFormat); | ||
} | ||
const DEFAULTS$1 = { | ||
stdout: console._stdout, | ||
dateFormat: 'HH:mm:ss', | ||
formatOptions: { | ||
colors: false, | ||
compact: true, | ||
}, | ||
}; | ||
const bracket = (x) => (x ? `[${x}]` : ''); | ||
class NodeBasicReporter { | ||
constructor(options) { | ||
this.options = { ...DEFAULTS$1, ...options }; | ||
} | ||
// eslint-disable-next-line class-methods-use-this | ||
formatStack(stack) { | ||
return ` ${parseStack(stack).join('\n ')}`; | ||
} | ||
formatArgs(args) { | ||
const _args = args.map((arg) => { | ||
if (arg && typeof arg.stack === 'string') { | ||
return `${arg.message}\n${this.formatStack(arg.stack)}`; | ||
} | ||
return arg; | ||
}); | ||
// Only supported with Node >= 10 | ||
// https://nodejs.org/api/util.html#util_util_inspect_object_options | ||
if (typeof util.formatWithOptions === 'function') { | ||
// @ts-ignore | ||
return util.formatWithOptions(this.options.formatOptions, ..._args); | ||
} | ||
// @ts-ignore | ||
return util.format(..._args); | ||
} | ||
formatDate(date) { | ||
return formatDate(this.options.dateFormat, date); | ||
} | ||
filterAndJoin(arr) { | ||
return arr.filter((x) => x).join(' '); | ||
} | ||
formatLogObj(logObj, options) { | ||
const message = this.formatArgs(logObj.args); | ||
return this.filterAndJoin([bracket(logObj.type), bracket(logObj.name), message]); | ||
} | ||
log(logObj) { | ||
const line = this.formatLogObj(logObj, { | ||
width: this.options.stdout.columns || 0, | ||
}); | ||
return writeStream(`${line}\n`, this.options.stdout); | ||
} | ||
} | ||
const colorCache = {}; | ||
function chalkColor(name) { | ||
let color = colorCache[name]; | ||
if (color) { | ||
return color; | ||
} | ||
if (name[0] === '#') { | ||
color = chalk.hex(name); | ||
} | ||
else { | ||
color = chalk[name] || chalk.keyword(name); | ||
} | ||
colorCache[name] = color; | ||
return color; | ||
} | ||
const bgColorCache = {}; | ||
function chalkBgColor(name) { | ||
let color = bgColorCache[name]; | ||
if (color) { | ||
return color; | ||
} | ||
if (name[0] === '#') { | ||
color = chalk.bgHex(name); | ||
} | ||
else { | ||
color = chalk[`bg${name[0].toUpperCase()}${name.slice(1)}`] || chalk.bgKeyword(name); | ||
} | ||
bgColorCache[name] = color; | ||
return color; | ||
} | ||
const TYPE_COLOR_MAP = { | ||
info: 'cyan', | ||
}; | ||
const LEVEL_COLOR_MAP = { | ||
0: 'red', | ||
10: 'red', | ||
20: 'yellow', | ||
30: 'green', | ||
40: 'white', | ||
}; | ||
const DEFAULTS = { | ||
secondaryColor: 'grey', | ||
formatOptions: { | ||
colors: true, | ||
compact: false, | ||
}, | ||
}; | ||
const TYPE_ICONS = { | ||
info: figures('ℹ'), | ||
success: figures('✔'), | ||
debug: figures('›'), | ||
trace: figures('›'), | ||
log: '', | ||
}; | ||
class NodeDevReporter extends NodeBasicReporter { | ||
constructor(options) { | ||
super({ ...DEFAULTS, ...options }); | ||
} | ||
// eslint-disable-next-line class-methods-use-this | ||
formatStack(stack) { | ||
const grey = chalkColor('grey'); | ||
const cyan = chalkColor('cyan'); | ||
return `\n${parseStack(stack) | ||
.map((line) => ` ${line.replace(/^at +/, (m) => grey(m)).replace(/\((.+)\)/, (_, m) => `(${cyan(m)})`)}`) | ||
.join('\n')}`; | ||
} | ||
formatType(logObj, isBadge) { | ||
const typeColor = TYPE_COLOR_MAP[logObj.type] || LEVEL_COLOR_MAP[logObj.level] || this.options.secondaryColor; | ||
if (isBadge) { | ||
return chalkBgColor(typeColor).black(` ${logObj.type.toUpperCase()} `); | ||
} | ||
const _type = typeof TYPE_ICONS[logObj.type] === 'string' | ||
? TYPE_ICONS[logObj.type] | ||
: logObj.icon || logObj.type; | ||
return _type ? chalkColor(typeColor)(_type) : ''; | ||
} | ||
formatLogObj(logObj) { | ||
var _a; | ||
const [message, ...additional] = this.formatArgs(logObj.args).split('\n'); | ||
const isBadge = typeof logObj.badge !== 'undefined' ? Boolean(logObj.badge) : logObj.level <= 20; | ||
const secondaryColor = chalkColor(this.options.secondaryColor); | ||
const date = secondaryColor(this.formatDate(logObj.date)); | ||
const type = this.formatType(logObj, isBadge); | ||
const name = (_a = logObj.name) !== null && _a !== void 0 ? _a : chalk.cyan(`${logObj.name}`); | ||
const formattedMessage = message.replace(/`([^`]+)`/g, (_, m) => chalk.cyan(m)); | ||
let line = this.filterAndJoin([type, name, date, formattedMessage]); | ||
line += additional.length ? `\n${additional.join('\n')}` : ''; | ||
return isBadge ? `\n${line}\n` : line; | ||
} | ||
} | ||
/* eslint-disable prefer-destructuring */ | ||
const formatError = (error) => { | ||
if (isString(error)) { | ||
// eslint-disable-next-line no-param-reassign | ||
error = new Error(error); | ||
} | ||
return { | ||
...error, | ||
// @ts-ignore | ||
// хотим чтобы всегда был единый формат для error.body и error.code [text] | ||
// игнор потому что в error нет поля body и code | ||
body: safeStringifyJSON(error.body), | ||
// @ts-ignore | ||
code: safeStringifyJSON(error.code), | ||
message: error.message, | ||
stack: error.stack, | ||
}; | ||
}; | ||
const formatJson = (logObj) => { | ||
let fields = null; | ||
let message; | ||
let error; | ||
const { args } = logObj; | ||
if (args[0] instanceof Error) { | ||
error = formatError(args[0]); | ||
if (isString(args[1])) { | ||
message = args[1]; | ||
} | ||
else { | ||
message = args[0].message; | ||
} | ||
} | ||
else if (isObject(args[0]) && !isArray(args[0])) { | ||
fields = args[0]; | ||
error = fields.error && formatError(fields.error); | ||
if (args[0].message) { | ||
message = args[0].message; | ||
} | ||
else if (isString(args[1])) { | ||
message = args[1]; | ||
} | ||
} | ||
else { | ||
message = args[0]; | ||
} | ||
const otherArgs = args.slice(message === args[1] ? 2 : 1).map((arg) => { | ||
if (arg instanceof Error) { | ||
return { error: formatError(arg) }; | ||
} | ||
return arg; | ||
}); | ||
return { | ||
...logObj, | ||
args: otherArgs.length ? otherArgs : undefined, | ||
...fields, | ||
error, | ||
message, | ||
}; | ||
}; | ||
/* eslint-enable prefer-destructuring */ | ||
class JSONReporter { | ||
constructor({ stream = process.stdout, format = formatJson } = {}) { | ||
this.format = format; | ||
this.stream = stream; | ||
} | ||
log(logObj) { | ||
const json = safeStringifyJSON(this.format(logObj)); | ||
this.stream.write(`${json}\n`); | ||
} | ||
} | ||
var _a, _b; | ||
const level = (_a = process.env.LOG_LEVEL) !== null && _a !== void 0 ? _a : process.env.DEBUG_LEVEL; | ||
const enable = (_b = process.env.LOG_ENABLE) !== null && _b !== void 0 ? _b : process.env.DEBUG_ENABLE; | ||
Logger.setLevel(level); | ||
if (enable) { | ||
each((val) => { | ||
const [lvl, ...name] = val.split(':'); | ||
if (lvl in LEVELS) { | ||
Logger.enable(lvl, name.join(':')); | ||
} | ||
else { | ||
Logger.enable(val); | ||
} | ||
}, split(',', enable)); | ||
} | ||
if (!level && !enable) { | ||
const state = debugGetState(); | ||
state && Logger.load(state); | ||
} | ||
const DefaultReporter = env.ci || env.test ? NodeBasicReporter : NodeDevReporter; | ||
const reporter = process.env.DEBUG_PLAIN || process.env.NODE_ENV !== 'production' | ||
? new DefaultReporter() | ||
: new JSONReporter(); | ||
const logger = createLoggerFactory({ | ||
name: '', | ||
reporters: [reporter], | ||
defaults: { | ||
pid: process.pid, | ||
hostname: hostname(), | ||
}, | ||
}); | ||
class BrowserReporter { | ||
constructor() { | ||
this.defaultColor = '#7f8c8d'; // Gray | ||
this.levelColorMap = { | ||
0: '#c00046', | ||
10: '#c0392b', | ||
20: '#f39c12', | ||
30: '#00BCD4', // Cyan | ||
}; | ||
} | ||
log(logObj) { | ||
const consoleLogFn = | ||
// eslint-disable-next-line no-nested-ternary, no-console | ||
logObj.level < 20 ? console.error : logObj.level === 20 ? console.warn : console.log; | ||
// Styles | ||
const color = this.levelColorMap[logObj.level] || this.defaultColor; | ||
const style = ` | ||
background: ${color}; | ||
border-radius: 0.5em; | ||
color: white; | ||
font-weight: bold; | ||
padding: 2px 0.5em; | ||
`; | ||
const badge = `%c${[logObj.name, logObj.type].filter(Boolean).join(':')}`; | ||
// Log to the console | ||
if (typeof logObj.args[0] === 'string') { | ||
consoleLogFn.call(console, `${badge}%c ${logObj.args[0]}`, style, | ||
// Empty string as style resets to default console style | ||
'', ...logObj.args.slice(1)); | ||
} | ||
else { | ||
consoleLogFn.call(console, badge, style, ...logObj.args); | ||
} | ||
} | ||
} | ||
class RemoteReporter { | ||
constructor({ requestCount, makeRequest, emitLevels, }) { | ||
this.reqCount = 0; | ||
this.queue = []; | ||
this.requestCount = requestCount || 1; | ||
this.makeRequest = makeRequest; | ||
this.emitLevels = emitLevels || { fatal: true }; | ||
} | ||
checkQueue() { | ||
if (this.queue.length && this.reqCount < this.requestCount) { | ||
this.sendRequest(); | ||
} | ||
} | ||
sendRequest() { | ||
const logObj = this.queue.shift(); | ||
// eslint-disable-next-line no-plusplus | ||
this.reqCount++; | ||
// eslint-disable-next-line promise/catch-or-return | ||
this.makeRequest(formatJson(logObj)) | ||
.catch(noop) | ||
.then(() => { | ||
// eslint-disable-next-line no-plusplus | ||
this.reqCount--; | ||
this.checkQueue(); | ||
}); | ||
} | ||
remote(logObj) { | ||
this.queue.push(logObj); | ||
this.checkQueue(); | ||
} | ||
log(logObj) { | ||
const { type, remote } = logObj; | ||
if (remote != null) { | ||
if (remote === true || pathEq(['emitLevels', type], true, remote)) { | ||
this.remote({ ...logObj, remote: undefined }); | ||
} | ||
return; | ||
} | ||
if (this.emitLevels[type]) { | ||
this.remote(logObj); | ||
} | ||
} | ||
} | ||
export { BrowserReporter, JSONReporter, LEVELS, LEVEL_NAMES, NodeBasicReporter, NodeDevReporter, RemoteReporter, createLoggerFactory, logger as default, formatJson, logger }; | ||
import { logger } from './server.es.js'; | ||
export { logger as default, logger } from './server.es.js'; | ||
export { createLoggerFactory } from './factory.es.js'; | ||
export { BrowserReporter } from './reporters/browser/browser.es.js'; | ||
export { NodeBasicReporter } from './reporters/server/nodeBasic.es.js'; | ||
export { NodeDevReporter } from './reporters/server/nodeDev.es.js'; | ||
export { JSONReporter } from './reporters/json.es.js'; | ||
export { RemoteReporter } from './reporters/remote.es.js'; | ||
export { LEVELS, LEVEL_NAMES } from './constants.es.js'; | ||
export { formatJson } from './reporters/utils/formatJson.es.js'; |
679
lib/index.js
@@ -5,663 +5,24 @@ 'use strict'; | ||
var each = require('@tinkoff/utils/array/each'); | ||
var split = require('@tinkoff/utils/string/split'); | ||
var env = require('std-env'); | ||
var os = require('os'); | ||
var toLower = require('@tinkoff/utils/string/toLower'); | ||
var eachObj = require('@tinkoff/utils/object/each'); | ||
var toArray = require('@tinkoff/utils/array/toArray'); | ||
var util = require('util'); | ||
var path = require('path'); | ||
var dateFns = require('date-fns'); | ||
var figures = require('figures'); | ||
var chalk = require('chalk'); | ||
var safeStrings = require('@tramvai/safe-strings'); | ||
var isString = require('@tinkoff/utils/is/string'); | ||
var isObject = require('@tinkoff/utils/is/object'); | ||
var isArray = require('@tinkoff/utils/is/array'); | ||
var noop = require('@tinkoff/utils/function/noop'); | ||
var pathEq = require('@tinkoff/utils/object/pathEq'); | ||
var server = require('./server.js'); | ||
var factory = require('./factory.js'); | ||
var browser = require('./reporters/browser/browser.js'); | ||
var nodeBasic = require('./reporters/server/nodeBasic.js'); | ||
var nodeDev = require('./reporters/server/nodeDev.js'); | ||
var json = require('./reporters/json.js'); | ||
var remote = require('./reporters/remote.js'); | ||
var constants = require('./constants.js'); | ||
var formatJson = require('./reporters/utils/formatJson.js'); | ||
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
var each__default = /*#__PURE__*/_interopDefaultLegacy(each); | ||
var split__default = /*#__PURE__*/_interopDefaultLegacy(split); | ||
var env__default = /*#__PURE__*/_interopDefaultLegacy(env); | ||
var toLower__default = /*#__PURE__*/_interopDefaultLegacy(toLower); | ||
var eachObj__default = /*#__PURE__*/_interopDefaultLegacy(eachObj); | ||
var toArray__default = /*#__PURE__*/_interopDefaultLegacy(toArray); | ||
var util__default = /*#__PURE__*/_interopDefaultLegacy(util); | ||
var figures__default = /*#__PURE__*/_interopDefaultLegacy(figures); | ||
var chalk__default = /*#__PURE__*/_interopDefaultLegacy(chalk); | ||
var isString__default = /*#__PURE__*/_interopDefaultLegacy(isString); | ||
var isObject__default = /*#__PURE__*/_interopDefaultLegacy(isObject); | ||
var isArray__default = /*#__PURE__*/_interopDefaultLegacy(isArray); | ||
var noop__default = /*#__PURE__*/_interopDefaultLegacy(noop); | ||
var pathEq__default = /*#__PURE__*/_interopDefaultLegacy(pathEq); | ||
const LEVELS = { | ||
trace: 50, | ||
debug: 40, | ||
info: 30, | ||
warn: 20, | ||
error: 10, | ||
fatal: 0, | ||
silent: -Infinity, | ||
}; | ||
const LEVEL_NAMES = { | ||
50: 'trace', | ||
40: 'debug', | ||
30: 'info', | ||
20: 'warn', | ||
10: 'error', | ||
0: 'fatal', | ||
}; | ||
const createRegexpFromNamespace = (namespace) => { | ||
return new RegExp(`^${namespace.replace(/\*/g, '.*?')}$`); | ||
}; | ||
class Logger { | ||
// eslint-disable-next-line sort-class-members/sort-class-members | ||
constructor(options = { name: '' }) { | ||
this.name = toLower__default["default"](options.name); | ||
this.key = options.key || this.name; | ||
if (Logger.instances[this.key]) { | ||
return Logger.instances[this.key]; | ||
} | ||
this.beforeReporters = options.beforeReporters || []; | ||
this.reporters = options.reporters || []; | ||
this.filters = options.filters || []; | ||
this.extensions = options.extensions || []; | ||
this.defaults = options.defaults || {}; | ||
if (options.level) { | ||
this.setLevel(LEVELS[options.level]); | ||
} | ||
if (options.enabled) { | ||
this.setLevel(LEVELS.trace); | ||
} | ||
this.checkEnabled(); | ||
Logger.instances[this.key] = this; | ||
eachObj__default["default"]((level, levelName) => { | ||
this[levelName] = (...args) => { | ||
return this.log(level, args); | ||
}; | ||
}, LEVELS); | ||
} | ||
static save() { | ||
var _a; | ||
(_a = Logger.onChange) === null || _a === void 0 ? void 0 : _a.call(Logger, { | ||
level: Logger.level, | ||
enabledName: this.enabledName, | ||
enabledLevel: this.enabledLevel, | ||
}); | ||
} | ||
static load(state) { | ||
Logger.level = state.level; | ||
Logger.enabledName = state.enabledName; | ||
Logger.enabledLevel = state.enabledLevel; | ||
} | ||
static setLevel(newLevel) { | ||
var _a; | ||
Logger.level = (_a = LEVELS[newLevel]) !== null && _a !== void 0 ? _a : Logger.level; | ||
Logger.save(); | ||
} | ||
static setOnChange(onChange) { | ||
Logger.onChange = onChange; | ||
} | ||
static enable(level, namespace) { | ||
const [lvl, ns] = namespace ? [LEVELS[level], namespace] : [LEVELS.trace, level]; | ||
Logger.enabledName.push(ns); | ||
Logger.enabledLevel.push(lvl); | ||
Logger.save(); | ||
const regexp = createRegexpFromNamespace(ns); | ||
eachObj__default["default"]((instance) => { | ||
const { name } = instance; | ||
if (regexp.test(name)) { | ||
instance.setLevel(lvl); | ||
} | ||
}, Logger.instances); | ||
} | ||
static disable(level, namespace) { | ||
const [lvl, ns] = namespace ? [LEVELS[level], namespace] : [LEVELS.silent, level]; | ||
const index = Logger.enabledName.indexOf(ns); | ||
if (index > -1) { | ||
Logger.enabledName.splice(index, 1); | ||
Logger.enabledLevel.splice(index, 1); | ||
} | ||
else { | ||
Logger.enabledName.push(ns); | ||
Logger.enabledLevel.push(lvl); | ||
} | ||
Logger.save(); | ||
const regexp = createRegexpFromNamespace(ns); | ||
eachObj__default["default"]((instance) => { | ||
const { name } = instance; | ||
if (regexp.test(name)) { | ||
instance.setLevel(lvl); | ||
} | ||
}, Logger.instances); | ||
} | ||
static clear() { | ||
Logger.level = LEVELS.silent; | ||
Logger.enabledName = []; | ||
Logger.enabledLevel = []; | ||
Logger.save(); | ||
eachObj__default["default"]((instance) => { | ||
instance.setLevel(undefined); | ||
}, Logger.instances); | ||
} | ||
static setGlobalReporters(reporters) { | ||
const reportersArr = toArray__default["default"](reporters); | ||
eachObj__default["default"]((instance) => { | ||
// eslint-disable-next-line no-param-reassign | ||
instance.reporters = reportersArr; | ||
}, Logger.instances); | ||
} | ||
child(options) { | ||
const opts = typeof options === 'string' ? { name: options } : options; | ||
const childKey = opts.key || opts.name; | ||
const name = this.name ? `${this.name}.${opts.name}` : opts.name; | ||
const key = this.key ? `${this.key}.${childKey}` : childKey; | ||
return new Logger({ | ||
beforeReporters: this.beforeReporters, | ||
reporters: this.reporters, | ||
filters: this.filters, | ||
extensions: this.extensions, | ||
defaults: this.defaults, | ||
...opts, | ||
name, | ||
key, | ||
}); | ||
} | ||
addBeforeReporter(reporter) { | ||
this.beforeReporters = this.beforeReporters.concat(reporter); | ||
} | ||
setBeforeReporters(reporters) { | ||
this.beforeReporters = toArray__default["default"](reporters); | ||
} | ||
addReporter(reporter) { | ||
this.reporters = this.reporters.concat(reporter); | ||
} | ||
setReporters(reporters) { | ||
this.reporters = toArray__default["default"](reporters); | ||
} | ||
addFilter(filter) { | ||
this.filters = this.filters.concat(filter); | ||
} | ||
setFilters(filters) { | ||
this.filters = toArray__default["default"](filters); | ||
} | ||
addExtension(extension) { | ||
this.extensions = this.extensions.concat(extension); | ||
this.extensions.push(extension); | ||
} | ||
setExtensions(extensions) { | ||
this.extensions = toArray__default["default"](extensions); | ||
} | ||
setLevel(level) { | ||
this.level = level; | ||
} | ||
checkEnabled() { | ||
const len = Logger.enabledName.length; | ||
for (let i = len - 1; i >= 0; i--) { | ||
const namespace = Logger.enabledName[i]; | ||
const regexp = createRegexpFromNamespace(namespace); | ||
if (regexp.test(this.name)) { | ||
this.setLevel(Logger.enabledLevel[i]); | ||
return; | ||
} | ||
} | ||
} | ||
createLogObj(level, args) { | ||
return { | ||
date: new Date(), | ||
...this.defaults, | ||
name: this.name, | ||
type: LEVEL_NAMES[level], | ||
level, | ||
args, | ||
}; | ||
} | ||
log(level, args) { | ||
let logObj; | ||
if (this.beforeReporters.length) { | ||
logObj = this.createLogObj(level, args); | ||
} | ||
for (const reporter of this.beforeReporters) { | ||
reporter.log(logObj); | ||
} | ||
if (typeof this.level === 'undefined') { | ||
if (level > Logger.level) { | ||
return false; | ||
} | ||
} | ||
else if (level > this.level) { | ||
return false; | ||
} | ||
if (!logObj) { | ||
logObj = this.createLogObj(level, args); | ||
} | ||
for (const filter of this.filters) { | ||
if (filter.filter(logObj) === false) { | ||
return false; | ||
} | ||
} | ||
for (const extension of this.extensions) { | ||
logObj = extension.extend(logObj); | ||
} | ||
for (const reporter of this.reporters) { | ||
reporter.log(logObj); | ||
} | ||
return true; | ||
} | ||
} | ||
Logger.level = LEVELS.silent; | ||
Logger.instances = {}; | ||
Logger.enabledName = []; | ||
Logger.enabledLevel = []; | ||
const bindMethods = [ | ||
'addBeforeReporter', | ||
'setBeforeReporters', | ||
'addReporter', | ||
'setReporters', | ||
'addFilter', | ||
'setFilters', | ||
'addExtension', | ||
'setExtensions', | ||
...Object.keys(LEVELS), | ||
]; | ||
const createLoggerFactory = (options) => { | ||
const instance = new Logger(options); | ||
return Object.assign((opts) => { | ||
return instance.child(opts); | ||
}, bindMethods.reduce((acc, method) => { | ||
if (instance[method]) { | ||
acc[method] = instance[method].bind(instance); | ||
} | ||
return acc; | ||
}, {}), { | ||
setLevel: Logger.setLevel, | ||
setGlobalReporters: Logger.setGlobalReporters, | ||
enable: Logger.enable, | ||
disable: Logger.disable, | ||
clear: Logger.clear, | ||
}); | ||
}; | ||
const parseState = (value) => { | ||
if (!value) { | ||
return; | ||
} | ||
const names = value.split(','); | ||
return { | ||
level: LEVELS.silent, | ||
enabledLevel: Array(names.length).fill(LEVELS.trace), | ||
enabledName: names, | ||
}; | ||
}; | ||
const debugGetState = () => { | ||
try { | ||
return parseState(process.env.DEBUG); | ||
} | ||
catch (e) { } | ||
}; | ||
function parseStack(stack) { | ||
const cwd = process.cwd() + path.sep; | ||
const lines = stack | ||
.split('\n') | ||
.splice(1) | ||
.map((l) => l.trim().replace('file://', '').replace(cwd, '')); | ||
return lines; | ||
} | ||
function writeStream(data, stream) { | ||
const write = stream.__write || stream.write; | ||
return write.call(stream, data); | ||
} | ||
function formatDate(timeFormat, date) { | ||
return dateFns.format(date, timeFormat); | ||
} | ||
const DEFAULTS$1 = { | ||
stdout: console._stdout, | ||
dateFormat: 'HH:mm:ss', | ||
formatOptions: { | ||
colors: false, | ||
compact: true, | ||
}, | ||
}; | ||
const bracket = (x) => (x ? `[${x}]` : ''); | ||
class NodeBasicReporter { | ||
constructor(options) { | ||
this.options = { ...DEFAULTS$1, ...options }; | ||
} | ||
// eslint-disable-next-line class-methods-use-this | ||
formatStack(stack) { | ||
return ` ${parseStack(stack).join('\n ')}`; | ||
} | ||
formatArgs(args) { | ||
const _args = args.map((arg) => { | ||
if (arg && typeof arg.stack === 'string') { | ||
return `${arg.message}\n${this.formatStack(arg.stack)}`; | ||
} | ||
return arg; | ||
}); | ||
// Only supported with Node >= 10 | ||
// https://nodejs.org/api/util.html#util_util_inspect_object_options | ||
if (typeof util__default["default"].formatWithOptions === 'function') { | ||
// @ts-ignore | ||
return util__default["default"].formatWithOptions(this.options.formatOptions, ..._args); | ||
} | ||
// @ts-ignore | ||
return util__default["default"].format(..._args); | ||
} | ||
formatDate(date) { | ||
return formatDate(this.options.dateFormat, date); | ||
} | ||
filterAndJoin(arr) { | ||
return arr.filter((x) => x).join(' '); | ||
} | ||
formatLogObj(logObj, options) { | ||
const message = this.formatArgs(logObj.args); | ||
return this.filterAndJoin([bracket(logObj.type), bracket(logObj.name), message]); | ||
} | ||
log(logObj) { | ||
const line = this.formatLogObj(logObj, { | ||
width: this.options.stdout.columns || 0, | ||
}); | ||
return writeStream(`${line}\n`, this.options.stdout); | ||
} | ||
} | ||
const colorCache = {}; | ||
function chalkColor(name) { | ||
let color = colorCache[name]; | ||
if (color) { | ||
return color; | ||
} | ||
if (name[0] === '#') { | ||
color = chalk__default["default"].hex(name); | ||
} | ||
else { | ||
color = chalk__default["default"][name] || chalk__default["default"].keyword(name); | ||
} | ||
colorCache[name] = color; | ||
return color; | ||
} | ||
const bgColorCache = {}; | ||
function chalkBgColor(name) { | ||
let color = bgColorCache[name]; | ||
if (color) { | ||
return color; | ||
} | ||
if (name[0] === '#') { | ||
color = chalk__default["default"].bgHex(name); | ||
} | ||
else { | ||
color = chalk__default["default"][`bg${name[0].toUpperCase()}${name.slice(1)}`] || chalk__default["default"].bgKeyword(name); | ||
} | ||
bgColorCache[name] = color; | ||
return color; | ||
} | ||
const TYPE_COLOR_MAP = { | ||
info: 'cyan', | ||
}; | ||
const LEVEL_COLOR_MAP = { | ||
0: 'red', | ||
10: 'red', | ||
20: 'yellow', | ||
30: 'green', | ||
40: 'white', | ||
}; | ||
const DEFAULTS = { | ||
secondaryColor: 'grey', | ||
formatOptions: { | ||
colors: true, | ||
compact: false, | ||
}, | ||
}; | ||
const TYPE_ICONS = { | ||
info: figures__default["default"]('ℹ'), | ||
success: figures__default["default"]('✔'), | ||
debug: figures__default["default"]('›'), | ||
trace: figures__default["default"]('›'), | ||
log: '', | ||
}; | ||
class NodeDevReporter extends NodeBasicReporter { | ||
constructor(options) { | ||
super({ ...DEFAULTS, ...options }); | ||
} | ||
// eslint-disable-next-line class-methods-use-this | ||
formatStack(stack) { | ||
const grey = chalkColor('grey'); | ||
const cyan = chalkColor('cyan'); | ||
return `\n${parseStack(stack) | ||
.map((line) => ` ${line.replace(/^at +/, (m) => grey(m)).replace(/\((.+)\)/, (_, m) => `(${cyan(m)})`)}`) | ||
.join('\n')}`; | ||
} | ||
formatType(logObj, isBadge) { | ||
const typeColor = TYPE_COLOR_MAP[logObj.type] || LEVEL_COLOR_MAP[logObj.level] || this.options.secondaryColor; | ||
if (isBadge) { | ||
return chalkBgColor(typeColor).black(` ${logObj.type.toUpperCase()} `); | ||
} | ||
const _type = typeof TYPE_ICONS[logObj.type] === 'string' | ||
? TYPE_ICONS[logObj.type] | ||
: logObj.icon || logObj.type; | ||
return _type ? chalkColor(typeColor)(_type) : ''; | ||
} | ||
formatLogObj(logObj) { | ||
var _a; | ||
const [message, ...additional] = this.formatArgs(logObj.args).split('\n'); | ||
const isBadge = typeof logObj.badge !== 'undefined' ? Boolean(logObj.badge) : logObj.level <= 20; | ||
const secondaryColor = chalkColor(this.options.secondaryColor); | ||
const date = secondaryColor(this.formatDate(logObj.date)); | ||
const type = this.formatType(logObj, isBadge); | ||
const name = (_a = logObj.name) !== null && _a !== void 0 ? _a : chalk__default["default"].cyan(`${logObj.name}`); | ||
const formattedMessage = message.replace(/`([^`]+)`/g, (_, m) => chalk__default["default"].cyan(m)); | ||
let line = this.filterAndJoin([type, name, date, formattedMessage]); | ||
line += additional.length ? `\n${additional.join('\n')}` : ''; | ||
return isBadge ? `\n${line}\n` : line; | ||
} | ||
} | ||
/* eslint-disable prefer-destructuring */ | ||
const formatError = (error) => { | ||
if (isString__default["default"](error)) { | ||
// eslint-disable-next-line no-param-reassign | ||
error = new Error(error); | ||
} | ||
return { | ||
...error, | ||
// @ts-ignore | ||
// хотим чтобы всегда был единый формат для error.body и error.code [text] | ||
// игнор потому что в error нет поля body и code | ||
body: safeStrings.safeStringifyJSON(error.body), | ||
// @ts-ignore | ||
code: safeStrings.safeStringifyJSON(error.code), | ||
message: error.message, | ||
stack: error.stack, | ||
}; | ||
}; | ||
const formatJson = (logObj) => { | ||
let fields = null; | ||
let message; | ||
let error; | ||
const { args } = logObj; | ||
if (args[0] instanceof Error) { | ||
error = formatError(args[0]); | ||
if (isString__default["default"](args[1])) { | ||
message = args[1]; | ||
} | ||
else { | ||
message = args[0].message; | ||
} | ||
} | ||
else if (isObject__default["default"](args[0]) && !isArray__default["default"](args[0])) { | ||
fields = args[0]; | ||
error = fields.error && formatError(fields.error); | ||
if (args[0].message) { | ||
message = args[0].message; | ||
} | ||
else if (isString__default["default"](args[1])) { | ||
message = args[1]; | ||
} | ||
} | ||
else { | ||
message = args[0]; | ||
} | ||
const otherArgs = args.slice(message === args[1] ? 2 : 1).map((arg) => { | ||
if (arg instanceof Error) { | ||
return { error: formatError(arg) }; | ||
} | ||
return arg; | ||
}); | ||
return { | ||
...logObj, | ||
args: otherArgs.length ? otherArgs : undefined, | ||
...fields, | ||
error, | ||
message, | ||
}; | ||
}; | ||
/* eslint-enable prefer-destructuring */ | ||
class JSONReporter { | ||
constructor({ stream = process.stdout, format = formatJson } = {}) { | ||
this.format = format; | ||
this.stream = stream; | ||
} | ||
log(logObj) { | ||
const json = safeStrings.safeStringifyJSON(this.format(logObj)); | ||
this.stream.write(`${json}\n`); | ||
} | ||
} | ||
var _a, _b; | ||
const level = (_a = process.env.LOG_LEVEL) !== null && _a !== void 0 ? _a : process.env.DEBUG_LEVEL; | ||
const enable = (_b = process.env.LOG_ENABLE) !== null && _b !== void 0 ? _b : process.env.DEBUG_ENABLE; | ||
Logger.setLevel(level); | ||
if (enable) { | ||
each__default["default"]((val) => { | ||
const [lvl, ...name] = val.split(':'); | ||
if (lvl in LEVELS) { | ||
Logger.enable(lvl, name.join(':')); | ||
} | ||
else { | ||
Logger.enable(val); | ||
} | ||
}, split__default["default"](',', enable)); | ||
} | ||
if (!level && !enable) { | ||
const state = debugGetState(); | ||
state && Logger.load(state); | ||
} | ||
const DefaultReporter = env__default["default"].ci || env__default["default"].test ? NodeBasicReporter : NodeDevReporter; | ||
const reporter = process.env.DEBUG_PLAIN || process.env.NODE_ENV !== 'production' | ||
? new DefaultReporter() | ||
: new JSONReporter(); | ||
const logger = createLoggerFactory({ | ||
name: '', | ||
reporters: [reporter], | ||
defaults: { | ||
pid: process.pid, | ||
hostname: os.hostname(), | ||
}, | ||
}); | ||
class BrowserReporter { | ||
constructor() { | ||
this.defaultColor = '#7f8c8d'; // Gray | ||
this.levelColorMap = { | ||
0: '#c00046', | ||
10: '#c0392b', | ||
20: '#f39c12', | ||
30: '#00BCD4', // Cyan | ||
}; | ||
} | ||
log(logObj) { | ||
const consoleLogFn = | ||
// eslint-disable-next-line no-nested-ternary, no-console | ||
logObj.level < 20 ? console.error : logObj.level === 20 ? console.warn : console.log; | ||
// Styles | ||
const color = this.levelColorMap[logObj.level] || this.defaultColor; | ||
const style = ` | ||
background: ${color}; | ||
border-radius: 0.5em; | ||
color: white; | ||
font-weight: bold; | ||
padding: 2px 0.5em; | ||
`; | ||
const badge = `%c${[logObj.name, logObj.type].filter(Boolean).join(':')}`; | ||
// Log to the console | ||
if (typeof logObj.args[0] === 'string') { | ||
consoleLogFn.call(console, `${badge}%c ${logObj.args[0]}`, style, | ||
// Empty string as style resets to default console style | ||
'', ...logObj.args.slice(1)); | ||
} | ||
else { | ||
consoleLogFn.call(console, badge, style, ...logObj.args); | ||
} | ||
} | ||
} | ||
class RemoteReporter { | ||
constructor({ requestCount, makeRequest, emitLevels, }) { | ||
this.reqCount = 0; | ||
this.queue = []; | ||
this.requestCount = requestCount || 1; | ||
this.makeRequest = makeRequest; | ||
this.emitLevels = emitLevels || { fatal: true }; | ||
} | ||
checkQueue() { | ||
if (this.queue.length && this.reqCount < this.requestCount) { | ||
this.sendRequest(); | ||
} | ||
} | ||
sendRequest() { | ||
const logObj = this.queue.shift(); | ||
// eslint-disable-next-line no-plusplus | ||
this.reqCount++; | ||
// eslint-disable-next-line promise/catch-or-return | ||
this.makeRequest(formatJson(logObj)) | ||
.catch(noop__default["default"]) | ||
.then(() => { | ||
// eslint-disable-next-line no-plusplus | ||
this.reqCount--; | ||
this.checkQueue(); | ||
}); | ||
} | ||
remote(logObj) { | ||
this.queue.push(logObj); | ||
this.checkQueue(); | ||
} | ||
log(logObj) { | ||
const { type, remote } = logObj; | ||
if (remote != null) { | ||
if (remote === true || pathEq__default["default"](['emitLevels', type], true, remote)) { | ||
this.remote({ ...logObj, remote: undefined }); | ||
} | ||
return; | ||
} | ||
if (this.emitLevels[type]) { | ||
this.remote(logObj); | ||
} | ||
} | ||
} | ||
exports.BrowserReporter = BrowserReporter; | ||
exports.JSONReporter = JSONReporter; | ||
exports.LEVELS = LEVELS; | ||
exports.LEVEL_NAMES = LEVEL_NAMES; | ||
exports.NodeBasicReporter = NodeBasicReporter; | ||
exports.NodeDevReporter = NodeDevReporter; | ||
exports.RemoteReporter = RemoteReporter; | ||
exports.createLoggerFactory = createLoggerFactory; | ||
exports["default"] = logger; | ||
exports.formatJson = formatJson; | ||
exports.logger = logger; | ||
exports["default"] = server.logger; | ||
exports.logger = server.logger; | ||
exports.createLoggerFactory = factory.createLoggerFactory; | ||
exports.BrowserReporter = browser.BrowserReporter; | ||
exports.NodeBasicReporter = nodeBasic.NodeBasicReporter; | ||
exports.NodeDevReporter = nodeDev.NodeDevReporter; | ||
exports.JSONReporter = json.JSONReporter; | ||
exports.RemoteReporter = remote.RemoteReporter; | ||
exports.LEVELS = constants.LEVELS; | ||
exports.LEVEL_NAMES = constants.LEVEL_NAMES; | ||
exports.formatJson = formatJson.formatJson; |
{ | ||
"name": "@tinkoff/logger", | ||
"version": "0.10.57", | ||
"version": "0.10.58", | ||
"description": "", | ||
@@ -18,2 +18,3 @@ "main": "lib/index.js", | ||
"sideEffects": [ | ||
"./lib/index.js", | ||
"./lib/browser.js", | ||
@@ -28,9 +29,8 @@ "./lib/index.browser.js", | ||
"scripts": { | ||
"build": "tramvai-build --for-publish", | ||
"watch": "tsc -w", | ||
"build-for-publish": "true" | ||
"build": "tramvai-build --forPublish --preserveModules", | ||
"watch": "tsc -w" | ||
}, | ||
"dependencies": { | ||
"@tinkoff/utils": "^2.1.2", | ||
"@tramvai/safe-strings": "0.5.6", | ||
"@tramvai/safe-strings": "0.5.7", | ||
"chalk": "^3.0.0", | ||
@@ -37,0 +37,0 @@ "date-fns": "^2.11.0", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
81870
71
2138
1
+ Added@tramvai/safe-strings@0.5.7(transitive)
- Removed@tramvai/safe-strings@0.5.6(transitive)
Updated@tramvai/safe-strings@0.5.7