winston
versão? _node -v
saídas: _ v8.11.1Registrar um nó Error
object resulta em uma mensagem vazia:
Exemplo:
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});
Resultado resultante:
% node test.js
{"level":"error","message":{}}
Também:
logger.error(new Error('hello'))
Resulta em:
{"level":"error"}
Espero que a chave da mensagem tenha pelo menos a mensagem de erro incluída nela. Se eu tentar um formatador personalizado, info
também não contém o objeto de erro, então ele deve ser removido em algum lugar?
Deixe-me saber como posso ajudar - feliz em agitar um PR, mas ainda não sei como encontrar [email protected]
suficiente para encontrá-lo
Temos alguma cobertura de teste para isso, mas claramente precisamos de mais. O que está acontecendo nos bastidores:
Error
é passada ao longo da cadeia de tubos objectMode
streamLogger
é json
(veja: json
código de formato em logform
)message
e stack
em Error
não são enumeráveis, o que faz com que JSON.stringify
produza algo que ninguém espera.console.log(JSON.stringify(new Error('lol nothing here')));
// '{}'
De uma perspectiva de design, winston@3
introduziu formats
exatamente para esse tipo de problema para aumentar o desempenho. Falando em desempenho, curiosamente pino
faz algo interessante aqui . Talvez a solução seja implementar algo semelhante a asJson
no formato json
padrão.
Se alguém estiver procurando uma solução rápida, você pode incluir enumerateErrorFormat
no formato do seu logger por enquanto. Esperamos ter uma solução para isso antes de 3.0.0
próxima semana (ou logo depois em 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 , tentei seguir sua solução alternativa, mas não está funcionando. Você sabe por quê?
Formatador:
`` ` 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 ({
mensagem: info.message.message,
pilha: info.message.stack,
}, info.message);
}
if (info instanceof Error) {
return Object.assign ({
mensagem: info.message,
pilha: info.stack,
}, info);
}
informações de retorno;
});
const consoleLogger = winston.createLogger ({
nível,
formato: winston.format.timestamp (),
transportes: [
new winston.transports.Console ({
formato: winston.format.combine (
winston.format.colorize (),
enumerateErrorFormat (),
printFormat,
),
}),
],
});
Code:
javascript
tentar {
// Algum erro de lançamento de código
} catch (errar) {
logger.error (err);
}
Output:
28/06/2018T21: 17: 25.140Z - erro: indefinido
Info object:
javascript
{nível: '\ u001b [31merror \ u001b [39m', carimbo de data / hora: '2018-06-28T21: 17: 25.140Z', [Símbolo (nível)]: 'erro'}
`` ``
Onde está o atributo de mensagem no log de erros?
@sandrocsimas Percebi que você precisa fornecer a função enumerateErrorFormat para o formatador padrão do logger para fazê-la funcionar.
Formatador
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,
),
}),
],
});
Eu ainda não entendo porque
Acho que estou enfrentando o mesmo bug que @sandrocsimas.
Aqui está minha configuração de logger:
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
),
})
]
});
Se eu testar com este bloco de código:
Teste A
const logger = require('winston');
try {
throw(new Error());
} catch (err) {
logger.error(err);
}
onde new Error()
não contém um valor de mensagem, obtenho esta saída:
Produto 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]
Onde error: [object Object]
é exatamente o que eu esperava
No entanto, se eu testá-lo com este bloco de código:
Teste B
const logger = require('winston');
try {
throw(new Error('This causes error: undefined'));
} catch (err) {
logger.error(err);
}
Onde new Error()
contém um valor de mensagem, obtenho esta saída:
Produto B
** Info Object: **
{ level: '\u001b[31merror\u001b[39m',
[Symbol(level)]: 'error',
[Symbol(message)]: '{"level":"error"}' }
** Winston Output: **
error: undefined
Como você pode ver, recebo os mesmos error: undefined
que @sandrocsimas recebe. Esperava obter error: [object Object]
Observe, se eu tentar este bloco de código:
Teste C
const logger = require('winston');
try {
throw(new Error('This should work'));
} catch (err) {
logger.log({level: 'error', message: err});
}
Onde eu uso logger.log
vez de logger.error
, obtenho a mesma saída que a Saída A acima
Eu tenho o mesmo problema. Sou novo no winston. Tentei a solução @indexzero mas não funcionou. Você tem alguma solução?
@ nvtuan305 , você tentou a solução de @indexzero exatamente ou editou um pouco? Em caso afirmativo, você poderia fornecer um código de amostra? Seu código deve funcionar se você estiver usando logger.log({level: ____, message: err});
Não funcionará se você estiver fazendo logger.info
, logger.error
, ou qualquer outro sabor de logger.<level>
. Tenho quase certeza de que é um bug conforme especifiquei acima e deve ser corrigido em uma versão posterior.
Estou perdendo alguma coisa ou é uma completa dor de cabeça (ou mesmo impossível?) Obter a mesma saída que se obtém facilmente em 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: {}
}
Qual é o código winston equivalente para obter a mesma saída que
console.error('Caught error:', error);
?
E onde está a documentação para os parâmetros obtidos pelos métodos de conveniência no objeto logger?
@dandv
logger.error('Caught error:', e);
Isso não funciona porque, ao contrário de console.log()
, o logger.<level>(message)
do winston leva apenas um parâmetro chamado mensagem. Esse parâmetro de mensagem é um objeto ou uma string (alguém me corrige se eu estiver errado, mas esse é o meu entendimento).
Observe que você também pode usar logger.log({level: <level>, message: <message>})
. Para aprender mais sobre essas duas funções, eu recomendo a leitura desta parte da documentação: Winston Docs on Log Levels . Certifique-se de ler Usando níveis de registro
logger.error(`Caught error: ${e}`);
Não posso dizer definitivamente por que isso não gera a pilha, mas sei que isso não é um problema com o winston. Se você tentar console.log(`Caught error: ${e}`)
, também não incluirá a pilha. Não trabalhei muito com literais de modelo, portanto, os literais de modelo não funcionam bem com objetos ou o console.log do javascript reconhece o objeto como um objeto de erro e, portanto, apenas exibe a propriedade the message. Esse é meu melhor palpite.
logger.error(`Caught error: ${JSON.stringify(e)}`)
Este vai ao cerne do que é esse tópico de bug. Primeiro você deve entender alguns detalhes técnicos sobre javascript. Observe que se você tentar console.log(`Caught error: ${JSON.stringify(e)}`)
também obterá a mesma saída Caught error: {}
. Como @indexzero explicou:
message
estack
emError
não são enumeráveis, o que faz com queJSON.stringify
produza algo que ninguém espera.
Basicamente, porque message
e stack
propriedades não são enumeráveis, JSON.stringify
pula essas propriedades, que é como você termina com um objeto vazio {}
. Para entender melhor a enumerabilidade, recomendo a leitura deste Enumerabilidade e propriedade de propriedades
Felizmente, devido à forma como o winston 3.0 foi projetado (props para a equipe winston), temos uma solução alternativa para isso que o @indexzero ofereceu. Vou ajudar a explicar. Primeiro você cria esta função:
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;
});
Nos objetos Streams, objectMode e info do docs info.level
e info.message
. Essa propriedade info.message
É o objeto de erro se isso for tudo o que você passou. Portanto, criamos um novo objeto onde message.stack
e message.message
(Pense nisso como Error.stack
e Error.message
) agora são enumeráveis e incluímos todas as outras propriedades que também podem ser anexadas a esse objeto de erro.
Em seguida, você criará este registrador que usa a função enumerateErrorFormat()
acima:
const logger = createLogger({
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new transports.Console()
]
});
Isso pegará qualquer message
você passar e verificar se é um objeto de erro. Se for, ele corrigirá o problema de enumeração. Em seguida, ele passa uma mensagem para format.json
que irá string qualquer objeto (erro ou não). Se não for um objeto, é uma string e format.json
effectivley não faz nada e você está em casa livre!
Ainda assim, seria bom se não tivéssemos que criar aquele enumerateErrorFormat
uma vez que os objetos de erro são comumente registrados. Pelo que entendi, a equipe winston está trabalhando em uma correção que será lançada em uma versão posterior.
Algumas notas finais. Isso só funciona se você usar logger.log({level: <level>, message: <message>})
onde mensagem é o objeto de erro. Exemplo:
try {
throw(new Error('This should work'));
} catch (err) {
logger.log({level: 'error', message: err});
}
Há outro bug no winston em que este código não funciona, como expliquei em meu outro post acima:
try {
throw(new Error('This will not work'));
} catch (err) {
logger.error(err);
}
Por alguma razão, a propriedade info.message
é indefinida quando usamos logger.error(err)
. Esperançosamente @indexzero pode descobrir isso.
@ SamuelMaddox17 @indexzero Obrigado! Tentei usar logger.log({level: 'error', message: err});
e funcionou
Isso pode ser corrigido para logger.error, etc?
É complicado e prolixo usar logger.log
, especialmente porque com logger.error
você pode adicionar facilmente vários argumentos.
Ei, pessoal, estou investigando isso. @indexzero : ainda acha que a melhor ideia é essencialmente adicionar a funcionalidade enumerateErrorFormat
ao formatador json
por padrão? Precisamos nos preocupar separadamente se meta
é um Error
não apenas um object
(suponho que as pessoas reclamarão se não cuidarmos desse caso?) ? Além disso, estou usando master
, mas parece que logger.error
funciona para mim com a solução de @indexzero / @ SamuelMaddox17 acima:
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'));
Após uma investigação mais aprofundada, parece que o problema logger.error
que expliquei acima é apenas um problema ao usar o registrador padrão. @DABH , experimentei seu código e funciona para mim, mas quando
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'));
Em segundo lugar, concordo que enumerateErrorFormat
deve ser adicionado ao formato json; e você provavelmente está certo sobre meta
também.
Finalmente, gostaria de observar que o exemplo de código fornecido por @DABH faz com que a pilha não "imprima bem" se você quiser; pelo menos na minha máquina executando o macOS High Sierra. Isso é o que parece para mim:
{"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"}
Como você pode ver, ao gerar o erro com uma função JSON, os caracteres de nova linha \n
não criam novas linhas reais. Este é o comportamento esperado ao pegar um objeto e convertê-lo em JSON, mas provavelmente não é o comportamento que realmente desejaríamos de um logger, pelo menos ao efetuar login no console.
Obrigado por pesquisar mais sobre este @DABH
Para sua informação, cheguei aqui depois de brincar um pouco com isso:
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;
O problema é causado por este bug: https://github.com/winstonjs/winston-transport/issues/31
Definitivamente usamos este formulário no winston2.x sem problemas. winston.err('some message', err);
junto com winston.error(err)
acima enumerateErrorFormat
corrige winston.error(err)
mas não o caso de uso com err como segundo parâmetro.
@ SamuelMaddox17
logger.log ({nível: ____, mensagem: err});
funciona muito bem
Ok, descobri algo. Meu comentário de 3 de setembro está errado. Este não é um problema com o registrador padrão. Este é um problema em que você define level
e / ou format
. @DABH aqui está seu código antigo:
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'));
Se você remover isso:
const logger = winston.createLogger({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
transports: [
new winston.transports.Console(),
],
});
E substitua-o por este:
const logger = winston.createLogger({
transports: [
new winston.transports.Console({
level: 'debug',
format: format.combine(
enumerateErrorFormat(),
format.json()
),
}),
],
});
Então, o problema info.message === undefined
aparece. Acredito que não haja problema em especificar o nível e o formato de cada transporte; e tenho quase certeza de que isso era permitido no Winston 2.0.
Aqui está seu exemplo de código com minha alteração de código para que você possa executar e testar facilmente:
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'));
Espero que isso ajude a chegar à raiz do problema.
Eu criei https://github.com/winstonjs/winston/pull/1527
Isso cobre todas as opções. No entanto, alguns testes falham, então fechei-o por enquanto. As falhas são esperadas devido à correção, mas não acredito que estou em posição de fazer a chamada para alterar / excluir os testes.
A falha de compilação está aqui https://travis-ci.org/winstonjs/winston/jobs/453012141 e é óbvio por que os testes agora falham quando você lê o código de teste:
https://github.com/winstonjs/winston/blob/c42ab7fdc51b88db180a7dd90c52ce04ddd4e054/test/logger.test.js#L668
Pensamentos?
Acho que o problema esta nesta linha
const info = (msg && !(msg instanceof Error)
&& msg.message && msg) || {
mensagem: msg
};
adicionar uma verificação de instanceof Error parece resolver o problema, como @crowleym aponta
Para qualquer um que ainda esteja lidando com isso, este é o formatador de solução alternativa que consegui criar (snippet do meu módulo 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));
}
Por alguma razão, logger.error(new Error("hello"))
só funciona se você definir o formatador globalmente em winston.createLogger
🤔 e obter o objeto Error em info
no formatador.
Se você definir um formatador por transporte, terá que usar logger.log({level: "error", message: new Error("FAILED")})
e manipular o objeto Error por meio de info.message
vez de info
para acessar o objeto Error.
Eu acho que há um bug ao definir o campo de formato nas opções de transporte.
Esses são apenas meus 2 centavos e o que funcionou para mim, eu sou novo no Winston e não experiente em JavaScript, então não me cite em nada.
Minha abordagem foi uma tentativa de consertar a causa raiz. Mas não está obtendo muita força dos proprietários do repo ...
Sim, eu entendo isso. Eu literalmente gastei muito tempo descobrindo isso porque sou novo no Winston e pensei que talvez fosse eu o utilizando incorretamente ou não tendo compreendido os conceitos por trás dele de maneira adequada ainda.
Mas, felizmente, me deparei com alguns tópicos (incluindo este) que me mostraram o contrário. Esperançosamente, eles consertarão isso para que eu não precise continuar usando a solução alternativa.
Isso pode ser causado por wintson-transport
, consulte https://github.com/winstonjs/winston-transport/issues/31 para o problema e https://github.com/winstonjs/winston-transport/pull/ 34 para um PR.
O registro direto de objetos de erro é sempre uma bagunça por causa de suas propriedades não enumeráveis. Pessoalmente, considero isso uma prática ruim, mas muitas pessoas na comunidade são inflexíveis quanto a isso como um requisito de que devemos apoiá-lo.
Considerando a adoção de https://github.com/winstonjs/logform/pull/59 como um formato para suportar comportamentos como este. No lado positivo, ele encapsula todos os casos extremos que são tão comuns ao tratar erros como mensagens de log. Por outro lado, seria outro formato que as pessoas precisariam aceitar (semelhante a .splat()
)
@indexzero Eu tendo a concordar, mas o registro de erros direto pode ser útil quando combinado com o formato de registro personalizado / printf se houver necessidade de exibir vários tipos Error
diferente e não me lembro do Winston 2.x tentando combater essa prática, pois era permitido fora da caixa
Portanto, a solução proposta para enumerateErrorFormat funciona, mas não suporta o formato logger.error('some message', err)
. Porque nem info.message
nem info
são instanceof Error
. Também quero apontar outro problema com esta solução. No momento, estou registrando um erro que retornou de 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
}
Se simplesmente usarmos Object.assign então resfrie a pilha e a mensagem será definida! MAS, qualquer outra informação que fazia parte do erro também será registrada. Isso pode ser muito perigoso nos casos em que os erros contêm dados confidenciais, como Authorization Headers
(que, neste caso, são incluídos como parte do objeto de erro).
Mas então você pode dizer. Isso não é uma falha do winston, nem do winston que o superagente adiciona esses dados ao erro. EU CONCORDO! NO ENTANTO, como tudo é armazenado plano no objeto info
, torna-se muito difícil manter as informações antigas e não substituir o resto.
Seria quase bom se, ao usar logger.error. Assumiu que o segundo parâmetro era um erro e o colocou no objeto info
como info.error
e, se logar de outra forma, a interface seria { level: "error", error: YOUR ERROR OBJECT}
Na verdade, estou apenas cuspindo aqui, mas a nova interface definitivamente tem sido um pouco frustrante (tudo sobre informações).
Apenas para elaborar o que eu estava defendendo, suponha que você logger.error( e )
onde e é do tipo erro.
Então, em seu código, você configurou o winston da seguinte maneira:
winston.configure({
format: combine(
timestamp(),
enumerateErrorFormat(),
...
),
});
o carimbo de data / hora está sendo empurrado para o objeto de erro 😱. Isso realmente faz sentido? Pense nisso .. o objeto de erro que você enviou está obtendo um novo prop dinamicamente .. timestamp.
Acho que a melhor solução geral para esse problema seria oferecer suporte à seguinte sintaxe
logger.error('An error occurred when doing something important', { error: e } );
e então, internamente, você pode criar um formatador de erro que procura o campo de erro!
Atualização sobre este pessoal:
errors
em logform
com winston: https://github.com/winstonjs/winston/compare/gh-1338Esperando costurá-lo e despachá-lo nos próximos dias. É a penúltima edição em nosso [email protected]
tracker
Olá pessoal, confira https://github.com/winstonjs/winston/pull/1562. Este foi o último item em nossa lista de verificação de lançamento de 3.2.0
então, assim que o PR for costurado, poderemos liberar.
Até que uma correção seja publicada, eu uso a seguinte solução alternativa:
logger.error = item => {
logger.log({ level: 'error', message: item instanceof Error ? item.stack : item });
};
Estou no último winston (3.2.1) e ainda estou recebendo undefined
ao passar um erro para logger.error
@ezze teve uma ótima solução, mas o rastreamento de pilha é forçado em uma nova linha. aqui está uma versão ligeiramente modificada que o coloca em uma linha (então é capturado por um grep simples de arquivos de log)
logger.error = item => {
const message = item instanceof Error
? item.stack.replace('\n', '').replace(' ', ' - trace: ')
: item;
logger.log({ level: 'error', message });
};
com saída <Error message> - trace: <stack trace>
se houver uma maneira mais fácil de fazer isso com o winston mais recente, me informe @indexzero. eu sou novo na biblioteca e estava seguindo a documentação
Acabei de ver o link que você postou no PR. isso significa que para passar um erro para logger.error
necessária uma string de mensagem, então o erro?
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 Acabou havendo 2 problemas sobre os quais este tópico falou. O primeiro é o que o pôster original trouxe, e o segundo é o problema que eu mencionei, que é o mesmo que o seu. Acho que eles apenas consertaram o problema dos pôsteres originais. Pretendo verificar mais a fundo para ter certeza e, em seguida, abrir um novo problema, se for esse o caso. Eu não tive tempo para mergulhar mais fundo, infelizmente. Nesse ínterim, se você usar logger.log({level: 'error', message: err});
que err
é um objeto de erro, ele funcionará.
Ainda tendo esse problema, perdi muito tempo para descobrir isso, a solução do @ the-vampiire funciona bem.
Por que este tíquete está fechado?
Substituir logger.error é até agora a melhor solução porque não adiciona uma propriedade timestamp a um objeto Error que é passado como um único argumento para error (). A maioria das pessoas provavelmente espera que os objetos Error sejam imutáveis. Se você também não sobrescrever logger.info e todos os outros métodos relacionados a níveis, será uma surpresa quando as coisas não funcionarem como o esperado. Novamente, a menos que você queira que seu objeto seja modificado, não importa seu tipo, não o envie diretamente para um método logger Winston.
O recurso é compatível desde [email protected]
Exemplo de uso:
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 @ the-vampiire
Eu também ainda estou tendo o problema.
Quando chamo o erro de logger.error(error);
, recebo apenas undefined
.
Somente se eu chamá-lo como logger.error('Something went wrong', error)
, obtenho o erro completo e posso analisá-lo.
Eu também ainda estou tendo o problema.
Quando chamo o erro delogger.error(error);
, recebo apenasundefined
.
Somente se eu chamá-lo comologger.error('Something went wrong', error)
, obtenho o erro completo e posso analisá-lo.
Você adicionou isso?
format.errors({ stack: true })
Sim, ainda é o mesmo problema. Tento reproduzi-lo em uma essência.
@ OBrown92 Eu enfrentei o mesmo problema hoje. Posso confirmar que funciona, se format.errors({ stack: true })
, é aplicado ao logger, não ao transporte. Neste caso, é possível usar logger.error(error);
e logger.error('Something went wrong', error)
. No entanto, há um problema quando tento aplicar format.errors({ stack: true })
ao transporte escolhido. Neste caso, recebo undefined
por logger.error(error);
, mas logger.error('Something went wrong', error)
funciona corretamente.
Não tenho certeza se é o comportamento esperado ou se é um bug, mas gastei muito tempo para encontrar a causa, então corrija ou mencione isso em algum lugar na sua documentação. Seria muito útil.
De qualquer forma, sou muito grato por seu trabalho neste grande projeto.
Eu estava enfrentando o mesmo problema, então escrevi este pacote, utils-deep-clone . Confira.
format.errors is not a function
... bem, isso é uma surpresa.
@holmberd
Você importou os formatos do pacote winston?
Exemplo de uso:
const { format } = require('winston')
Ou
const winston = require('winston');
const { format } = winston;
@aybhalala yepp, embora não importe que a pilha de erros seja passada para printf
sem ela.
Atualização: como ainda há problemas com isso, estou fazendo o seguinte há algum tempo e está funcionando muito bem
// 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 } );
^^ Esse é o uso esperado. Visto que meros mortais nunca descobrirão isso, deve ser documentado.
Uma vez que meros mortais nunca vão descobrir isso, deve ser documentado
😂 +1 para aquele companheiro
Eu uso o winston com um transporte de terceiros ( @google-cloud/logging-winston
), então tenho um pouco menos de controle sobre a sintaxe. Além disso, acho isso apenas mais intuitivo:
const error = new Error('something bad happened');
logger.error('was doing this and', error);
Ao fazer login no console, concateno a pilha na mensagem. Mas o resultado é mais ou menos assim:
ERROR was doing this andsomething bad happened Error: something bad happened <rest of the stack.>
Como o winston concatena meta.message
na mensagem original, existe o estranho andsomething
e a mensagem duplicada que também é impressa na pilha. Isso é descrito em # 1660.
Parece que # 1664 está tentando consertar isso. Nesse ínterim, escrevi um formatador que "desfaz" essa concatenação: https://github.com/winstonjs/winston/issues/1660#issuecomment -512226578
@dandv
logger.error('Caught error:', e);
Isso não funciona porque, ao contrário de
console.log()
, ologger.<level>(message)
do winston leva apenas um parâmetro chamado mensagem. Esse parâmetro de mensagem é um objeto ou uma string (alguém me corrige se eu estiver errado, mas esse é o meu entendimento).Observe que você também pode usar
logger.log({level: <level>, message: <message>})
. Para aprender mais sobre essas duas funções, eu recomendo a leitura desta parte da documentação: Winston Docs on Log Levels . Certifique-se de ler Usando níveis de registrologger.error(`Caught error: ${e}`);
Não posso dizer definitivamente por que isso não gera a pilha, mas sei que isso não é um problema com o winston. Se você tentar
console.log(`Caught error: ${e}`)
, também não incluirá a pilha. Não trabalhei muito com literais de modelo, portanto, os literais de modelo não funcionam bem com objetos ou o console.log do javascript reconhece o objeto como um objeto de erro e, portanto, apenas exibe a propriedade the message. Esse é meu melhor palpite.logger.error(`Caught error: ${JSON.stringify(e)}`)
Este vai ao cerne do que é esse tópico de bug. Primeiro você deve entender alguns detalhes técnicos sobre javascript. Observe que se você tentar
console.log(`Caught error: ${JSON.stringify(e)}`)
também obterá a mesma saídaCaught error: {}
. Como @indexzero explicou:
message
estack
emError
não são enumeráveis, o que faz com queJSON.stringify
produza algo que ninguém espera.Basicamente, porque
message
estack
propriedades não são enumeráveis,JSON.stringify
pula essas propriedades, que é como você termina com um objeto vazio{}
. Para entender melhor a enumerabilidade, recomendo a leitura deste Enumerabilidade e propriedade de propriedadesFelizmente, devido à forma como o winston 3.0 foi projetado (props para a equipe winston), temos uma solução alternativa para isso que o @indexzero ofereceu. Vou ajudar a explicar. Primeiro você cria esta função:
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; });
Nos objetos Streams, objectMode e info do docs
info.level
einfo.message
. Essa propriedadeinfo.message
É o objeto de erro se isso for tudo o que você passou. Portanto, criamos um novo objeto ondemessage.stack
emessage.message
(Pense nisso comoError.stack
eError.message
) agora são enumeráveis e incluímos todas as outras propriedades que também podem ser anexadas a esse objeto de erro.Em seguida, você criará este registrador que usa a função
enumerateErrorFormat()
acima:const logger = createLogger({ format: format.combine( enumerateErrorFormat(), format.json() ), transports: [ new transports.Console() ] });
Isso pegará qualquer
message
você passar e verificar se é um objeto de erro. Se for, ele corrigirá o problema de enumeração. Em seguida, ele passa a mensagem paraformat.json
que irá stringificar qualquer objeto (erro ou não). Se não for um objeto, é uma string eformat.json
effectivley não faz nada, e você está em casa livre!Ainda assim, seria bom se não tivéssemos que criar aquele
enumerateErrorFormat
uma vez que os objetos de erro são comumente registrados. Pelo que entendi, a equipe winston está trabalhando em uma correção que será lançada em uma versão posterior.Algumas notas finais. Isso só funciona se você usar
logger.log({level: <level>, message: <message>})
onde mensagem é o objeto de erro. Exemplo:try { throw(new Error('This should work')); } catch (err) { logger.log({level: 'error', message: err}); }
Há outro bug no winston em que este código não funciona, como expliquei em meu outro post acima:
try { throw(new Error('This will not work')); } catch (err) { logger.error(err); }
Por alguma razão, a propriedade
info.message
é indefinida quando usamoslogger.error(err)
. Esperançosamente @indexzero pode descobrir isso.
Muito boa explicação, só quero adicionar que com logger.error(
Erro capturado: $ {e} );
você perde a pilha por causa da maneira como a string literal funciona em javascript, `${e}`
é exatamente igual a e.toString()
, portanto, imprimir apenas a mensagem de erro é o comportamento esperado.
Isso ainda é um problema? Ainda estou tendo problemas com isso:
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
}
Isso ainda é um problema? Ainda estou tendo problemas com isso:
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 }
mesmo problema aqui...
depois de olhar o código-fonte, posso ver quais parâmetros ele aceita:
interface LeveledLogMethod {
(mensagem: string, callback: LogCallback): Logger;
(mensagem: string, meta: any, callback: LogCallback): Logger;
(mensagem: string, ... meta: any []): Logger;
(infoObject: objeto): Logger;
}
portanto, se você passar o objeto de erro como primeiro parâmetro, ele só receberá a mensagem do erro porque só entende strings, e se você passar o erro no segundo parâmetro, poderá acessar o rastreamento de pilha em info.stack
btw eu não consegui encontrar isso em nenhum lugar na documentação
Eu encontrei duas soluções, a primeira é usar format.errors
, mencionado no logform no logger pai , em seguida, criar um messageFormatter usando format.printf
e adicionar condicionalmente um campo stack
extraído de info
( format.errors({ stack: true})
adicionará isso).
A outra solução, que eu preferia, era hackear loggers de nível 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)
}
})
Parece que posso obter um registro de erros semelhante a console.log
Posso verificar se o comentário de @tiagonapoli sobre como format.errors
deve estar no registrador _parent_ está correto. Quando eu faço algo assim:
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);
O manuseio do objeto Error
é feito como se eles fossem uma string. No entanto, se eu fizer algo assim:
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);
O manuseio do objeto Error
funciona corretamente.
Parece-me que o bug aqui é que não deve haver diferença no comportamento.
Então isso ainda não foi corrigido após 1 ano? Tenho que hackear o código do winston logger para fazê-lo funcionar?
Sim, isso me deu tanta dor de cabeça que Winston começou a parecer muito mais problemático do que valia para o meu caso de uso relativamente simples ... Acabei escrevendo minha própria pequena classe de logger e recomendaria que outros fizessem o mesmo, a menos que Winston fornece algo de que você realmente precisa.
Caras, sério? isso é frustrante ...
Não sou um committer, mas provavelmente estou correto em dizer que isso não será “consertado” porque não está quebrado. Vale a pena usar Winston. Você só precisa configurá-lo - o melhor conselho para mim está acima em https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691
Ainda não ?
Atualização: como ainda há problemas com isso, estou fazendo o seguinte há algum tempo e está funcionando muito bem
// 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 } );
de onde vem o traço?
Não, realmente, isso é inaceitável para uma biblioteca de registro.
O mantenedor deve simplesmente colocar um exemplo bem destacado nos documentos, onde é mostrado como registrar um erro, até mesmo definindo o formato printf personalizado e o formato não json e onde você pode registrar o erro com algo como logger.error ("something", err) e logger .error (err)
Winston parecia ótimo, mas esse problema é incrivelmente inaceitável
Esta é minha opinião sobre como registrar erros usando o Winston. Não é o único, muitas pessoas acima também têm soluções de trabalho baseadas nos mesmos conceitos.
Fundo
Estou usando @jsdevtools/ono
para envolver tipos de objetos arbitrários em erros personalizados, mas, independentemente disso, esta solução ainda parece funcionar bem em erros de nó nativo (por exemplo, erros fs eperm) e classes de erro personalizadas.
Explicação
Basicamente, eu confio em format.errors({stack:true})
e format.metadata()
. Conforme mencionado por https://github.com/winstonjs/winston/issues/1338#issuecomment -532327143, isso deve estar no formatador pai .
Os metadados ajudam a mudar todas as propriedades personalizadas do objeto de erro para info.metadata
.
Eu queria imprimir 3 tipos de informação: a mensagem de erro, o stacktrace e as propriedades do objeto de erro. A mensagem de erro já era um texto simples. Imprimi a pilha info.metadata.stack
usando o módulo pretty-error
. Para as propriedades do objeto de erro, eu não queria que o stacktrace aparecesse novamente, então, clonei o objeto e excluí a propriedade stacktrace. Em seguida, imprimi o objeto de erro usando fast-safe-stringify
, que é o mesmo módulo stringify do qual o winston depende.
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: Também considero a solução mencionada em https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691 uma boa alternativa. Ou seja, usando logger.warn("Oh no", { error: new Error() })
, em seguida, referenciando info.error
em seu formatador personalizado.
@tiagonapoli, sua solução sobre o uso de format.errors
no registrador pai funcionou para mim:
const logger = createLogger({
transports: loggerTransports,
});
logger.format = format.errors({ stack: true });
É bastante doloroso configurar este logger ... Ele não poderia simplesmente se comportar como console.log
fora da caixa?
@ will093 mesmo aqui. Voltei a falar desse assunto e não entendo por que meu console.log
é bom e limpo e o formato winston é uma merda.
Meus 2 centavos
// 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;
}),
),
}));
}
Exemplo para logger.error("Error during schema stitching", e);
usar @tiagonapoli e a solução de @ will093 de adicioná-lo apenas ao pai parece ser a maneira mais fácil de suportar erros de registro direto e ainda registrar mensagens - aqui está um exemplo completo de uma configuração mínima com carimbos de data / hora:
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
),
});
};
funciona com uma pilha quando chamado com um erro como: logger.error(error)
, funciona com uma string quando chamado como logger.error('a regular message')
, tem a seguinte aparência em meus logs:
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
isso não tenta resolver a logger.error('message here', error)
-incompatibilidade winston w / console.log
, que a solução mais envolvente de
Além disso, se você gosta de logs json, pode largar logFormatter
aqui e usar winston.format.json()
em seu lugar, o que ainda incluirá a pilha - mas não é bonito.
Atualização: como ainda há problemas com isso, estou fazendo o seguinte há algum tempo e está funcionando muito bem
// 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 } );
onde está a definição trace ()?
Atualização: como ainda há problemas com isso, estou fazendo o seguinte há algum tempo e está funcionando muito bem
// 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 } );
de onde vem o traço?
alguma resposta sobre isso?
Comentários muito úteis
Não, realmente, isso é inaceitável para uma biblioteca de registro.
O mantenedor deve simplesmente colocar um exemplo bem destacado nos documentos, onde é mostrado como registrar um erro, até mesmo definindo o formato printf personalizado e o formato não json e onde você pode registrar o erro com algo como logger.error ("something", err) e logger .error (err)
Winston parecia ótimo, mas esse problema é incrivelmente inaceitável