winston
версия? _node -v
выходы: _ v8.11.1Регистрация объекта узла Error
приводит к пустому сообщению:
Пример:
const winston = require('winston');
const { createLogger, format, transports } = winston;
const logger = createLogger({
transports: [
new transports.Console()
]
});
let err = new Error('this is a test');
logger.log({level: 'error', message: err});
Результат:
% node test.js
{"level":"error","message":{}}
Также:
logger.error(new Error('hello'))
Результаты в:
{"level":"error"}
Я ожидаю, что в ключе сообщения будет хотя бы сообщение об ошибке. Если я попробую использовать специальный форматировщик, в info
также нет объекта ошибки, поэтому его нужно где-то удалить?
Дайте мне знать, чем я могу помочь - я рад щелкнуть PR, но я еще не знаю, как обойтись [email protected]
достаточно, чтобы его найти
У нас есть тестовое покрытие для этого, но очевидно, что нам нужно больше. Что творится под одеялом:
Error
передается по цепочке потоков objectMode
Logger
- json
(см .: код формата json
в logform
)message
и stack
в Error
не перечисляются, что приводит к тому, что JSON.stringify
выводит то, чего никто не ожидает.console.log(JSON.stringify(new Error('lol nothing here')));
// '{}'
С точки зрения дизайна winston@3
представил formats
именно для такого рода задач, чтобы повысить производительность. Говоря о производительности, что интересно, pino
делает здесь кое-что интересное . Возможно, решение реализует что-то похожее на asJson
в формате по умолчанию json
.
Если кто-то ищет быстрое решение, вы можете пока включить enumerateErrorFormat
в формат вашего регистратора. Мы надеемся исправить это до 3.0.0
следующей неделе (или вскоре после этого в 3.0.1
)
const winston = require('../');
const { createLogger, format, transports } = winston;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
const logger = createLogger({
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new transports.Console()
]
});
// Error as message
console.log('Run FIRST test...');
logger.log({ level: 'error', message: new Error('FIRST test error') });
// Error as info (one argument)
console.log('\nRun SECOND test...');
const err = new Error('SECOND test error');
err.level = 'info';
logger.info(err);
// Error as info (two arguments);
console.log('\nRun THIRD test...');
logger.log('info', new Error('THIRD test error'));
@indexzero , я попытался путем , но он не работает. Ты знаешь почему?
Форматировщик:
`` ` javascript
const level = settings.debug ? 'debug' : 'info';
const printFormat = winston.format.printf(info =>
$ {info.timestamp} - $ {info.level}: $ {info.message}`);
const enumerateErrorFormat = winston.format (info => {
if (info.message instanceof Error) {
info.message = Object.assign ({
сообщение: info.message.message,
стек: info.message.stack,
}, info.message);
}
if (info instanceof Error) {
return Object.assign ({
сообщение: info.message,
стек: info.stack,
}, Информация);
}
вернуть информацию;
});
const consoleLogger = winston.createLogger ({
уровень,
формат: winston.format.timestamp (),
транспорты: [
новый winston.transports.Console ({
формат: winston.format.combine (
winston.format.colorize (),
enumerateErrorFormat (),
printFormat,
),
}),
],
});
Code:
javascript
пытаться {
// Некоторая ошибка выдачи кода
} catch (err) {
logger.error (ошибка);
}
Output:
2018-06-28T21: 17: 25.140Z - ошибка: undefined
Info object:
javascript
{level: '\ u001b [31merror \ u001b [39m', отметка времени: '2018-06-28T21: 17: 25.140Z', [Symbol (level)]: 'error'}
`` ''
Где находится атрибут сообщения в журнале ошибок?
@sandrocsimas Я заметил, что вам нужно передать функцию enumerateErrorFormat
Форматировщик
const consoleLogger = winston.createLogger({
level,
format: winston.format.combine(
winston.format.timestamp(),
enumerateErrorFormat()
),
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
printFormat,
),
}),
],
});
Я до сих пор не понимаю, почему
Я думаю, что столкнулся с той же ошибкой, что и @sandrocsimas.
Вот моя конфигурация регистратора:
logger.js
const winston = require('winston');
const {configure, format} = winston;
const {combine, colorize, timestamp, printf} = format;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
const myConsoleFormat = printf(info => {
console.log('** Info Object: **');
console.log(info);
console.log('** Winston Output: **');
return `${info.level}: ${info.message}`;
});
winston.configure({
transports: [
new winston.transports.Console({
format: combine(
colorize(),
enumerateErrorFormat(),
myConsoleFormat
),
})
]
});
Если я протестирую это с помощью этого блока кода:
Тест А
const logger = require('winston');
try {
throw(new Error());
} catch (err) {
logger.error(err);
}
где new Error()
не содержит значения сообщения, я получаю такой вывод:
Выход A
** Info Object: **
{ message:
{ message: '',
stack: 'Error\n at Object.<anonymous> (app.js:21:9)\n at Module._compile (module.js:652:30)\n at Object.Module._extensions..js (module.js:663:10)\n at Module.load (module.js:565:32)\n at tryModuleLoad (module.js:505:12)\n at Function.Module._load (module.js:497:3)\n at Module.require (module.js:596:17)\n at require (internal/module.js:11:18)\n at Object.<anonymous> (server.js:11:13)\n at Module._compile (module.js:652:30)' },
level: '\u001b[31merror\u001b[39m',
[Symbol(level)]: 'error',
[Symbol(message)]: '{"message":{},"level":"error"}' }
** Winston Output: **
error: [object Object]
Где error: [object Object]
- именно то, что я ожидал
Однако, если я протестирую это с помощью этого блока кода:
Тест B
const logger = require('winston');
try {
throw(new Error('This causes error: undefined'));
} catch (err) {
logger.error(err);
}
Если new Error()
действительно содержит значение сообщения, я получаю следующий вывод:
Выход B
** Info Object: **
{ level: '\u001b[31merror\u001b[39m',
[Symbol(level)]: 'error',
[Symbol(message)]: '{"level":"error"}' }
** Winston Output: **
error: undefined
Как видите, я получаю те же error: undefined
что и @sandrocsimas . Я ожидал получить error: [object Object]
Обратите внимание, если я попробую этот блок кода:
Тест C
const logger = require('winston');
try {
throw(new Error('This should work'));
} catch (err) {
logger.log({level: 'error', message: err});
}
Если я использую logger.log
вместо logger.error
я получаю тот же результат, что и результат A выше.
У меня та же проблема. Я новичок в Уинстоне. Я пробовал решение @indexzero, но не работал. У тебя есть какое-нибудь решение?
@ nvtuan305 , вы пробовали именно решение logger.log({level: ____, message: err});
Он не будет работать, если вы используете logger.info
, logger.error
или любой другой вариант logger.<level>
. Я почти уверен, что это ошибка, указанная выше, и ее следует исправить в более позднем выпуске.
Я что-то упускаю, или это полная головная боль (или даже невозможность?), Чтобы получить тот же результат, который легко получить из console.log / error / warn?
try {
// ...
throw new Error('foo');
} catch (e) {
console.error('Caught error:', e); // convenient, informative
logger.error('Caught error:', e); // nope, the second parameter is something else (couldn't find docs)
logger.error(`Caught error: ${e}`); // stack lost
logger.error(`Caught error: ${JSON.stringify(e)}`); // Caught error: {}
}
Каков эквивалентный код Winston, чтобы получить тот же результат, что и
console.error('Caught error:', error);
?
А где документация по параметрам, принимаемым вспомогательными методами объекта логгера?
@dandv
logger.error('Caught error:', e);
Это не работает, потому что, в отличие от console.log()
, logger.<level>(message)
Winston принимает только один параметр с именем message. Этот параметр сообщения является либо объектом, либо строкой (кто-нибудь поправит меня, если я ошибаюсь, но это мое понимание).
Обратите внимание, что вы также можете использовать logger.log({level: <level>, message: <message>})
. Чтобы узнать больше об этих двух функциях, я бы порекомендовал прочитать эту часть документации: Winston Docs on Log Levels . Обязательно ознакомьтесь с разделом Использование уровней ведения журнала.
logger.error(`Caught error: ${e}`);
Я не могу однозначно сказать, почему это не выводит стек, но я знаю, что это не проблема Winston. Если вы попробуете console.log(`Caught error: ${e}`)
он также не будет включать стек. Я мало работал с шаблонными литералами, поэтому либо шаблонные литералы не работают с объектами, либо javascript console.log распознает объект как объект ошибки и, таким образом, выводит только свойство сообщения. Это мое лучшее предположение.
logger.error(`Caught error: ${JSON.stringify(e)}`)
Это помогает понять суть этой ветки ошибок. Сначала вы должны понять некоторые технические подробности о javascript. Обратите внимание, что если вы попробуете console.log(`Caught error: ${JSON.stringify(e)}`)
вы получите тот же результат Caught error: {}
. Как пояснил @indexzero :
Свойства
message
иstack
вError
не перечисляются, что приводит к тому, чтоJSON.stringify
выводит то, чего никто не ожидает.
По сути, поскольку свойства message
и stack
не перечислимые, JSON.stringify
пропускает эти свойства, что и приводит к пустому объекту {}
. Чтобы лучше понять перечислимость, я рекомендую прочитать это перечисление и владение свойствами .
К счастью, благодаря способу разработки Winston 3.0 (поддержка команды Winston) у нас есть обходной путь, который дал @indexzero . Я помогу это объяснить. Сначала вы создаете эту функцию:
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
Из объектов docs info.level
и info.message
. Это свойство info.message
ЯВЛЯЕТСЯ объектом ошибки, если это все, что вы передали. Итак, мы создаем новый объект, где message.stack
и message.message
(Думайте об этом как Error.stack
и Error.message
) теперь можно перечислить, и мы включаем любые другие свойства, которые также могут быть прикреплены к этому объекту ошибки.
Затем вы создадите этот регистратор, который использует указанную выше функцию enumerateErrorFormat()
:
const logger = createLogger({
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new transports.Console()
]
});
Это возьмет все, что вы передадите message
, и проверит, является ли это объектом ошибки. Если это так, это решит проблему с перечислением. Затем он передает сообщение в format.json
который преобразует любой объект в строку (ошибка или нет). Если это не объект, то это строка, и format.json
Effectivley ничего не делает, и вы дома бесплатно!
Тем не менее, было бы неплохо, если бы нам не нужно было создавать этот enumerateErrorFormat
поскольку объекты ошибок обычно регистрируются. Насколько я понимаю, команда Winston работает над исправлением, которое будет выпущено в более поздней версии.
Несколько заключительных примечаний. Это работает, только если вы используете logger.log({level: <level>, message: <message>})
где сообщение - это объект ошибки. Пример:
try {
throw(new Error('This should work'));
} catch (err) {
logger.log({level: 'error', message: err});
}
В Winston есть еще одна ошибка, из-за которой этот код не работает, как я объяснил в другом посте выше:
try {
throw(new Error('This will not work'));
} catch (err) {
logger.error(err);
}
По какой-то причине свойство info.message
не определено, когда мы используем logger.error(err)
. Надеюсь, @indexzero сможет понять это.
@ SamuelMaddox17 @indexzero Спасибо! Я пробовал использовать logger.log({level: 'error', message: err});
и он работает
Можно ли исправить ошибку logger.error и т. Д.?
Использование logger.log
громоздко и многословно, тем более что с помощью logger.error
вы можете легко добавить несколько аргументов.
Привет всем, я разбираюсь в этом. @indexzero : по-прежнему считаете, что лучше всего добавить функциональность enumerateErrorFormat
в средство форматирования json
по умолчанию? Нужно ли нам отдельно беспокоиться о том, является ли meta
Error
не просто object
(я предполагаю, что люди будут жаловаться, если мы также не рассмотрим этот случай?) ? Кроме того, я использую master
, но похоже, что logger.error
у меня работает с решением от @indexzero / @ SamuelMaddox17 выше:
const winston = require('winston');
const format = winston.format;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
const logger = winston.createLogger({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new winston.transports.Console(),
],
});
logger.error(new Error('whatever'));
После дальнейшего исследования выяснилось, что проблема logger.error
я объяснил выше, возникает только при использовании регистратора по умолчанию. @DABH , я попробовал ваш код, и он у меня работает, но когда я переключаю его на регистратор по умолчанию, он не работает:
const winston = require('winston');
const format = winston.format;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
winston.configure({
transports: [
new winston.transports.Console({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
})
]
});
winston.error(new Error('whatever'));
Во-вторых, я согласен с тем, что enumerateErrorFormat
следует добавить в формат json; и вы, вероятно, правы и насчет meta
.
Наконец, я хотел бы отметить, что пример кода, приведенный @DABH, заставляет стек не "печатать красиво", если хотите; по крайней мере, на моей машине под управлением macOS High Sierra. Для меня это выглядит так:
{"message":"whatever","stack":"Error: whatever\n at Object.<anonymous> (/Users/samuelmaddox/Desktop/winston-test/index.js:33:14)\n at Module._compile (internal/modules/cjs/loader.js:689:30)\n at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)\n at Module.load (internal/modules/cjs/loader.js:599:32)\n at tryModuleLoad (internal/modules/cjs/loader.js:538:12)\n at Function.Module._load (internal/modules/cjs/loader.js:530:3)\n at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)\n at startup (internal/bootstrap/node.js:266:19)\n at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)","level":"error"}
Как видите, при выводе ошибки с помощью функции JSON символы новой строки \n
не создают фактических новых строк. Это ожидаемое поведение при взятии объекта и его преобразовании в JSON, но, вероятно, это не то поведение, которое мы действительно хотели бы от регистратора, по крайней мере, при входе в консоль.
Спасибо, что заглянули в этот @DABH.
К вашему сведению, это то, к чему я добрался, немного поиграв с этим:
import winston from 'winston';
const format = winston.format;
const printNice = format.printf(info => {
const {level, message} = info;
return `Logging Level: ${level} - Logging Message: ${message}`;
});
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: `${info.message.message}\n============\n${info.message.stack}`
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: `${info.message}\n============\n${info.stack}`
}, info);
}
return info;
});
const logger = winston.createLogger({
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new winston.transports.Console({
format: format.combine(
format.colorize(),
printNice,
),
})
]
});
export default logger;
Проблема вызвана этой ошибкой: https://github.com/winstonjs/winston-transport/issues/31
Мы определенно использовали эту форму в winston2.x без проблем. winston.err('some message', err);
вместе с winston.error(err)
enumerateErrorFormat
исправляет winston.error(err)
но не вариант использования с ошибкой в качестве второго параметра.
@ SamuelMaddox17
logger.log ({уровень: ____, сообщение: ошибка});
это работает спасибо
Хорошо, я кое-что обнаружил. Мой комментарий от 3 сентября неверен. Это не проблема с регистратором по умолчанию. Это проблема, когда вы определяете level
и / или format
. @DABH вот ваш старый код:
const winston = require('winston');
const format = winston.format;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
const logger = winston.createLogger({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new winston.transports.Console(),
],
});
logger.error(new Error('whatever'));
Если вы удалите это:
const logger = winston.createLogger({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new winston.transports.Console(),
],
});
И замените это на это:
const logger = winston.createLogger({
transports: [
new winston.transports.Console({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
}),
],
});
Затем появляется проблема info.message === undefined
. Я считаю, что можно указать уровень и формат для каждого транспорта; и я почти уверен, что это было разрешено в Winston 2.0.
Вот ваш образец кода с моим изменением кода, чтобы вы могли легко запустить и протестировать:
const winston = require('winston');
const format = winston.format;
const enumerateErrorFormat = format(info => {
if (info.message instanceof Error) {
info.message = Object.assign({
message: info.message.message,
stack: info.message.stack
}, info.message);
}
if (info instanceof Error) {
return Object.assign({
message: info.message,
stack: info.stack
}, info);
}
return info;
});
const logger = winston.createLogger({
transports: [
new winston.transports.Console({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
}),
],
});
logger.error(new Error('whatever'));
Надеюсь, это поможет разобраться в корне проблемы.
Я создал https://github.com/winstonjs/winston/pull/1527
Это охватывает все варианты. Однако некоторые тесты не проходят, поэтому я пока закрыл его. Ожидаются сбои с учетом исправления, но я не верю, что могу сделать призыв изменить / удалить тесты.
Неудачная сборка находится здесь https://travis-ci.org/winstonjs/winston/jobs/453012141, и это очевидно, почему тесты теперь терпят неудачу, когда вы читаете тестовый код:
https://github.com/winstonjs/winston/blob/c42ab7fdc51b88db180a7dd90c52ce04ddd4e054/test/logger.test.js#L668
Мысли?
Я думаю проблема в этой строчке
const info = (msg && !(msg instanceof Error)
&& msg.message && msg) || {
сообщение: msg
};
добавление проверки instanceof Error, похоже, решает проблему, как
Для тех, кто все еще имеет дело с этим, это средство форматирования обходного пути, которое мне удалось придумать (фрагмент моего модуля logger.js):
const { format, transports, createLogger } = require("winston");
const { combine, timestamp, colorize, printf } = format;
function devFormat() {
const formatMessage = info => `${info.level}: ${info.timestamp} ${info.message}`;
const formatError = info => `${info.level}: ${info.timestamp}\n\n${info.stack}\n`;
const format = info => info instanceof Error ? formatError(info) : formatMessage(info);
return combine(timestamp(), printf(format));
}
По какой-то причине logger.error(new Error("hello"))
работает только в том случае, если вы определяете средство форматирования глобально в winston.createLogger
🤔, а затем получаете объект Error в info
в средстве форматирования.
Если вы определяете средство форматирования для каждого транспорта, вам нужно использовать logger.log({level: "error", message: new Error("FAILED")})
и обрабатывать объект Error через info.message
вместо info
для доступа к объекту Error.
Я предполагаю, что есть ошибка при установке поля формата в опциях транспорта?
Это всего лишь мои 2 цента, и то, что у меня сработало, я новичок в Winston и не опытен в JavaScript, так что не цитируйте меня ни в чем.
Мой подход был попыткой устранить основную причину. Но особой поддержки со стороны владельцев репо он не получает ...
Да, я это понимаю. Я буквально потратил много времени на выяснение этого, потому что я новичок в Уинстоне и подумал, что, возможно, я использую его неправильно или еще недостаточно хорошо понял концепции, лежащие в основе этого.
Но, к счастью, я наткнулся на несколько тем (включая эту), которые показали мне обратное. Надеюсь, они исправят это, так что мне не придется продолжать использовать обходной путь.
Это может быть вызвано wintson-transport
, проблему см. Https://github.com/winstonjs/winston-transport/issues/31 и https://github.com/winstonjs/winston-transport/pull/ 34 для PR.
Прямая регистрация объектов ошибок всегда вызывает беспорядок из-за их неперечислимых свойств. Лично я считаю это плохой практикой, но достаточное количество людей в сообществе непреклонно относятся к этому как к требованию, которое мы должны поддерживать.
Рассмотрение принятия https://github.com/winstonjs/logform/pull/59 в качестве формата для поддержки подобного поведения. С другой стороны, он инкапсулирует все крайние случаи, которые так часто встречаются при обработке ошибок как сообщений журнала. С другой стороны, это был бы еще один формат, на который людям нужно было бы согласиться (аналогично .splat()
).
@indexzero Я склонен согласиться, но прямое ведение журнала ошибок может быть полезно в сочетании с настраиваемым форматом ведения журнала / printf, если есть необходимость отображать несколько типов Error
разному, и я не помню, чтобы Winston 2.x пытался бороться с этой практикой, поскольку это было разрешено нестандартно.
Таким образом, предлагаемое решение для enumerateErrorFormat работает, но не поддерживает формат logger.error('some message', err)
. Потому что ни info.message
ни info
являются instanceof Error
. Также хочу отметить еще одну проблему с этим решением. В настоящее время я регистрирую ошибку, возвращаемую из superagent
try {
const response = await request
.get('https://some/endpoint')
.set('Authorization', bearerToken);
logger.info('successfully received response');
return response.body;
} catch (e) {
logger.error('An error was caught while getting programs');
logger.error(e); // <<< THE ERROR LOG
}
Если мы просто используем Object.assign, тогда охладим стек и сообщение будет установлено! НО, любая другая информация, которая была частью ошибки, также будет записана. Это может быть очень опасно в случаях, когда ошибки содержат конфиденциальные данные, такие как Authorization Headers
(которые в этом случае включаются как часть объекта ошибки).
Но тогда можно сказать. Это не вина Winston, и не вина Winston, что суперагент добавляет эти данные к ошибке. Я СОГЛАСЕН! ОДНАКО, поскольку все хранится в объекте info
становится очень сложно сохранить старую информацию и не переопределить остальную.
Было бы неплохо, если бы при использовании logger.error. Он предположил, что второй параметр был ошибкой и поместил его в объект info
как info.error
а затем, если ведение журнала другим способом, интерфейс будет { level: "error", error: YOUR ERROR OBJECT}
Я действительно здесь просто плевался, но новый интерфейс определенно немного разочаровал (все в информации).
Чтобы уточнить, о чем я говорил, предположим, что вы logger.error( e )
где e имеет ошибку типа.
Затем в вашем коде вы настроили Winston следующим образом:
winston.configure({
format: combine(
timestamp(),
enumerateErrorFormat(),
...
),
});
метка времени помещается в объект ошибки 😱. Это действительно имеет смысл? Подумайте об этом ... объект ошибки, который вы отправили, динамически получает новую опору ... метку времени.
Я думаю, что лучшим решением этой проблемы будет поддержка следующего синтаксиса
logger.error('An error occurred when doing something important', { error: e } );
а затем внутри вы можете создать средство форматирования ошибок, которое ищет поле ошибки!
Обновите это, ребята:
errors
в logform
с Winston: https://github.com/winstonjs/winston/compare/gh-1338Надеюсь, что это зашито и отправлено в ближайшие пару дней. Это предпоследний выпуск в нашем трекере [email protected]
Привет, ребята - посетите https://github.com/winstonjs/winston/pull/1562. Это был последний пункт в нашем контрольном списке выпуска 3.2.0
поэтому, как только PR будет зашит, мы сможем выпустить его.
Пока исправление не будет опубликовано, я использую следующий обходной путь:
logger.error = item => {
logger.log({ level: 'error', message: item instanceof Error ? item.stack : item });
};
Я использую последнюю версию Winston (3.2.1) и все еще получаю undefined
при передаче ошибки logger.error
У @ezze было отличное решение, но трассировка стека
logger.error = item => {
const message = item instanceof Error
? item.stack.replace('\n', '').replace(' ', ' - trace: ')
: item;
logger.log({ level: 'error', message });
};
с выходом <Error message> - trace: <stack trace>
Если есть более простой способ сделать это с помощью последней версии Winston, дайте мне знать @indexzero. Я новичок в библиотеке и следил за документами
Я только что увидел ссылку, которую вы разместили в PR. Означает ли это, что для передачи ошибки в logger.error
требуется строка сообщения, а затем ошибка?
try {
someThing();
} catch(error) {
logger.error(error); // what I would like to do
logger.error('special message', error); // what I believe is required?
}
@ the-vampiire В этой ветке обсуждались две проблемы. Первое - это то, что было сказано на оригинальном плакате, а второе - проблема, которую я поднял, и она совпадает с вашей. Я думаю, они исправили только исходную проблему с плакатами. Я собирался проверить дальше, чтобы убедиться, а затем открыть новую проблему, если это так. К сожалению, у меня не было времени нырять глубже. Между тем, если вы используете logger.log({level: 'error', message: err});
где err
- это объект ошибки, он будет работать.
У вас все еще есть эта проблема, потеряли кучу времени, чтобы понять это, решение от @ the-vampiire работает хорошо.
Почему этот билет закрыт?
Переопределение logger.error пока является лучшим решением, поскольку оно не добавляет свойство отметки времени к объекту Error, который передается как единственный аргумент функции error (). Большинство людей, вероятно, ожидают, что объекты Error неизменяемы. Если вы также не переопределите logger.info и любой другой метод, связанный с уровнем, будет сюрпризом, когда что-то работает не так, как ожидалось. Опять же, если вы не хотите, чтобы ваш объект был изменен, независимо от его типа, не отправляйте его напрямую методу регистратора Winston.
Функция поддерживается с [email protected]
Пример использования:
const winston = require('winston');
const { transports, format } = winston;
const print = format.printf((info) => {
const log = `${info.level}: ${info.message}`;
return info.stack
? `${log}\n${info.stack}`
: log;
});
const logger = winston.createLogger({
level: 'debug',
format: format.combine(
format.errors({ stack: true }),
print,
),
transports: [new transports.Console()],
});
const error = new Error('Ooops');
logger.error(error);
logger.error('An error occurred:', error);
cc @ HRK44 @ вампир
Я тоже все еще сталкиваюсь с проблемой.
Когда я вызываю ошибку типа logger.error(error);
я получаю только undefined
.
Только если я назову это как logger.error('Something went wrong', error)
я получаю полную ошибку и могу ее проанализировать.
Я тоже все еще сталкиваюсь с проблемой.
Когда я вызываю ошибку типаlogger.error(error);
я получаю толькоundefined
.
Только если я назову это какlogger.error('Something went wrong', error)
я получаю полную ошибку и могу ее проанализировать.
Вы это добавили?
format.errors({ stack: true })
Да, все та же проблема. Я пытаюсь передать это вкратце.
@ OBrown92 Сегодня я столкнулся с той же проблемой. Я могу подтвердить, что это работает, если format.errors({ stack: true })
применяется к регистратору, а не к транспорту. В этом случае можно использовать как logger.error(error);
и logger.error('Something went wrong', error)
. Однако возникает проблема, когда я пытаюсь применить format.errors({ stack: true })
к выбранному транспорту. В этом случае я получаю undefined
за logger.error(error);
, но logger.error('Something went wrong', error)
работает правильно.
Я не уверен, ожидаемое это поведение или это ошибка, но я потратил много времени, чтобы найти причину, поэтому, пожалуйста, исправьте ее или упомяните об этом где-нибудь в своей документации. Это было бы действительно полезно.
В любом случае, я очень благодарен вам за работу над этим замечательным проектом.
Я столкнулся с той же проблемой, поэтому написал этот пакет utils-deep-clone . Проверить это.
format.errors is not a function
... ну это сюрприз.
@holmberd
Вы импортировали форматы из пакета winston?
Пример использования:
const { format } = require('winston')
Или же
const winston = require('winston');
const { format } = winston;
@aybhalala yepp, хотя не имеет значения, что стек ошибок передается в printf
без него.
Обновление: поскольку с этим все еще есть проблемы, я некоторое время делал следующее, и он отлично работал
// Grab the default winston logger
const winston = require('winston');
const { format } = winston;
const { combine, timestamp } = format;
// Custom format function that will look for an error object and log out the stack and if
// its not production, the error itself
const myFormat = format.printf((info) => {
const { timestamp: tmsmp, level, message, error, ...rest } = info;
let log = `${tmsmp} - ${level}:\t${message}`;
// Only if there is an error
if ( error ) {
if ( error.stack) log = `${log}\n${error.stack}`;
if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
}
// Check if rest is object
if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
log = `${log}\n${JSON.stringify(rest, null, 2)}`;
}
return log;
});
winston.configure({
transports: [
new winston.transports.Console({
level: 'debug',
timestamp: true,
handleExceptions: true
}),
];
format: combine(
trace(),
timestamp(),
myFormat
),
});
// Finally you log like this
logger.error('An error occurred!!!', { error } );
^^ Это ожидаемое использование. Поскольку простые смертные никогда в этом не догадаются, это следует задокументировать.
Поскольку простые смертные никогда в этом не догадаются, это следует задокументировать.
😂 +1 этому товарищу
Я использую winston со сторонним транспортом ( @google-cloud/logging-winston
), поэтому у меня немного меньше контроля над синтаксисом. К тому же я нахожу это более интуитивным:
const error = new Error('something bad happened');
logger.error('was doing this and', error);
При входе в консоль я присоединяю стек к сообщению. Но результат примерно такой:
ERROR was doing this andsomething bad happened Error: something bad happened <rest of the stack.>
Поскольку Winston объединяет meta.message
с исходным сообщением, в стеке также печатается странное сообщение andsomething
и дубликат сообщения. Это описано в №1660.
Похоже, что # 1664 пытается это исправить. Тем временем я написал средство форматирования, которое «отменяет» это объединение: https://github.com/winstonjs/winston/issues/1660#issuecomment -512226578
@dandv
logger.error('Caught error:', e);
Это не работает, потому что, в отличие от
console.log()
,logger.<level>(message)
Winston принимает только один параметр с именем message. Этот параметр сообщения является либо объектом, либо строкой (кто-нибудь поправит меня, если я ошибаюсь, но это мое понимание).Обратите внимание, что вы также можете использовать
logger.log({level: <level>, message: <message>})
. Чтобы узнать больше об этих двух функциях, я бы порекомендовал прочитать эту часть документации: Winston Docs on Log Levels . Обязательно ознакомьтесь с разделом Использование уровней ведения журнала.logger.error(`Caught error: ${e}`);
Я не могу однозначно сказать, почему это не выводит стек, но я знаю, что это не проблема Winston. Если вы попробуете
console.log(`Caught error: ${e}`)
он также не будет включать стек. Я мало работал с шаблонными литералами, поэтому либо шаблонные литералы не работают с объектами, либо javascript console.log распознает объект как объект ошибки и, таким образом, выводит только свойство сообщения. Это мое лучшее предположение.logger.error(`Caught error: ${JSON.stringify(e)}`)
Это помогает понять суть этой ветки ошибок. Сначала вы должны понять некоторые технические подробности о javascript. Обратите внимание, что если вы попробуете
console.log(`Caught error: ${JSON.stringify(e)}`)
вы получите тот же результатCaught error: {}
. Как пояснил @indexzero :Свойства
message
иstack
вError
не перечисляются, что приводит к тому, чтоJSON.stringify
выводит то, чего никто не ожидает.По сути, поскольку свойства
message
иstack
не перечислимые,JSON.stringify
пропускает эти свойства, что и приводит к пустому объекту{}
. Чтобы лучше понять перечислимость, я рекомендую прочитать это перечисление и владение свойствами .К счастью, благодаря способу разработки Winston 3.0 (поддержка команды Winston) у нас есть обходной путь, который дал @indexzero . Я помогу это объяснить. Сначала вы создаете эту функцию:
const enumerateErrorFormat = format(info => { if (info.message instanceof Error) { info.message = Object.assign({ message: info.message.message, stack: info.message.stack }, info.message); } if (info instanceof Error) { return Object.assign({ message: info.message, stack: info.stack }, info); } return info; });
Из объектов docs
info.level
иinfo.message
. Этоinfo.message
свойство является объектом ошибки , если это все , что вы прошли в. Таким образом , мы создаем новый объект , гдеmessage.stack
иmessage.message
(Думайте об этом какError.stack
иError.message
) теперь можно перечислить, и мы включаем любые другие свойства, которые также могут быть прикреплены к этому объекту ошибки.Затем вы создадите этот регистратор, который использует указанную выше функцию
enumerateErrorFormat()
:const logger = createLogger({ format: format.combine( enumerateErrorFormat(), format.json() ), transports: [ new transports.Console() ] });
Это займет все
message
вамиformat.json
который преобразует любой объект в строку (ошибка или нет). Если это не объект, то это строка, иformat.json
Effectivley ничего не делает, и вы дома бесплатно!Тем не менее, было бы неплохо, если бы нам не нужно было создавать этот
enumerateErrorFormat
поскольку объекты ошибок обычно регистрируются. Насколько я понимаю, команда Winston работает над исправлением, которое будет выпущено в более поздней версии.Несколько заключительных примечаний. Это работает, только если вы используете
logger.log({level: <level>, message: <message>})
где сообщение - это объект ошибки. Пример:try { throw(new Error('This should work')); } catch (err) { logger.log({level: 'error', message: err}); }
В Winston есть еще одна ошибка, из-за которой этот код не работает, как я объяснил в другом посте выше:
try { throw(new Error('This will not work')); } catch (err) { logger.error(err); }
По какой-то причине свойство
info.message
не определено, когда мы используемlogger.error(err)
. Надеюсь, @indexzero сможет понять это.
Очень хорошее объяснение, я просто хочу добавить это с ошибкой logger.error(
Caught: $ {e} );
вы теряете стек из-за того, как строковый литерал работает в javascript, `${e}`
в точности совпадает с e.toString()
, поэтому печать только сообщения об ошибке является ожидаемым поведением.
Это все еще проблема? У меня все еще проблемы с этим:
const { createLogger, format, transports } = require('winston')
const { combine } = format
const errorFormatter = format((info) => {
console.log(info)
return info
})
const consoleTransport = new transports.Console({
format: combine(errorFormatter()),
})
const logger = createLogger({
transports: [
consoleTransport,
],
})
try {
throw new Error('Error message')
} catch(err) {
logger.error(err) // info doesnt have the error object
logger.error('', err) // info have the error object
}
Это все еще проблема? У меня все еще проблемы с этим:
const { createLogger, format, transports } = require('winston') const { combine } = format const errorFormatter = format((info) => { console.log(info) return info }) const consoleTransport = new transports.Console({ format: combine(errorFormatter()), }) const logger = createLogger({ transports: [ consoleTransport, ], }) try { throw new Error('Error message') } catch(err) { logger.error(err) // info doesnt have the error object logger.error('', err) // info have the error object }
такая же проблема здесь ...
посмотрев исходный код, я могу увидеть, какие параметры он принимает:
interface LeveledLogMethod {
(сообщение: строка, обратный вызов: LogCallback): Регистратор;
(сообщение: строка, мета: любой, обратный вызов: LogCallback): Регистратор;
(сообщение: строка, ... мета: любой []): Регистратор;
(infoObject: object): Регистратор;
}
поэтому, если вы передадите объект ошибки в качестве первого параметра, он будет принимать только сообщение об ошибке, потому что он понимает только строки, и если вы передадите ошибку во втором параметре, вы можете получить доступ к трассировке стека в info.stack
кстати, я не мог найти этого нигде в документации
Я нашел два решения, первое - использовать format.errors
, указанное в форме журнала в родительском регистраторе, затем создать messageFormatter с помощью format.printf
и условно добавить поле stack
извлеченное из info
( format.errors({ stack: true})
добавит это).
Другое решение, которое я предпочел, - это взломать логгеры уровня Winston:
const addArgs = format((info) => {
const args: any[] = info[Symbol.for('splat')]
info.args = args ? [...args] : []
return info
})
const messageFormatter = format.printf(info => {
const { timestamp: timeString = '', message, args = [] } = info
const formattedMsgWithArgs = util.formatWithOptions({ colors: true }, message, ...args)
const msg = `${timeString} - ${info.level}: ${formattedMsgWithArgs}`
return msg
})
const logger = createLogger({
format: format.combine(
addArgs(),
format.timestamp({ format: 'HH:mm:ss.SSS' })
),
transports: [
new transports.Console({
format: format.combine(format.colorize(), messageFormatter),
}),
],
})
const levels = ['debug', 'info', 'error']
levels.forEach((level) => {
logger[level] = (msg: any, ...remains: any) => {
if(typeof msg != "string") {
return logger.log(level, '', msg, ...remains)
}
logger.log(level, msg, ...remains)
}
})
Кажется, таким образом я могу получить журнал ошибок, похожий на console.log
Я могу проверить, что комментарий @tiagonapoli о том, как format.errors
должен быть в _parent_ logger, точен. Когда я делаю что-то вроде этого:
winston.loggers.add("default");
const log = winston.loggers.get("default");
/* get a `transportOptions` object and a `transportType` */
transportOptions.format = logform.format.combine(
logform.format.errors({ stack: true }),
logform.format.timestamp(),
logform.format.printf(myFormatter)
);
log.add(new winston.transports[transportType](transportOptions);
Обработка объекта Error
происходит так, как если бы он был строкой. Однако, если я сделаю что-то вроде этого:
winston.loggers.add("default");
const log = winston.loggers.get("default");
log.format = logform.format.errors({ stack: true });
/* get a `transportOptions` object and a `transportType` */
transportOptions.format = logform.format.combine(
logform.format.timestamp(),
logform.format.printf(myFormatter)
);
log.add(new winston.transports[transportType](transportOptions);
Обработка объекта Error
работает правильно.
Мне кажется, что ошибка здесь в том, что никакой разницы в поведении быть не должно.
Значит, по прошествии 1 года это все еще не исправлено? Нужно ли мне взламывать код Winston Logger, чтобы он заработал?
Да, это доставило мне достаточно головной боли, и Уинстон начал казаться намного больше проблем, чем это того стоило для моего относительно простого варианта использования ... В итоге я просто написал свой собственный небольшой класс регистратора, и я бы рекомендовал другим сделать то же самое, если только Уинстон предоставляет то, что вам ДЕЙСТВИТЕЛЬНО нужно.
Ребята, правда? это расстраивает ...
Я не коммиттер, но, вероятно, правильно скажу, что это не будет «исправлено», потому что оно не сломано. Winston стоит использовать. Вам просто нужно настроить его - лучший совет для меня выше на https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691
Еще нет ?
Обновление: поскольку с этим все еще есть проблемы, я некоторое время делал следующее, и он отлично работал
// Grab the default winston logger const winston = require('winston'); const { format } = winston; const { combine, timestamp } = format; // Custom format function that will look for an error object and log out the stack and if // its not production, the error itself const myFormat = format.printf((info) => { const { timestamp: tmsmp, level, message, error, ...rest } = info; let log = `${tmsmp} - ${level}:\t${message}`; // Only if there is an error if ( error ) { if ( error.stack) log = `${log}\n${error.stack}`; if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`; } // Check if rest is object if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) { log = `${log}\n${JSON.stringify(rest, null, 2)}`; } return log; }); winston.configure({ transports: [ new winston.transports.Console({ level: 'debug', timestamp: true, handleExceptions: true }), ]; format: combine( trace(), timestamp(), myFormat ), }); // Finally you log like this logger.error('An error occurred!!!', { error } );
откуда идет след?
Нет, правда, это недопустимо для библиотеки журналов.
Сопровождающий должен просто поместить хорошо выделенный пример в документы, где показано, как регистрировать ошибку, даже определяя собственный формат printf и формат, отличный от json, и где вы можете регистрировать ошибку с помощью чего-то вроде logger.error ("что-то", err) и регистратора .error (ошибка)
Уинстон казался отличным, но эта проблема невероятно неприемлема.
Это мой взгляд на то, как регистрировать ошибки с помощью Winston. Это не уникально, многие взгляды выше имеют рабочие решения, основанные на тех же концепциях.
Задний план
Я использую @jsdevtools/ono
чтобы обернуть произвольные типы объектов в пользовательские ошибки, но, несмотря на это, это решение по-прежнему отлично работает с ошибками собственных узлов (например, с ошибками fs eperm) и пользовательскими классами ошибок.
Объяснение
В основном я полагаюсь на format.errors({stack:true})
и format.metadata()
. Как упоминалось https://github.com/winstonjs/winston/issues/1338#issuecomment -532327143, это должно быть в родительском модуле форматирования.
Метаданные помогают сдвинуть все настраиваемые свойства объекта ошибки на info.metadata
.
Я хотел напечатать 3 типа информации: сообщение об ошибке, трассировку стека и свойства объекта ошибки. Сообщение об ошибке уже было открытым текстом. Я красиво распечатал стек info.metadata.stack
с помощью модуля pretty-error
. Что касается свойств объекта ошибки, я не хотел, чтобы трассировка стека снова появлялась, поэтому я клонировал объект и удалил свойство трассировки стека. Затем я красиво распечатал объект ошибки, используя fast-safe-stringify
, который является тем же модулем строкового преобразования, на который полагается Winston.
const lodash = require("lodash");
const path = require("path");
const winston = require("winston");
const { default: stringify } = require("fast-safe-stringify");
const logDir = "D:/temp/logs";
// pretty formatting
const PrettyError = require("pretty-error");
const pe = new PrettyError();
pe.withoutColors()
.appendStyle({
'pretty-error > trace':
{
display: 'inline'
},
'pretty-error > trace > item':
{
marginBottom: 0,
bullet: '"*"'
}
})
// @ts-ignore
.alias(/.*[\\\/]CelebrityQuery/i, "<project>")
.alias(/\[CelebrityQuery\][\\\/]?/i, "")
.skip(/** <strong i="23">@type</strong> {(_:any) => boolean} */ (traceline => {
if (traceline && traceline.dir) {
return traceline.dir.toString().startsWith("internal");
}
return false;
}))
.skipNodeFiles();
const consoleFormat = winston.format.combine(
winston.format.colorize(),
winston.format.timestamp({
format: 'DD MMM HH:mm:ss'
}),
winston.format.printf(info => {
if (!lodash.isEmpty(info.metadata) && info.metadata.hasOwnProperty("stack")) {
let dup = lodash.clone(info.metadata);
delete dup.stack;
const errBody = stringify(dup, undefined, 4);
const stack = pe.render({ stack: info.metadata.stack });
return `${info.timestamp} ${info.level} ${info.message}${errBody}\n${stack}`;
} else if (lodash.isString(info.message)) {
return `${info.timestamp} ${info.level} ${info.message}`;
} else {
return `${info.timestamp} ${info.level} ${stringify(info.message, undefined, 4)}`;
}
})
);
const logFormat = winston.format.combine(winston.format.timestamp(), winston.format.json());
return winston.createLogger({
level: 'debug',
format: winston.format.combine(
winston.format.errors({ stack: true }),
winston.format.metadata()
),
transports: [
new winston.transports.Console({
format: consoleFormat,
level: 'info',
}),
new winston.transports.File({
filename: path.join(logDir, "stdout.json"),
format: logFormat,
level: 'debug',
maxsize: 1000000,
tailable: true
})
]
});
PS: Я также считаю, что решение, упомянутое в https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691, является хорошей альтернативой. Т.е. используя logger.warn("Oh no", { error: new Error() })
, а затем ссылку на info.error
в пользовательском средстве форматирования.
@tiagonapoli ваше решение об использовании format.errors
в родительском регистраторе сработало для меня:
const logger = createLogger({
transports: loggerTransports,
});
logger.format = format.errors({ stack: true });
Настраивать этот регистратор довольно болезненно ... Неужели он не может вести себя как console.log
из коробки?
@ will093 и здесь. Я снова столкнулся с этой проблемой и не понимаю, почему мой console.log
красивый и чистый, а формат Winston - дерьмо.
Мой 2 ¢
// Enable console logging when not in production
if (process.env.NODE_ENV !== "production") {
logger.add(new transports.Console({
format: format.combine(
format.colorize(),
format.simple(),
format.printf(info => {
const { level, ...rest } = info;
let rtn = "";
// rtn += info.timestamp;
rtn += "[" + info.level + "] ";
if (rest.stack) {
rtn += rest.message.replace(rest.stack.split("\n")[0].substr(7),"");
rtn += "\n";
rtn += "[" + level + "] ";
rtn += rest.stack.replace(/\n/g, `\n[${level}]\t`);
} else {
rtn += rest.message;
}
return rtn;
}),
),
}));
}
Пример для logger.error("Error during schema stitching", e);
Использование @tiagonapoli и @ will093 решения по добавлению его только к родительскому
const createLogger = () => {
const logFormatter = winston.format.printf(info => {
let { timestamp, level, code, stack, message } = info;
// print out http error code w/ a space if we have one
code = code ? ` ${code}` : '';
// print the stack if we have it, message otherwise.
message = stack || message;
return `${timestamp} ${level}${code}: ${message}`;
});
return winston.createLogger({
level: 'info',
// put the errors formatter in the parent for some reason, only needed there:
format: winston.format.errors({ stack: true }),
transports: new winston.transports.Console({
format: winston.format.combine(
winston.format.timestamp(),
logFormatter
),
});
};
работает со стеком при вызове с ошибкой типа: logger.error(error)
, работает со строкой при вызове типа logger.error('a regular message')
, в моих журналах выглядит так:
2020-09-23T20:05:30.30Z info: Feathers application started on http://localhost:3030
2020-09-23T20:05:35.40Z info: job queue - redis ready, registering queues...
2020-09-23T20:05:40.25Z error 401: NotAuthenticated: invalid authorization header
at new NotAuthenticated (/path/to/server/node_modules/@feathersjs/errors/lib/index.js:94:17)
at Object.<anonymous> (/path/to/server/src/hooks/authentication.js:123:456)
at /path/to/server/node_modules/@feathersjs/commons/lib/hooks.js:116:46
это не пытается решить проблему несовместимости Winston logger.error('message here', error)
с console.log
, которую, похоже , сложное решение
Кроме того, если вам нравятся журналы json, вы можете оставить здесь logFormatter
и использовать вместо него winston.format.json()
, который по-прежнему будет включать стек, но это некрасиво.
Обновление: поскольку с этим все еще есть проблемы, я некоторое время делал следующее, и он отлично работал
// Grab the default winston logger const winston = require('winston'); const { format } = winston; const { combine, timestamp } = format; // Custom format function that will look for an error object and log out the stack and if // its not production, the error itself const myFormat = format.printf((info) => { const { timestamp: tmsmp, level, message, error, ...rest } = info; let log = `${tmsmp} - ${level}:\t${message}`; // Only if there is an error if ( error ) { if ( error.stack) log = `${log}\n${error.stack}`; if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`; } // Check if rest is object if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) { log = `${log}\n${JSON.stringify(rest, null, 2)}`; } return log; }); winston.configure({ transports: [ new winston.transports.Console({ level: 'debug', timestamp: true, handleExceptions: true }), ]; format: combine( trace(), timestamp(), myFormat ), }); // Finally you log like this logger.error('An error occurred!!!', { error } );
где определение trace ()?
Обновление: поскольку с этим все еще есть проблемы, я некоторое время делал следующее, и он отлично работал
// Grab the default winston logger const winston = require('winston'); const { format } = winston; const { combine, timestamp } = format; // Custom format function that will look for an error object and log out the stack and if // its not production, the error itself const myFormat = format.printf((info) => { const { timestamp: tmsmp, level, message, error, ...rest } = info; let log = `${tmsmp} - ${level}:\t${message}`; // Only if there is an error if ( error ) { if ( error.stack) log = `${log}\n${error.stack}`; if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`; } // Check if rest is object if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) { log = `${log}\n${JSON.stringify(rest, null, 2)}`; } return log; }); winston.configure({ transports: [ new winston.transports.Console({ level: 'debug', timestamp: true, handleExceptions: true }), ]; format: combine( trace(), timestamp(), myFormat ), }); // Finally you log like this logger.error('An error occurred!!!', { error } );
откуда идет след?
есть ответ по этому поводу?
Самый полезный комментарий
Нет, правда, это недопустимо для библиотеки журналов.
Сопровождающий должен просто поместить хорошо выделенный пример в документы, где показано, как регистрировать ошибку, даже определяя собственный формат printf и формат, отличный от json, и где вы можете регистрировать ошибку с помощью чего-то вроде logger.error ("что-то", err) и регистратора .error (ошибка)
Уинстон казался отличным, но эта проблема невероятно неприемлема.