Winston: [3.0.0] Objeto de erro não é analisado ou impresso

Criado em 29 mai. 2018  ·  68Comentários  ·  Fonte: winstonjs/winston

Conte-nos sobre o seu ambiente:

  • _ winston versão? _
  • _ node -v saídas: _ v8.11.1
  • _Sistema operacional? _ (Windows, macOS ou Linux) macOS
  • _Language? _ (All | TypeScript XX | ES6 / 7 | ES5 | Dart) All

Qual é o problema?

Registrar 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"}

O que você espera que aconteça em vez disso?

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?

Outra informação

Deixe-me saber como posso ajudar - feliz em agitar um PR, mas ainda não sei como encontrar [email protected] suficiente para encontrá-lo

bug important

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

Todos 68 comentários

Temos alguma cobertura de teste para isso, mas claramente precisamos de mais. O que está acontecendo nos bastidores:

  1. Sua instância Error é passada ao longo da cadeia de tubos objectMode stream
  2. O formato padrão para Logger é json (veja: json código de formato em logform )
  3. 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 e stack em Error não são enumeráveis, o que faz com que JSON.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:

Esperando 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 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.
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() , 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 e stack em Error não são enumeráveis, o que faz com que JSON.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 a mensagem para format.json que irá stringificar 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.

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

Log Screenshot

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

image

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?

Esta página foi útil?
0 / 5 - 0 avaliações