Winston: [рей.реж.реж] рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБ рдкрд╛рд░реНрд╕ рдпрд╛ рдореБрджреНрд░рд┐рдд рдирд╣реАрдВ рд╣реИ

рдХреЛ рдирд┐рд░реНрдорд┐рдд 29 рдордИ 2018  ┬╖  68рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: winstonjs/winston

рдХреГрдкрдпрд╛ рд╣рдореЗрдВ рдЕрдкрдиреЗ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрддрд╛рдПрдВ:

  • _ winston рд╕рдВрд╕реНрдХрд░рдг?_
  • _ node -v рдЖрдЙрдЯрдкреБрдЯ:_ v8.11.1
  • _рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо?_ (Windows, macOS, рдпрд╛ Linux) macOS
  • _рднрд╛рд╖рд╛?_ (рд╕рднреА | рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ XX | ES6/7 | ES5 | рдбрд╛рд░реНрдЯ) рд╕рднреА

рд╕рдорд╕реНрдпрд╛ рдХреНрдпрд╛ рд╣реИ?

рдПрдХ рдиреЛрдб Error рдСрдмреНрдЬреЗрдХреНрдЯ рд▓реЙрдЧ рдХрд░рдиреЗ рд╕реЗ рдПрдХ рдЦрд╛рд▓реА рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ:

рдЙрджрд╛рд╣рд░рдг:

const winston = require('winston');
const { createLogger, format, transports } = winston;

const logger = createLogger({
  transports: [
    new transports.Console()
  ]
});

let err = new Error('this is a test');
logger.log({level: 'error', message: err});

рдкрд░рд┐рдгрд╛рдореА рдЖрдЙрдЯрдкреБрдЯ:

% node test.js
{"level":"error","message":{}}

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛:

logger.error(new Error('hello'))

рдХрд╛ рдкрд░рд┐рдгрд╛рдо:

{"level":"error"}

рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдЖрдк рдХреНрдпрд╛ рд╣реЛрдиреЗ рдХреА рдЙрдореНрдореАрдж рдХрд░рддреЗ рд╣реИрдВ?

рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рд╕рдВрджреЗрд╢ рдХреБрдВрдЬреА рдореЗрдВ рдХрдо рд╕реЗ рдХрдо рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рд╢рд╛рдорд┐рд▓ рд╣реЛрдЧрд╛ред рдпрджрд┐ рдореИрдВ рдПрдХ рдХрд╕реНрдЯрдо рдлреЙрд░реНрдореЗрдЯрд░ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реВрдВ, рддреЛ info рднреА рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдХрд╣реАрдВ рд╕реЗ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП?

рдЕрдиреНрдп рд╕реВрдЪрдирд╛

рдореБрдЭреЗ рдмрддрд╛рдПрдВ рдХрд┐ рдореИрдВ рдХреИрд╕реЗ рдорджрдж рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ - рдПрдХ рдкреАрдЖрд░ рдлреНрд▓рд┐рдХ рдХрд░рдиреЗ рдореЗрдВ рдЦреБрд╢реА рд╣реБрдИ рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдЗрд╕реЗ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдЕрднреА рддрдХ [email protected] рдЖрд╕рдкрд╛рд╕ рдЕрдкрдирд╛ рд░рд╛рд╕реНрддрд╛ рдирд╣реАрдВ рдкрддрд╛ рд╣реИ

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдирд╣реАрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рд▓реЙрдЧрд┐рдВрдЧ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд▓рд┐рдП рдЕрд╕реНрд╡реАрдХрд╛рд░реНрдп рд╣реИред
рдореЗрдВрдЯреЗрдирд░ рдХреЛ рдХреЗрд╡рд▓ рдбреЙрдХреНрд╕ рдкрд░ рдПрдХ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдЙрджрд╛рд╣рд░рдг рд░рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП рдЬрд╣рд╛рдВ рдпрд╣ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдХреИрд╕реЗ рдПрдХ рддреНрд░реБрдЯрд┐ рд▓реЙрдЧ рдХрд░рдирд╛ рд╣реИ, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛтАЛтАЛрдХрд┐ рдХрд╕реНрдЯрдо рдкреНрд░рд┐рдВрдЯрдл рдкреНрд░рд╛рд░реВрдк рдФрд░ рдЧреИрд░ рдЬреЗрд╕рди рдкреНрд░рд╛рд░реВрдк рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдирд╛ рдФрд░ рдЬрд╣рд╛рдВ рдЖрдк рд▓реЙрдЧрд░ рдЬреИрд╕реЗ рдХреБрдЫ рдХреЗ рд╕рд╛рде рддреНрд░реБрдЯрд┐ рд▓реЙрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рддреНрд░реБрдЯрд┐ (рддреНрд░реБрдЯрд┐)
рд╡рд┐рдВрд╕реНрдЯрди рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд▓рдЧ рд░рд╣рд╛ рдерд╛ рд▓реЗрдХрд┐рди рдпрд╣ рдореБрджреНрджрд╛ рдЕрд╡рд┐рд╢реНрд╡рд╕рдиреАрдп рд░реВрдк рд╕реЗ рдЕрд╕реНрд╡реАрдХрд╛рд░реНрдп рд╣реИ

рд╕рднреА 68 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреБрдЫ рдкрд░реАрдХреНрд╖рдг рдХрд╡рд░реЗрдЬ рд╣реИрдВ , рд▓реЗрдХрд┐рди рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд╣рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдХрд╡рд░ рдХреЗ рддрд╣рдд рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ:

  1. рдЖрдкрдХрд╛ Error рдЙрджрд╛рд╣рд░рдг objectMode рд╕реНрдЯреНрд░реАрдо рдкрд╛рдЗрдк-рдЪреЗрди рдХреЗ рд╕рд╛рде рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ
  2. Logger рд▓рд┐рдП рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкреНрд░рд╛рд░реВрдк json (рджреЗрдЦреЗрдВ: json рдкреНрд░рд╛рд░реВрдк рдХреЛрдб logform )
  3. message рдФрд░ stack рдЧреБрдг Error рдкрд░ рдЧреИрд░-рдЧрдгрдирд╛ рдпреЛрдЧреНрдп рд╣реИрдВ рдЬреЛ JSON.stringify рдХреЛ рдХреБрдЫ рдРрд╕рд╛ рдЖрдЙрдЯрдкреБрдЯ рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░рдг рдмрдирддрд╛ рд╣реИ рдЬрд┐рд╕рдХреА рдХреЛрдИ рдЙрдореНрдореАрдж рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред
console.log(JSON.stringify(new Error('lol nothing here')));
// '{}'

рдПрдХ рдбрд┐рдЬрд╛рдЗрди рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ winston@3 рд╢реБрд░реВ рдХреА formats рд╡реГрджреНрдзрд┐ рдкреНрд░рджрд░реНрд╢рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЗрд╕ рддрд░рд╣ рдХреЗред рдкреНрд░рджрд░реНрд╢рди рдХреА рдмрд╛рдд рдХрд░реЗрдВ рддреЛ, рджрд┐рд▓рдЪрд╕реНрдк рд░реВрдк рд╕реЗ рдкрд░реНрдпрд╛рдкреНрдд pino рдпрд╣рд╛рдВ рдХреБрдЫ рджрд┐рд▓рдЪрд╕реНрдк рдХрд░рддрд╛ рд╣реИ ред рд╢рд╛рдпрдж рд╕рдорд╛рдзрд╛рди рдбрд┐рдлрд╝реЙрд▓реНрдЯ json рдкреНрд░рд╛рд░реВрдк рдореЗрдВ asJson рд╕рдорд╛рди рдХреБрдЫ рд▓рд╛рдЧреВ рдХрд░ рд░рд╣рд╛ рд╣реИред

рдпрджрд┐ рдХреЛрдИ рддреНрд╡рд░рд┐рдд рд╕рдорд╛рдзрд╛рди рдХреА рддрд▓рд╛рд╢ рдореЗрдВ рд╣реИ рддреЛ рдЖрдк рдЕрднреА рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдХреЗ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ enumerateErrorFormat рд╢рд╛рдорд┐рд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдо рдЙрдореНрдореАрдж рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдЕрдЧрд▓реЗ рд╕рдкреНрддрд╛рд╣ (рдпрд╛ рдЗрд╕рдХреЗ рддреБрд░рдВрдд рдмрд╛рдж 3.0.1 ) рд╕реЗ рдкрд╣рд▓реЗ 3.0.0 рд╕реЗ рдкрд╣рд▓реЗ рдЗрд╕реЗ рдареАрдХ рдХрд░ рд▓реЗрдВрдЧреЗред

const winston = require('../');
const { createLogger, format, transports } = winston;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const logger = createLogger({
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new transports.Console()
  ]
});

// Error as message
console.log('Run FIRST test...');
logger.log({ level: 'error', message: new Error('FIRST test error') });

// Error as info (one argument)
console.log('\nRun SECOND test...');
const err = new Error('SECOND test error');
err.level = 'info';
logger.info(err);

// Error as info (two arguments);
console.log('\nRun THIRD test...');
logger.log('info', new Error('THIRD test error'));

@indexzero , рдореИрдВрдиреЗ рдЖрдкрдХреЗ рдХрд╛рдордХрд╛рдЬ рдХрд╛ рдкрд╛рд▓рди рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА, рд▓реЗрдХрд┐рди рдпрд╣ рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИред рдЬрд╛рдирддреЗ рд╣реЛ рдХреНрдпреЛрдВ?

рдлрд╝реЙрд░реНрдореЗрдЯрд░:
``` javascript const level = settings.debug ? 'debug' : 'info'; const printFormat = winston.format.printf(info => ${info.timestamp} - ${info.level}: ${info.message}`);
const enumerateErrorFormat = рд╡рд┐рдВрд╕реНрдЯрдиред рдкреНрд░рд╛рд░реВрдк (рдЬрд╛рдирдХрд╛рд░реА => {
рдЕрдЧрд░ (info.message рдЙрджрд╛рд╣рд░рдг рддреНрд░реБрдЯрд┐) {
info.message = рдСрдмреНрдЬреЗрдХреНрдЯ.рдЕрд╕рд╛рдЗрди ({
рд╕рдВрджреЗрд╢: info.message.message,
рд╕реНрдЯреИрдХ: info.message.stack,
}, info.message);
}
рдЕрдЧрд░ (рд╕реВрдЪрдирд╛ рдЙрджрд╛рд╣рд░рдг рддреНрд░реБрдЯрд┐) {
рд╡рд╛рдкрд╕реА рд╡рд╕реНрддреБ.рдЕрд╕рд╛рдЗрди ({
рд╕рдВрджреЗрд╢: info.message,
рд╕реНрдЯреИрдХ: info.stack,
}, рдЬрд╛рдирдХрд╛рд░реА);
}
рд╡рд╛рдкрд╕реА рдХреА рдЬрд╛рдирдХрд╛рд░реА;
});

рдХреЙрдиреНрд╕реНрдЯ рдХрдВрд╕реЛрд▓рд▓реЙрдЧрд░ = рд╡рд┐рдВрд╕реНрдЯрдиред рдХреНрд░рд┐рдПрдЯрд▓реЙрдЧрд░ ({
рд╕реНрддрд░,
рдкреНрд░рд╛рд░реВрдк: рд╡рд┐рдВрд╕реНрдЯрдиред рдкреНрд░рд╛рд░реВрдкред рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк (),
рдкрд░рд┐рд╡рд╣рди: [
рдиреНрдпреВ рд╡рд┐рдВрд╕реНрдЯрди.рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯреНрд╕.рдХрдВрд╕реЛрд▓ ({
рдкреНрд░рд╛рд░реВрдк: рд╡рд┐рдВрд╕реНрдЯрди.format.combine(
рд╡рд┐рдВрд╕реНрдЯрди.format.colorize (),
рдЧрдгрдирд╛ рддреНрд░реБрдЯрд┐рдлреЙрд░реНрдореЗрдЯ (),
рдкреНрд░рд┐рдВрдЯрдлреЙрд░реНрдореЗрдЯ,
),
}),
],
});
Code: рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ
рдкреНрд░рдпрддреНрди {
// рдХреБрдЫ рдХреЛрдб рдлреЗрдВрдХрдиреЗ рдореЗрдВ рддреНрд░реБрдЯрд┐
} рдкрдХрдбрд╝реЛ (рдЧрд▓рддреА) {
рд▓рдХрдбрд╝рд╣рд╛рд░рд╛.рддреНрд░реБрдЯрд┐ (рддреНрд░реБрдЯрд┐);
}
Output:
2018-06-28T21:17:25.140Z - рддреНрд░реБрдЯрд┐: рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд
Info object: рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ
{рд╕реНрддрд░: '\u001b[31merror\u001b[39m', рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк: '2018-06-28T21:17:25.140Z', [рдкреНрд░рддреАрдХ(рд╕реНрддрд░)]: 'рддреНрд░реБрдЯрд┐'}
````
рддреНрд░реБрдЯрд┐ рд▓реЙрдЧ рдореЗрдВ рд╕рдВрджреЗрд╢ рд╡рд┐рд╢реЗрд╖рддрд╛ рдХрд╣рд╛рдБ рд╣реИ?

@sandrocsimas рдореИрдВрдиреЗ рджреЗрдЦрд╛ рд╣реИ рдХрд┐ рдЗрд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рд▓реЙрдЧрд░ рдХреЗ рдбрд┐рдлрд╝реЙрд▓реНрдЯ

рдлрд╝реЙрд░реНрдореЗрдЯрд░

const consoleLogger = winston.createLogger({
  level,
  format: winston.format.combine(
    winston.format.timestamp(),
    enumerateErrorFormat()
  ),
  transports: [
    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.colorize(),
        printFormat,
      ),
    }),
  ],
});

рдореБрдЭреЗ рдЕрднреА рднреА рд╕рдордЭ рдореЗрдВ рдирд╣реАрдВ рдЖрддрд╛ рдХрд┐ рдХреНрдпреЛрдВ

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдореИрдВ @sandrocsimas рдХреЗ рд╕рдорд╛рди рдмрдЧ рдХрд╛ рдЕрдиреБрднрд╡ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред

рдпрд╣рд╛рдБ рдореЗрд░реА рд▓рдХрдбрд╝рд╣рд╛рд░рд╛ рд╡рд┐рдиреНрдпрд╛рд╕ рд╣реИ:

рд▓рдХрдбрд╝рд╣рд╛рд░рд╛.рдЬреЗрдПрд╕

const winston = require('winston');
const {configure, format} = winston;
const {combine, colorize, timestamp, printf} = format;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const myConsoleFormat = printf(info => {
  console.log('** Info Object: **');
  console.log(info);
  console.log('** Winston Output: **');
  return `${info.level}: ${info.message}`;
});

winston.configure({
  transports: [
    new winston.transports.Console({
      format: combine(
        colorize(),
        enumerateErrorFormat(),
        myConsoleFormat
      ),
    })
  ]
});

рдЕрдЧрд░ рдореИрдВ рдХреЛрдб рдХреЗ рдЗрд╕ рдмреНрд▓реЙрдХ рдХреЗ рд╕рд╛рде рдЗрд╕рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рддрд╛ рд╣реВрдВ:

рдЯреЗрд╕реНрдЯ рдП

const logger = require('winston');
try {
  throw(new Error());
} catch (err) {
  logger.error(err);
}

рдЬрд╣рд╛рдВ new Error() рдореЗрдВ рдХреЛрдИ рд╕рдВрджреЗрд╢ рдорд╛рди рдирд╣реАрдВ рд╣реИ, рдореБрдЭреЗ рдпрд╣ рдЖрдЙрдЯрдкреБрдЯ рдорд┐рд▓рддрд╛ рд╣реИ:

рдЖрдЙрдЯрдкреБрдЯ рдП

** Info Object: **
{ message: 
   { message: '',
     stack: 'Error\n    at Object.<anonymous> (app.js:21:9)\n    at Module._compile (module.js:652:30)\n    at Object.Module._extensions..js (module.js:663:10)\n    at Module.load (module.js:565:32)\n    at tryModuleLoad (module.js:505:12)\n    at Function.Module._load (module.js:497:3)\n    at Module.require (module.js:596:17)\n    at require (internal/module.js:11:18)\n    at Object.<anonymous> (server.js:11:13)\n    at Module._compile (module.js:652:30)' },
  level: '\u001b[31merror\u001b[39m',
  [Symbol(level)]: 'error',
  [Symbol(message)]: '{"message":{},"level":"error"}' }
** Winston Output: **
error: [object Object]

рдЬрд╣рд╛рдВ error: [object Object] рд╡рд╣реА рд╣реИ рдЬрд┐рд╕рдХреА рдореБрдЭреЗ рдЙрдореНрдореАрдж рдереА

рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЕрдЧрд░ рдореИрдВ рдХреЛрдб рдХреЗ рдЗрд╕ рдмреНрд▓реЙрдХ рдХреЗ рд╕рд╛рде рдЗрд╕рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рддрд╛ рд╣реВрдВ:

рдЯреЗрд╕реНрдЯ рдмреА

const logger = require('winston');
try {
  throw(new Error('This causes error: undefined'));
} catch (err) {
  logger.error(err);
}

рдЬрд╣рд╛рдВ new Error() рдореЗрдВ рдПрдХ рд╕рдВрджреЗрд╢ рдорд╛рди рд╣реЛрддрд╛ рд╣реИ, рдореБрдЭреЗ рдпрд╣ рдЖрдЙрдЯрдкреБрдЯ рдорд┐рд▓рддрд╛ рд╣реИ:

рдЖрдЙрдЯрдкреБрдЯ рдмреА

** Info Object: **
{ level: '\u001b[31merror\u001b[39m',
  [Symbol(level)]: 'error',
  [Symbol(message)]: '{"level":"error"}' }
** Winston Output: **
error: undefined

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдореБрдЭреЗ рд╡рд╣реА error: undefined рдЬреЛ @sandrocsimas рдХреЛ рдорд┐рд▓рддрд╛ рд╣реИред рдореБрдЭреЗ error: [object Object] рдорд┐рд▓рдиреЗ рдХреА рдЙрдореНрдореАрдж

рдиреЛрдЯ, рдЕрдЧрд░ рдореИрдВ рдХреЛрдб рдХреЗ рдЗрд╕ рдмреНрд▓реЙрдХ рдХреЛ рдЖрдЬрдорд╛рддрд╛ рд╣реВрдВ:

рдЯреЗрд╕реНрдЯ рд╕реА

const logger = require('winston');
try {
  throw(new Error('This should work'));
} catch (err) {
  logger.log({level: 'error', message: err});
}

рдЬрд╣рд╛рдВ рдореИрдВ logger.log рдмрдЬрд╛рдп logger.error рд╣реВрдВ, рдореБрдЭреЗ рдЙрдкрд░реЛрдХреНрдд рдЖрдЙрдЯрдкреБрдЯ рдП рдХреЗ рд╕рдорд╛рди рдЖрдЙрдЯрдкреБрдЯ рдорд┐рд▓рддрд╛ рд╣реИ

рдореЗрд░реА рднреА рдпрд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реИред рдореИрдВ рд╡рд┐рдВрд╕реНрдЯрди рдореЗрдВ рдирдпрд╛ рд╣реВрдБред рдореИрдВрдиреЗ @indexzero рд╕рдорд╛рдзрд╛рди рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд▓реЗрдХрд┐рди рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ред рдХреНрдпрд╛ рдЖрдкрдХреЗ рдкрд╛рд╕ рдХреЛрдИ рдЙрдкрд╛рдп рд╣реИ?

@ nvtuan305 , рдХреНрдпрд╛ рдЖрдкрдиреЗ @indexzero рдХреЗ рд╕рдорд╛рдзрд╛рди рдХрд╛ рдмрд┐рд▓реНрдХреБрд▓ рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛ рдпрд╛ рдЖрдкрдиреЗ рдЗрд╕реЗ рдереЛрдбрд╝рд╛ рд╕рдВрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛? рдпрджрд┐ рд╣рд╛рдВ, рддреЛ рдХреНрдпрд╛ рдЖрдк рдирдореВрдирд╛ рдХреЛрдб рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ? рдЖрдк рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЙрдирдХреЗ рдХреЛрдб рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП logger.log({level: ____, message: err}); рдпрд╣ рдЖрдк рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдХрд╛рдо рдирд╣реАрдВ рд╣реЛрдЧрд╛ logger.info , logger.error , рдпрд╛ рдХрд┐рд╕реА рдЕрдиреНрдп рдХрд╛ рд╕реНрд╡рд╛рдж logger.<level> . рдореИрдВ рд▓рдЧрднрдЧ рдирд┐рд╢реНрдЪрд┐рдд рд╣реВрдВ рдХрд┐ рдпрд╣ рдПрдХ рдмрдЧ рд╣реИ рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рдКрдкрд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдмрд╛рдж рдХреЗ рд░рд┐рд▓реАрдЬ рдореЗрдВ рдареАрдХ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдХреНрдпрд╛ рдореБрдЭреЗ рдХреБрдЫ рдпрд╛рдж рдЖ рд░рд╣рд╛ рд╣реИ, рдпрд╛ рдпрд╣ рдПрдХ рд╣реА рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреВрд░реНрдг рд╕рд┐рд░рджрд░реНрдж (рдпрд╛ рдЕрд╕рдВрднрд╡ рднреА рд╣реИ?)

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: {}
}

рд╕рдорд╛рди рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдорддреБрд▓реНрдп рд╡рд┐рдВрд╕реНрдЯрди рдХреЛрдб рдХреНрдпрд╛ рд╣реИ
console.error('Caught error:', error); ?

рдФрд░ рд▓реЙрдЧрд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдкрд░ рд╕реБрд╡рд┐рдзрд╛ рд╡рд┐рдзрд┐рдпреЛрдВ рджреНрд╡рд╛рд░рд╛ рд▓рд┐рдП рдЧрдП рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд▓рд┐рдП рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдХрд╣рд╛рдВ рд╣реИ?

@dandv

logger.error('Caught error:', e);

рдпрд╣ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рдХреНрдпреЛрдВрдХрд┐, console.log() рд╡рд┐рдкрд░реАрдд, рд╡рд┐рдВрд╕реНрдЯрди рдХрд╛ logger.<level>(message) рдХреЗрд╡рд▓ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рд▓реЗрддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╕рдВрджреЗрд╢ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рд╡рд╣ рд╕рдВрджреЗрд╢ рдкреИрд░рд╛рдореАрдЯрд░ рдпрд╛ рддреЛ рдПрдХ рд╡рд╕реНрддреБ рдпрд╛ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИ (рдЕрдЧрд░ рдореИрдВ рдЧрд▓рдд рд╣реВрдВ рддреЛ рдХреЛрдИ рдореБрдЭреЗ рд╕рд╣реА рдХрд░реЗрдЧрд╛ рд▓реЗрдХрд┐рди рдпрд╣ рдореЗрд░реА рд╕рдордЭ рд╣реИ)ред

рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЖрдк logger.log({level: <level>, message: <message>}) рднреА рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрди рджреЛ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдореИрдВ рдбреЙрдХреНрд╕ рдХреЗ рдЗрд╕ рднрд╛рдЧ рдХреЛ рдкрдврд╝рдиреЗ рдХреА рд╕рд┐рдлрд╛рд░рд┐рд╢ рдХрд░реВрдВрдЧрд╛: рд╡рд┐рдВрд╕реНрдЯрди рдбреЙрдХреНрд╕ рдСрди рд▓реЙрдЧ рд▓реЗрд╡рд▓ ред рд▓реЙрдЧрд┐рдВрдЧ рд╕реНрддрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрдврд╝рдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ

logger.error(`Caught error: ${e}`);

рдореИрдВ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдпрд╣ рдирд╣реАрдВ рдХрд╣ рд╕рдХрддрд╛ рдХрд┐ рдпрд╣ рд╕реНрдЯреИрдХ рдХреЛ рдЖрдЙрдЯрдкреБрдЯ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╡рд┐рдВрд╕реНрдЯрди рдХреЗ рд╕рд╛рде рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИред рдпрджрд┐ рдЖрдк console.log(`Caught error: ${e}`) рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЗрд╕рдореЗрдВ рд╕реНрдЯреИрдХ рднреА рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдореИрдВрдиреЗ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рд▓рд┐рдЯрд░рд▓реНрд╕ рдХреЗ рд╕рд╛рде рдмрд╣реБрдд рдЕрдзрд┐рдХ рдХрд╛рдо рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╛ рддреЛ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рд▓рд┐рдЯрд░рд▓реНрд╕ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рд╕рд╛рде рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рдпрд╛ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдХрдВрд╕реЛрд▓.рд▓реЙрдЧ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдПрдХ рдПрд░рд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╣рдЪрд╛рдирддрд╛ рд╣реИ рдФрд░ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреЗрд╡рд▓ рдореИрд╕реЗрдЬ рдкреНрд░реЙрдкрд░реНрдЯреА рдХреЛ рдЖрдЙрдЯрдкреБрдЯ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдореЗрд░рд╛ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рдЕрдиреБрдорд╛рди рд╣реИред

logger.error(`Caught error: ${JSON.stringify(e)}`)

рдпрд╣ рдмрдЧ рдереНрд░реЗрдб рдХрд┐рд╕ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИ, рдЗрд╕рдХреЗ рджрд┐рд▓ рдореЗрдВ рдЙрддрд░ рдЬрд╛рддрд╛ рд╣реИред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рддрдХрдиреАрдХреА рд╡рд┐рд╡рд░рдгреЛрдВ рдХреЛ рд╕рдордЭрдирд╛ рд╣реЛрдЧрд╛ред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрджрд┐ рдЖрдк console.log(`Caught error: ${JSON.stringify(e)}`) рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЖрдкрдХреЛ рд╡рд╣реА рдЖрдЙрдЯрдкреБрдЯ Caught error: {} рднреА рдорд┐рд▓рддрд╛ рд╣реИред рдЬреИрд╕рд╛ рдХрд┐ @indexzero рдиреЗ рд╕рдордЭрд╛рдпрд╛:

message рдФрд░ stack рдкрд░ Error stack рдЧреБрдг рдЧреИрд░-рдЧрдгрдирд╛ рдпреЛрдЧреНрдп рд╣реИрдВ рдЬреЛ JSON.stringify рдХреЛ рдХреБрдЫ рдРрд╕рд╛ рдЖрдЙрдЯрдкреБрдЯ рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░рдг рдмрдирддрд╛ рд╣реИ рдЬрд┐рд╕рдХреА рдХреЛрдИ рдЙрдореНрдореАрдж рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред

рдореВрд▓ рд░реВрдк рд╕реЗ, рдХреНрдпреЛрдВрдХрд┐ message рдФрд░ stack рдЧреБрдг рдЧреИрд░-рдЧрдгрдирд╛ рдпреЛрдЧреНрдп рд╣реИрдВ, JSON.stringify рдЙрди рдЧреБрдгреЛрдВ рдкрд░ рдЫреЛрдбрд╝ рджреЗрддрд╛ рд╣реИ рдЬреЛ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдЖрдк рдПрдХ рдЦрд╛рд▓реА рд╡рд╕реНрддреБ рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рд╣реЛрддреЗ рд╣реИрдВ {} ред рдПрдиреНрдпреВрдорд░реЗрдмрд┐рд▓рд┐рдЯреА рдХреЛ рдмреЗрд╣рддрд░ рдврдВрдЧ рд╕реЗ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдореИрдВ рдЗрд╕ рдПрдиреНрдпреВрдорд░реЗрдмрд┐рд▓рд┐рдЯреА рдФрд░ рдкреНрд░реЙрдкрд░реНрдЯреА рдХреЗ рд╕реНрд╡рд╛рдорд┐рддреНрд╡ рдХреЛ рдкрдврд╝рдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВред

рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, рдЬрд┐рд╕ рддрд░рд╣ рд╕реЗ рд╡рд┐рдВрд╕реНрдЯрди 3.0 рдХреЛ рдбрд┐рдЬрд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ (рд╡рд┐рдВрд╕реНрдЯрди рдЯреАрдо рдХреЗ рд▓рд┐рдП рд╕рд╣рд╛рд░рд╛) рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рд╣реИ рдЬреЛ @indexzero рдиреЗ рджрд┐рдпрд╛ рдерд╛ред рдореИрдВ рдЗрд╕реЗ рд╕рдордЭрд╛рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реВрдВрдЧрд╛ред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдЖрдк рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛рдПрдВ:

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

рдбреЙрдХреНрд╕ рд╕реНрдЯреНрд░реАрдо, рдСрдмреНрдЬреЗрдХреНрдЯрдореЛрдб, рдФрд░ рдЬрд╛рдирдХрд╛рд░реА рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реЗ рдЬрд╛рдирдХрд╛рд░реА рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рджреЛ рдЧреБрдг рд╣реИрдВ, info.level , рдФрд░ info.message ред рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ info.message рд╕рдВрдкрддреНрддрд┐ рддреНрд░реБрдЯрд┐ рдЙрджреНрджреЗрд╢реНрдп рдпрд╣ рд╣реИ рдХрд┐ рдЕрдЧрд░ рдЖрдк рд╕рднреА рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд░ рджрд┐рдпрд╛ рд╣реИред рддреЛ рд╣рдо рдПрдХ рдирдИ рд╡рд╕реНрддреБ рдмрдирд╛рдиреЗ рдЬрд╣рд╛рдВ message.stack рдФрд░ message.message (рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдордЭреЗрдВ Error.stack рдФрд░ Error.message ) рдЕрдм рдЧрдгрдирд╛ рдпреЛрдЧреНрдп рд╣реИрдВ, рдФрд░ рд╣рдо рдЙрди рдЕрдиреНрдп рдЧреБрдгреЛрдВ рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рдЙрд╕ рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реЗ рднреА рд╕рдВрд▓рдЧреНрди рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред

рдЖрдЧреЗ рдЖрдк рдЗрд╕ рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдХреЛ рдмрдирд╛рдПрдВрдЧреЗ рдЬреЛ рдКрдкрд░ рджрд┐рдП рдЧрдП enumerateErrorFormat() рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ:

const logger = createLogger({
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new transports.Console()
  ]
});

рдЗрд╕рдореЗрдВ рдЬреЛ рдХреБрдЫ рднреА message рдЖрдк рдкрд╛рд╕ рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЬрд╛рдВрдЪ рд▓реЗрдВрдЧреЗ рдХрд┐ рдпрд╣ рдПрдХ рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБ рд╣реИ рдпрд╛ рдирд╣реАрдВред рдЕрдЧрд░ рдРрд╕рд╛ рд╣реИ рддреЛ рдпрд╣ рдЧрдгрдирд╛ рдХреА рд╕рдорд╕реНрдпрд╛ рдХреЛ рдареАрдХ рдХрд░ рджреЗрдЧрд╛ред рдлрд┐рд░ рдпрд╣ format.json рд╕рдВрджреЗрд╢ рднреЗрдЬрддрд╛ рд╣реИ рдЬреЛ рдХрд┐рд╕реА рдСрдмреНрдЬреЗрдХреНрдЯ (рддреНрд░реБрдЯрд┐ рдпрд╛ рдирд╣реАрдВ) рдХреЛ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХрд░реЗрдЧрд╛ред рдпрджрд┐ рдпрд╣ рдХреЛрдИ рд╡рд╕реНрддреБ рдирд╣реАрдВ рд╣реИ рддреЛ рдпрд╣ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИ рдФрд░ format.json рдЗрдлреЗрдХреНрдЯрд┐рд╡рд▓реА рдХреБрдЫ рднреА рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдЖрдк рдШрд░ рд╕реЗ рдореБрдХреНрдд рд╣реИрдВ!

рдлрд┐рд░ рднреА, рдпрд╣ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рд╣рдореЗрдВ рд╡рд╣ enumerateErrorFormat рдирд╣реАрдВ рдмрдирд╛рдирд╛ рдкрдбрд╝реЗ рдХреНрдпреЛрдВрдХрд┐ рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдЖрдорддреМрд░ рдкрд░ рд▓реЙрдЧ рд╣реЛрддреЗ рд╣реИрдВред рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВ рд╕рдордЭрддрд╛ рд╣реВрдВ рдХрд┐ рд╡рд┐рдВрд╕реНрдЯрди рдЯреАрдо рдПрдХ рдлрд┐рдХреНрд╕ рдкрд░ рдХрд╛рдо рдХрд░ рд░рд╣реА рд╣реИ рдЬрд┐рд╕реЗ рдмрд╛рдж рдХреЗ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдЬрд╛рд░реА рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рдХреБрдЫ рдЕрдВрддрд┐рдо рдиреЛрдЯред рдпрд╣ рдХреЗрд╡рд▓ рддрднреА рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм рдЖрдк logger.log({level: <level>, message: <message>}) рдЬрд╣рд╛рдВ рд╕рдВрджреЗрд╢ рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБ рд╣реИред рдЙрджрд╛рд╣рд░рдг:

try {
  throw(new Error('This should work'));
} catch (err) {
  logger.log({level: 'error', message: err});
}

рд╡рд┐рдВрд╕реНрдЯрди рдореЗрдВ рдПрдХ рдФрд░ рдмрдЧ рд╣реИ рдЬрд╣рд╛рдВ рдпрд╣ рдХреЛрдб рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рдЙрдкрд░реЛрдХреНрдд рдореЗрд░реА рдЕрдиреНрдп рдкреЛрд╕реНрдЯ рдореЗрдВ рдмрддрд╛рдпрд╛ рд╣реИ:

try {
  throw(new Error('This will not work'));
} catch (err) {
  logger.error(err);
}

рдЬрдм рд╣рдо logger.error(err) рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдХрд┐рд╕реА рдХрд╛рд░рдг рд╕реЗ info.message рд╕рдВрдкрддреНрддрд┐ рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд рд╣реЛрддреА рд╣реИред рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ @indexzero рдЗрд╕рдХрд╛ рдкрддрд╛

@SamuelMaddox17 @indexzero рдзрдиреНрдпрд╡рд╛рдж! рдореИрдВрдиреЗ logger.log({level: 'error', message: err}); рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рдФрд░ рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ

рдХреНрдпрд╛ рдпрд╣ рдХреГрдкрдпрд╛ logger.error, рдЖрджрд┐ рдХреЗ рд▓рд┐рдП рдареАрдХ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ?

logger.log рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЛрдЭрд┐рд▓ рдФрд░ рдХреНрд░рд┐рдпрд╛рддреНрдордХ рд╣реИ, рдЦрд╛рд╕рдХрд░ рдЬрдм рд╕реЗ logger.error рдЖрдк рдЖрд╕рд╛рдиреА рд╕реЗ рдХрдИ рддрд░реНрдХ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред

рд╣реЗ рд╕рдм, рдореИрдВ рдЗрд╕ рдкрд░ рдЧреМрд░ рдХрд░ рд░рд╣рд╛ рд╣реВрдБред @indexzero : рдЕрднреА рднреА рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдЪрд╛рд░ рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ enumerateErrorFormat рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ json рдлреЙрд░реНрдореЗрдЯрд░ рдореЗрдВ рдЬреЛрдбрд╝рдирд╛ рд╣реИ? рдХреНрдпрд╛ рд╣рдореЗрдВ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдЕрд▓рдЧ рд╕реЗ рдЪрд┐рдВрддрд╛ рдХрд░рдиреЗ рдХреА рдЬрд╝рд░реВрд░рдд рд╣реИ рдХрд┐ рдХреНрдпрд╛ meta рдПрдХ Error рди рдХрд┐ рдХреЗрд╡рд▓ object (рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЕрдЧрд░ рд╣рдо рдЙрд╕ рдорд╛рдорд▓реЗ рдХреЛ рднреА рдирд╣реАрдВ рд╕рдВрднрд╛рд▓реЗрдВрдЧреЗ рддреЛ рд▓реЛрдЧ рд╢рд┐рдХрд╛рдпрдд рдХрд░реЗрдВрдЧреЗ?) ? рд╕рд╛рде рд╣реА, рдореИрдВ master рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ logger.error рдореЗрд░реЗ рд▓рд┐рдП рдЙрдкрд░реЛрдХреНрдд @indexzero / @ рд╕реИрдореБрдЕрд▓рдореИрдбреЙрдХреНрд╕ 17 рджреНрд╡рд╛рд░рд╛ рд╕рдорд╛рдзрд╛рди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ:

const winston = require('winston');
const format = winston.format;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new winston.transports.Console(),
  ],
});

logger.error(new Error('whatever'));

рдЖрдЧреЗ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдкрд░ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдКрдкрд░ рдмрддрд╛рдИ рдЧрдИ logger.error рд╕рдорд╕реНрдпрд╛ рдХреЗрд╡рд▓ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд▓реЙрдЧрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИред @DABH , рдореИрдВрдиреЗ рдЖрдкрдХрд╛ рдХреЛрдб рдЖрдЬрд╝рдорд╛рдпрд╛ рдФрд░ рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЬрдм рдореИрдВ рдЗрд╕реЗ рдбрд┐рдлрд╝реЙрд▓реНрдЯ

const winston = require('winston');
const format = winston.format;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

winston.configure({
  transports: [
    new winston.transports.Console({
      level: 'debug',
      format: format.combine(
        enumerateErrorFormat(),
        format.json()
      ),
    })
  ]
});

winston.error(new Error('whatever'));

рджреВрд╕рд░рд╛, рдореИрдВ рд╕рд╣рдордд рд╣реВрдВ рдХрд┐ enumerateErrorFormat рдХреЛ рдЬреЛрдВрд╕ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП; рдФрд░ рдЖрдк рд╢рд╛рдпрдж meta рдореЗрдВ рднреА рд╕рд╣реА рд╣реИрдВред

рдЕрдВрдд рдореЗрдВ, рдореИрдВ рдпрд╣ рдиреЛрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ рдХрд┐ @DABH рджреНрд╡рд╛рд░рд╛ рджрд┐рдП рдЧрдП рдХреЛрдб рдЙрджрд╛рд╣рд░рдг рдХреЗ рдХрд╛рд░рдг рдпрджрд┐ рдЖрдк рдЪрд╛рд╣реЗрдВ рддреЛ рд╕реНрдЯреИрдХ рдХреЛ "рд╕реБрдВрджрд░ рдкреНрд░рд┐рдВрдЯ" рди рдХрд░реЗрдВ; рдХрдо рд╕реЗ рдХрдо рдореЗрд░реА рдорд╢реАрди рдкрд░ macOS рд╣рд╛рдИ рд╕рд┐рдПрд░рд╛ рдЪрд▓ рд░рд╣рд╛ рд╣реИред рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдХреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИ:

{"message":"whatever","stack":"Error: whatever\n    at Object.<anonymous> (/Users/samuelmaddox/Desktop/winston-test/index.js:33:14)\n    at Module._compile (internal/modules/cjs/loader.js:689:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)\n    at Module.load (internal/modules/cjs/loader.js:599:32)\n    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)\n    at Function.Module._load (internal/modules/cjs/loader.js:530:3)\n    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)\n    at startup (internal/bootstrap/node.js:266:19)\n    at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)","level":"error"}

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, JSON рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рд╛рде рддреНрд░реБрдЯрд┐ рдХреЛ рдЖрдЙрдЯрдкреБрдЯ рдХрд░рддреЗ рд╕рдордп рдиреНрдпреВрд▓рд╛рдЗрди рд╡рд░реНрдг \n рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдирдИ рд▓рд╛рдЗрдиреЗрдВ рдирд╣реАрдВ рдмрдирд╛рддреЗ рд╣реИрдВред рдСрдмреНрдЬреЗрдХреНрдЯ рд▓реЗрддреЗ рд╕рдордп рдФрд░ рдЗрд╕реЗ JSON рдореЗрдВ рдХрдирд╡рд░реНрдЯ рдХрд░рддреЗ рд╕рдордп рдпрд╣ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рдВрднрд╡рдд: рд╡рд╣ рд╡реНрдпрд╡рд╣рд╛рд░ рдирд╣реАрдВ рд╣реИ рдЬреЛ рд╣рдо рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд▓реЙрдЧрд░ рд╕реЗ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдХрдо рд╕реЗ рдХрдо рдХрдВрд╕реЛрд▓ рдкрд░ рд▓реЙрдЧрд┐рдВрдЧ рдХрд░рддреЗ рд╕рдордпред

рдЗрд╕рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж @DABH

рдПрдлрд╡рд╛рдИрдЖрдИ рдпрд╣ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдВ рдореБрдЭреЗ рдЗрд╕рдХреЗ рд╕рд╛рде рдереЛрдбрд╝рд╛ рд╕рд╛ рдЦреЗрд▓рдиреЗ рдХреЗ рдмрд╛рдж рдорд┐рд▓ рдЧрдпрд╛ рд╣реИ:

import winston from 'winston';
const format = winston.format;

const printNice = format.printf(info => {
    const {level, message} = info;
    return `Logging Level: ${level} - Logging Message: ${message}`;
});

const enumerateErrorFormat = format(info => {
    if (info.message instanceof Error) {
        info.message = Object.assign({
            message: `${info.message.message}\n============\n${info.message.stack}`
        }, info.message);
    }

    if (info instanceof Error) {
        return Object.assign({
            message: `${info.message}\n============\n${info.stack}`
        }, info);
    }

    return info;
});

const logger = winston.createLogger({
    format: format.combine(
        enumerateErrorFormat(),
        format.json()
    ),
    transports: [
        new winston.transports.Console({
            format: format.combine(
                format.colorize(),
                printNice,
            ),
        })
    ]
});

export default logger;

рд╕рдорд╕реНрдпрд╛ рдЗрд╕ рдмрдЧ рдХреЗ рдХрд╛рд░рдг рд╣реИ: https://github.com/winstonjs/winston-transport/issues/31

рд╣рдордиреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рд╕рдорд╕реНрдпрд╛ рдХреЗ рд╡рд┐рдВрд╕реНрдЯрди2.x рдореЗрдВ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдЗрд╕ рдлреЙрд░реНрдо рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ред winston.err('some message', err); рдХреЗ рд╕рд╛рде winston.error(err) рдЙрдкрд░реЛрдХреНрдд enumerateErrorFormat winston.error(err) рдареАрдХ рдХрд░рддрд╛ рд╣реИ рд▓реЗрдХрд┐рди рджреВрд╕рд░реЗ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдЧрд▓рддреА рдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЗ рдХреЛ рдирд╣реАрдВред

@рд╕реИрдореБрдЕрд▓рдореИрдбреЙрдХреНрд╕17

рд▓рдХрдбрд╝рд╣рд╛рд░рд╛.рд▓реЙрдЧ ({рд╕реНрддрд░: ____, рд╕рдВрджреЗрд╢: рддреНрд░реБрдЯрд┐});

рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ thx

рдареАрдХ рд╣реИ, рдореИрдВрдиреЗ рдХреБрдЫ рдЦреЛрдЬрд╛ред 3 рд╕рд┐рддрдВрдмрд░ рдХреА рдореЗрд░реА рдЯрд┐рдкреНрдкрдгреА рдЧрд▓рдд рд╣реИред рдпрд╣ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд▓рдХрдбрд╝рд╣рд╛рд░рд╛ рдХреЗ рд╕рд╛рде рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИред рдпрд╣ рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ рдЬрд╣рд╛рдВ рдЖрдк level рдФрд░/рдпрд╛ format рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред @DABH рдЖрдкрдХрд╛ рдкреБрд░рд╛рдирд╛ рдХреЛрдб рд╣реИ:

const winston = require('winston');
const format = winston.format;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new winston.transports.Console(),
  ],
});

logger.error(new Error('whatever'));

рдпрджрд┐ рдЖрдк рдЗрд╕реЗ рд╣рдЯрд╛рддреЗ рд╣реИрдВ:

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new winston.transports.Console(),
  ],
});

рдФрд░ рдЗрд╕реЗ рдЗрд╕рдХреЗ рд╕рд╛рде рдмрджрд▓реЗрдВ:

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      level: 'debug',
      format: format.combine(
        enumerateErrorFormat(),
        format.json()
      ),
    }),
  ],
});

рдлрд┐рд░ info.message === undefined рд╕рдорд╕реНрдпрд╛ рджрд┐рдЦрд╛рдИ рджреЗрддреА рд╣реИред рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдкрд░рд┐рд╡рд╣рди рдХреЗ рд▓рд┐рдП рд╕реНрддрд░ рдФрд░ рдкреНрд░рд╛рд░реВрдк рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рдареАрдХ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП; рдФрд░ рдореИрдВ рд▓рдЧрднрдЧ рдирд┐рд╢реНрдЪрд┐рдд рд╣реВрдВ рдХрд┐ рд╡рд┐рдВрд╕реНрдЯрди 2.0 рдореЗрдВ рдЗрд╕рдХреА рдЕрдиреБрдорддрд┐ рдереАред

рдореЗрд░реЗ рдХреЛрдб рдкрд░рд┐рд╡рд░реНрддрди рдХреЗ рд╕рд╛рде рдЖрдкрдХрд╛ рдХреЛрдб рдирдореВрдирд╛ рдпрд╣рд╛рдВ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рддрд╛рдХрд┐ рдЖрдк рдЖрд╕рд╛рдиреА рд╕реЗ рдЪрд▓рд╛ рд╕рдХреЗрдВ рдФрд░ рдкрд░реАрдХреНрд╖рдг рдХрд░ рд╕рдХреЗрдВ:

const winston = require('winston');
const format = winston.format;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      level: 'debug',
      format: format.combine(
        enumerateErrorFormat(),
        format.json()
      ),
    }),
  ],
});

logger.error(new Error('whatever'));

рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдЗрд╕рд╕реЗ рд╕рдорд╕реНрдпрд╛ рдХреА рдЬрдбрд╝ рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдореЗрдВ рдорджрдж рдорд┐рд▓реЗрдЧреАред

рдореИрдВрдиреЗ рдмрдирд╛рдпрд╛ https://github.com/winstonjs/winston/pull/1527

рдЗрд╕рдореЗрдВ рд╕рднреА рд╡рд┐рдХрд▓реНрдк рд╢рд╛рдорд┐рд▓ рд╣реИрдВред рд╣рд╛рд▓рд╛рдБрдХрд┐ рдХреБрдЫ рдкрд░реАрдХреНрд╖рдг рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВ рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЗрд╕реЗ рдЕрднреА рдХреЗ рд▓рд┐рдП рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ рд╣реИред рд╡рд┐рдлрд▓рддрд╛рдУрдВ рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХреА рдЙрдореНрдореАрдж рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдореИрдВ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рд╕рдВрд╢реЛрдзрди/рд╣рдЯрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╣реВрдВред

рдЕрд╕рдлрд▓ рдирд┐рд░реНрдорд╛рдг рдпрд╣рд╛рдБ рд╣реИ https://travis-ci.org/winstonjs/winston/jobs/453012141 рдФрд░ рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реИ рдХрд┐ рдЬрдм рдЖрдк рдкрд░реАрдХреНрд╖рдг рдХреЛрдб рдкрдврд╝рддреЗ рд╣реИрдВ рддреЛ рдкрд░реАрдХреНрд╖рдг рдЕрдм рд╡рд┐рдлрд▓ рдХреНрдпреЛрдВ рд╣реЛрддреЗ рд╣реИрдВ:
https://github.com/winstonjs/winston/blob/c42ab7fdc51b88db180a7dd90c52ce04ddd4e054/test/logger.test.js#L668

рд╡рд┐рдЪрд╛рд░?

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╕рдорд╕реНрдпрд╛ рдЗрд╕ рд▓рд╛рдЗрди рдореЗрдВ рд╣реИ
const рдЬрд╛рдирдХрд╛рд░реА = (рд╕рдВрджреЗрд╢ && !(msg instanceof Error) && msg.message && msg) || {
рд╕рдВрджреЗрд╢: рд╕рдВрджреЗрд╢
};
рдЙрджрд╛рд╣рд░рдг рдХреЗ рдПрдХ рдЪреЗрдХ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рд╕реЗ рддреНрд░реБрдЯрд┐ @crowleym рдмрд┐рдВрджреБ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рд▓рдЧрддреА рд╣реИ

рдХрд┐рд╕реА рдХреЗ рд▓рд┐рдП рднреА рдЬреЛ рдЕрднреА рднреА рдЗрд╕рд╕реЗ рдирд┐рдкрдЯ рд░рд╣рд╛ рд╣реИ, рдпрд╣ рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рдлреЙрд░реНрдореЗрдЯрд░ рд╣реИ рдЬрд┐рд╕рдХреЗ рд╕рд╛рде рдореИрдВ рдЖрдиреЗ рдореЗрдВ рдХрд╛рдордпрд╛рдм рд░рд╣рд╛ рд╣реВрдВ (рдореЗрд░реЗ рд▓реЙрдЧрд░.рдЬреЗрдПрд╕ рдореЙрдбреНрдпреВрд▓ рдХрд╛ рд╕реНрдирд┐рдкреЗрдЯ):

const { format, transports, createLogger }     = require("winston");
const { combine, timestamp, colorize, printf } = format;

function devFormat() {
    const formatMessage = info => `${info.level}: ${info.timestamp} ${info.message}`;
    const formatError   = info => `${info.level}: ${info.timestamp}\n\n${info.stack}\n`;
    const format        = info => info instanceof Error ? formatError(info) : formatMessage(info);

    return combine(timestamp(), printf(format));
}

рдХрд┐рд╕реА рдХрд╛рд░рдг рд╕реЗ logger.error(new Error("hello")) рдХреЗрд╡рд▓ рддрднреА рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм рдЖрдк winston.createLogger ЁЯдФ рдореЗрдВ рдлрд╝реЙрд░реНрдореЗрдЯрд░ рдХреЛ рд╡рд┐рд╢реНрд╡ рд╕реНрддрд░ рдкрд░ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдлрд┐рд░ рдЖрдкрдХреЛ рдлрд╝реЙрд░реНрдореЗрдЯрд░ рдореЗрдВ info рдореЗрдВ рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдорд┐рд▓рддрд╛ рд╣реИред

рдпрджрд┐ рдЖрдк рдкреНрд░рддрд┐ рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ рдПрдХ рдлреЙрд░реНрдореЗрдЯрд░ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЖрдкрдХреЛ logger.log({level: "error", message: new Error("FAILED")}) info рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдПрд░рд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдПрдХреНрд╕реЗрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП info.message рдорд╛рдзреНрдпрдо рд╕реЗ рдПрд░рд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд╣реИрдВрдбрд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдкрд░рд┐рд╡рд╣рди рд╡рд┐рдХрд▓реНрдкреЛрдВ рдореЗрдВ рдкреНрд░рд╛рд░реВрдк рдлрд╝реАрд▓реНрдб рд╕реЗрдЯ рдХрд░рддреЗ рд╕рдордп рдПрдХ рдмрдЧ рд╣реИ?

рд╡реЗ рд╕рд┐рд░реНрдл рдореЗрд░реЗ 2 рд╕реЗрдВрдЯ рд╣реИрдВ рдФрд░ рдореЗрд░реЗ рд▓рд┐рдП рдХреНрдпрд╛ рдХрд╛рдо рдХрд┐рдпрд╛ рд╣реИ, рдореИрдВ рд╡рд┐рдВрд╕реНрдЯрди рдХреЗ рд▓рд┐рдП рдирдпрд╛ рд╣реВрдВ рдФрд░ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рдЕрдиреБрднрд╡реА рдирд╣реАрдВ рд╣реВрдВ рдЗрд╕рд▓рд┐рдП рдореБрдЭреЗ рдХрд┐рд╕реА рднреА рдЪреАрдЬрд╝ рдкрд░ рдЙрджреНрдзреГрдд рди рдХрд░реЗрдВред

рдореЗрд░рд╛ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдореВрд▓ рдХрд╛рд░рдг рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдерд╛ред рд▓реЗрдХрд┐рди рдЗрд╕реЗ рд░реЗрдкреЛ рдорд╛рд▓рд┐рдХреЛрдВ рд╕реЗ рдЬреНрдпрд╛рджрд╛ рдХрд░реНрд╖рдг рдирд╣реАрдВ рдорд┐рд▓ рд░рд╣рд╛ рд╣реИ ...

рд╣рд╛рдБ, рдореИрдВ рдЗрд╕реЗ рд╕рдордЭрддрд╛ рд╣реВрдБред рдореИрдВрдиреЗ рд╕рдЪрдореБрдЪ рдЗрд╕рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдореЗрдВ рдмрд╣реБрдд рд╕рдордп рдмрд┐рддрд╛рдпрд╛ рдХреНрдпреЛрдВрдХрд┐ рдореИрдВ рд╡рд┐рдВрд╕реНрдЯрди рдХреЗ рд▓рд┐рдП рдирдпрд╛ рд╣реВрдВ рдФрд░ рдореБрдЭреЗ рд▓рдЧрд╛ рдХрд┐ рд╢рд╛рдпрдж рдореИрдВ рдЗрд╕реЗ рдЧрд▓рдд рддрд░реАрдХреЗ рд╕реЗ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдпрд╛ рдЗрд╕рдХреЗ рдкреАрдЫреЗ рдХреА рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдХреЛ рдЕрднреА рддрдХ рдареАрдХ рд╕реЗ рд╕рдордЭ рдирд╣реАрдВ рдкрд╛рдпрд╛ рд╣реВрдВред

рд▓реЗрдХрд┐рди рд╕реМрднрд╛рдЧреНрдп рд╕реЗ рдореИрдВ рдХреБрдЫ рдзрд╛рдЧреЛрдВ (рдЗрд╕рдореЗрдВ рд╢рд╛рдорд┐рд▓) рдкрд░ рдареЛрдХрд░ рдЦрд╛рдИ, рдЬреЛ рдореБрдЭреЗ рдЕрдиреНрдпрдерд╛ рджрд┐рдЦрд╛рддреА рдереАред рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рд╡реЗ рдЗрд╕реЗ рдареАрдХ рдХрд░ рд▓реЗрдВрдЧреЗ, рдЗрд╕рд▓рд┐рдП рдореБрдЭреЗ рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд░рд╣рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред

рдпрд╣ wintson-transport рдХрд╛рд░рдг рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рд╕рдорд╕реНрдпрд╛ рдХреЗ рд▓рд┐рдП https://github.com/winstonjs/winston-transport/issues/31 рджреЗрдЦреЗрдВ рдФрд░ https://github.com/winstonjs/winston-transport/pull/ рдПрдХ рдЬрдирд╕рдВрдкрд░реНрдХ рдХреЗ рд▓рд┐рдП

рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБрдУрдВ рдХреА рдкреНрд░рддреНрдпрдХреНрд╖ рд▓реЙрдЧрд┐рдВрдЧ рдЙрдирдХреЗ рдЧреИрд░-рдЧрдгрдирд╛ рдпреЛрдЧреНрдп рдЧреБрдгреЛрдВ рдХреЗ рдХрд╛рд░рдг рд╣рдореЗрд╢рд╛ рдПрдХ рдЧрдбрд╝рдмрдбрд╝ рд╣реЛрддреА рд╣реИред рд╡реНрдпрдХреНрддрд┐рдЧрдд рд░реВрдк рд╕реЗ рдореИрдВ рдЗрд╕реЗ рдПрдХ рдмреБрд░реА рдкреНрд░рдерд╛ рдорд╛рдирддрд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рд╕рдореБрджрд╛рдп рдореЗрдВ рдкрд░реНрдпрд╛рдкреНрдд рд▓реЛрдЧ рдЗрд╕реЗ рдПрдХ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдорд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рд╣рдореЗрдВ рдЗрд╕рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдЗрд╕ рддрд░рд╣ рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░реЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП https://github.com/winstonjs/logform/pull/59 рдХреЛ рдПрдХ рдкреНрд░рд╛рд░реВрдк рдХреЗ рд░реВрдк рдореЗрдВ рдЕрдкрдирд╛рдиреЗ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рдирд╛ред рдкреНрд▓рд╕ рддрд░рдл рдпрд╣ рд╕рднреА рдХрд┐рдирд╛рд░реЗ рдХреЗ рдорд╛рдорд▓реЛрдВ рдХреЛ рд╕рдорд╛рд╣рд┐рдд рдХрд░рддрд╛ рд╣реИ рдЬреЛ рд▓реЙрдЧ рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХрд╛ рдЗрд▓рд╛рдЬ рдХрд░рддреЗ рд╕рдордп рдмрд╣реБрдд рдЖрдо рд╣реИрдВред рдиреАрдЪреЗ рдХреА рддрд░рдл рдпрд╣ рдПрдХ рдФрд░ рдкреНрд░рд╛рд░реВрдк рд╣реЛрдЧрд╛ рдЬрд┐рд╕реЗ рд▓реЛрдЧреЛрдВ рдХреЛ рдСрдкреНрдЯ-рдЗрди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ (рдЗрд╕реА рддрд░рд╣ .splat() )

@indexzero рдореИрдВ рд╕рд╣рдордд рд╣реВрдВ рд▓реЗрдХрд┐рди рдХрд╕реНрдЯрдо рд▓реЙрдЧрд┐рдВрдЧ рдкреНрд░рд╛рд░реВрдк/ Error рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдореБрдЭреЗ рд╡рд┐рдВрд╕реНрдЯрди 2.x рдпрд╛рдж рдирд╣реАрдВ рд╣реИ рдЗрд╕ рдЕрднреНрдпрд╛рд╕ рд╕реЗ рд▓рдбрд╝реЗрдВ рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕реЗ рдмреЙрдХреНрд╕ рд╕реЗ рдмрд╛рд╣рд░ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдереАред

рддреЛ enumerateErrorFormat рдХреЗ рд▓рд┐рдП рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рд╕рдорд╛рдзрд╛рди рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рд▓реЗрдХрд┐рди logger.error('some message', err) рдкреНрд░рд╛рд░реВрдк рдХрд╛ рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдХреНрдпреЛрдВрдХрд┐ рди рддреЛ info.message рдпрд╛ info instanceof Error ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдореИрдВ рдЗрд╕ рд╕рдорд╛рдзрд╛рди рдХреЗ рд╕рд╛рде рдПрдХ рдФрд░ рдореБрджреНрджреЗ рдХреА рдУрд░ рдЗрд╢рд╛рд░рд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рдореИрдВ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдПрдХ рддреНрд░реБрдЯрд┐ рд▓реЙрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдЬреЛ superagent рд╕реЗ рд▓реМрдЯрд╛рдИ рдЧрдИ рд╣реИ

    try {
      const response = await request
        .get('https://some/endpoint')
        .set('Authorization', bearerToken);
      logger.info('successfully received response');
      return response.body;
    } catch (e) {
      logger.error('An error was caught while getting programs');
      logger.error(e); // <<< THE ERROR LOG  
    }

рдЕрдЧрд░ рд╣рдо рдХреЗрд╡рд▓ Object.assign рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рд╕реНрдЯреИрдХ рдХреЛ рдардВрдбрд╛ рдХрд░реЗрдВ рдФрд░ рд╕рдВрджреЗрд╢ рд╕реЗрдЯ рд╣реЛ рдЬрд╛рдПрдЧрд╛! рд▓реЗрдХрд┐рди, рдХреЛрдИ рдЕрдиреНрдп рдЬрд╛рдирдХрд╛рд░реА рдЬреЛ рддреНрд░реБрдЯрд┐ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдереА, рд╡рд╣ рднреА рд▓реЙрдЧ рд╣реЛ рдЬрд╛рдПрдЧреАред рдпрд╣ рдЙрди рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдмрд╣реБрдд рдЦрддрд░рдирд╛рдХ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдЬрд╣рд╛рдВ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдореЗрдВ рд╕рдВрд╡реЗрджрдирд╢реАрд▓ рдбреЗрдЯрд╛ рд╣реЛрддрд╛ рд╣реИ рдЬреИрд╕реЗ Authorization Headers (рдЬреЛ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБ рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд░реВрдк рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ)ред

рд▓реЗрдХрд┐рди рддрдм рдЖрдк рдХрд╣ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рд╡рд┐рдВрд╕реНрдЯрди рдХреА рдЧрд▓рддреА рдирд╣реАрдВ рд╣реИ, рдпрд╣ рд╡рд┐рдВрд╕реНрдЯрди рдХреА рдЧрд▓рддреА рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╕реБрдкрд░рдПрдЬреЗрдВрдЯ рдЗрд╕ рдбреЗрдЯрд╛ рдХреЛ рддреНрд░реБрдЯрд┐ рдореЗрдВ рдЬреЛрдбрд╝рддрд╛ рд╣реИред рдореИрдВ рд╕рд╣рдордд рд╣реВрдВ! рд╣рд╛рд▓рд╛рдБрдХрд┐, рдХреНрдпреЛрдВрдХрд┐ рд╕рдм рдХреБрдЫ info рдСрдмреНрдЬреЗрдХреНрдЯ рдкрд░ рд╕рдорд╛рди рд░реВрдк рд╕реЗ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реИ, рдкреБрд░рд╛рдиреА рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рд░рдЦрдирд╛ рдФрд░ рдмрд╛рдХреА рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдирд╣реАрдВ рдХрд░рдирд╛ рдмрд╣реБрдд рдореБрд╢реНрдХрд┐рд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред

рдпрд╣ рд▓рдЧрднрдЧ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐, logger.error рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордпред рдпрд╣ рдорд╛рди рд▓рд┐рдпрд╛ рдЧрдпрд╛ рдХрд┐ рджреВрд╕рд░рд╛ рдкрд░рдо рдерд╛ рдФрд░ рддреНрд░реБрдЯрд┐ рдереА рдФрд░ рдЗрд╕реЗ info рдСрдмреНрдЬреЗрдХреНрдЯ рдкрд░ info.error рдФрд░ рдлрд┐рд░ рджреВрд╕рд░реА рддрд░рдл рд▓реЙрдЧрд┐рдВрдЧ рдХрд░рддреЗ рд╣реБрдП, рдЗрдВрдЯрд░рдлрд╝реЗрд╕ { level: "error", error: YOUR ERROR OBJECT}

рдореИрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣рд╛рдВ рд╕рд┐рд░реНрдл рд╕реНрдкрд┐рдЯрдмреЙрд▓ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рд▓реЗрдХрд┐рди рдирдпрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдереЛрдбрд╝рд╛ рдирд┐рд░рд╛рд╢рд╛рдЬрдирдХ рд░рд╣рд╛ рд╣реИ (рдЬрд╛рдирдХрд╛рд░реА рдкрд░ рд╕рдм рдХреБрдЫ)ред

рдмрд╕ рдЙрд╕ рдмрд┐рдВрджреБ рдХреЛ рд╡рд┐рд╕реНрддреГрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЛ рдореИрдВ рдмрдирд╛ рд░рд╣рд╛ рдерд╛, рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдЖрдк logger.error( e ) рдЬрд╣рд╛рдВ рдИ рдкреНрд░рдХрд╛рд░ рдХреА рддреНрд░реБрдЯрд┐ рд╣реИред

рдлрд┐рд░ рдЖрдкрдХреЗ рдХреЛрдб рдореЗрдВ рдЖрдкрдиреЗ рд╡рд┐рдВрд╕реНрдЯрди рдХреЛ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рд╣реИ:

winston.configure({
    format: combine(
      timestamp(),
      enumerateErrorFormat(),
      ...
    ),
  });

рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБ object рдкрд░ рд╣рд┐рд▓рд╛рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИред рдХреНрдпрд╛ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИ? рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪреЗрдВ .. рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рднреЗрдЬреА рдЧрдИ рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБ рдХреЛ рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдПрдХ рдирдпрд╛ рдкреНрд░реЛрдк рдорд┐рд▓ рд░рд╣рд╛ рд╣реИ .. рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдкред

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рд╕рдорд╛рдзрд╛рди рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рд┐рдВрдЯреИрдХреНрд╕ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдирд╛ рд╣реЛрдЧрд╛:

logger.error('An error occurred when doing something important', { error: e } );

рдФрд░ рдлрд┐рд░ рдЖрдВрддрд░рд┐рдХ рд░реВрдк рд╕реЗ рдЖрдк рдПрдХ рддреНрд░реБрдЯрд┐ рдлрд╝реЙрд░реНрдореЗрдЯрд░ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рддреНрд░реБрдЯрд┐ рдлрд╝реАрд▓реНрдб рдХреА рддрд▓рд╛рд╢ рдХрд░рддрд╛ рд╣реИ!

рдЗрд╕ рдкрд░ рдЕрдкрдбреЗрдЯ рдХрд░реЗрдВ рд▓реЛрдЧ:

рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдЕрдЧрд▓реЗ рджреЛ рджрд┐рдиреЛрдВ рдореЗрдВ рдЗрд╕реЗ рд╕реАрд╡рди рдХрд░ рднреЗрдЬ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрд╣ рд╣рдорд╛рд░реЗ [email protected] рдЯреНрд░реИрдХрд░ рдореЗрдВ рдЕрдЧрд▓рд╛ рд╕реЗ рдЕрдВрддрд┐рдо рдЕрдВрдХ рд╣реИ

рд╣рд╛рдЙрдбреА рд▓реЛрдЧ - рдХреГрдкрдпрд╛ https://github.com/winstonjs/winston/pull/1562 рджреЗрдЦреЗрдВред рдпрд╣ рд╣рдорд╛рд░реА 3.2.0 рд░рд┐рд▓реАрдЬ рдЪреЗрдХ рд▓рд┐рд╕реНрдЯ рдкрд░ рдЖрдЦрд┐рд░реА рдЖрдЗрдЯрдо рдерд╛ рддрд╛рдХрд┐ рдПрдХ рдмрд╛рд░ рдкреАрдЖрд░ рдХреЛ рд╕реАрд╡рди рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рд╣рдо рд░рд┐рд▓реАрдЬ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдВрдЧреЗред

рдЬрдм рддрдХ рдХреЛрдИ рд╕рдорд╛рдзрд╛рди рдкреНрд░рдХрд╛рд╢рд┐рдд рдирд╣реАрдВ рд╣реЛ рдЬрд╛рддрд╛, рдореИрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рдорд╛рдзрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ:

logger.error = item => {
  logger.log({ level: 'error', message: item instanceof Error ? item.stack : item });
};

рдореИрдВ рдирд╡реАрдирддрдо рд╡рд┐рдВрд╕реНрдЯрди (3.2.1) рдкрд░ рд╣реВрдВ рдФрд░ рдЕрднреА рднреА undefined рдкреНрд░рд╛рдкреНрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдЬрдм logger.error рддреНрд░реБрдЯрд┐ рд╣реЛ рд░рд╣реА рд╣реИ

@ezze рдХрд╛ рдПрдХ рдЕрдЪреНрдЫрд╛ рд╕рдорд╛рдзрд╛рди рдерд╛ рд▓реЗрдХрд┐рди рд╕реНрдЯреИрдХ рдЯреНрд░реЗрд╕ рдХреЛ рдПрдХ рдирдИ рд▓рд╛рдЗрди рдкрд░ рдордЬрдмреВрд░ рд╣реЛрдирд╛ рдкрдбрд╝рд╛ред рдпрд╣рд╛рдБ рдереЛрдбрд╝рд╛ рд╕рдВрд╢реЛрдзрд┐рдд рд╕рдВрд╕реНрдХрд░рдг рд╣реИ рдЬреЛ рдЗрд╕реЗ рдПрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рд░рдЦрддрд╛ рд╣реИ (рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рд▓реЙрдЧ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд╕рд╛рдзрд╛рд░рдг grep рджреНрд╡рд╛рд░рд╛ рдкрдХрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИ)

logger.error = item => {
  const message = item instanceof Error
    ? item.stack.replace('\n', '').replace('    ', ' - trace: ')
    : item;
  logger.log({ level: 'error', message });
};

рдЖрдЙрдЯрдкреБрдЯ рдХреЗ рд╕рд╛рде <Error message> - trace: <stack trace>

рдЕрдЧрд░ рдирд╡реАрдирддрдо рд╡рд┐рдВрд╕реНрдЯрди рдХреЗ рд╕рд╛рде рдРрд╕рд╛ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рдЖрд╕рд╛рди рддрд░реАрдХрд╛ рд╣реИ рддреЛ рдХреГрдкрдпрд╛ рдореБрдЭреЗ @indexzero рдмрддрд╛рдПрдВред рдореИрдВ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореЗрдВ рдирдпрд╛ рд╣реВрдБ рдФрд░ рдбреЙрдХреНрд╕ рдХрд╛ рдкрд╛рд▓рди рдХрд░ рд░рд╣рд╛ рдерд╛

рдореИрдВрдиреЗ рдЕрднреА рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рдкреАрдЖрд░ рдХреЛ рдкреЛрд╕реНрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд▓рд┐рдВрдХ рджреЗрдЦрд╛ рд╣реИред рдХреНрдпрд╛ рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рд╣реИ рдХрд┐ рдХрд┐рд╕реА рддреНрд░реБрдЯрд┐ рдХреЛ logger.error рд▓рд┐рдП рдПрдХ рд╕рдВрджреЗрд╢ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдлрд┐рд░ рддреНрд░реБрдЯрд┐?

try {
  someThing();
} catch(error) {
  logger.error(error); // what I would like to do
  logger.error('special message', error); // what I believe is required?
}

@ the-vampiire рдЗрд╕ рдзрд╛рдЧреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдиреЗ рд╡рд╛рд▓реА 2 рд╕рдорд╕реНрдпрд╛рдПрдВ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдИрдВред рдкрд╣рд▓рд╛ рдЬреЛ рдореВрд▓ рдкреЛрд╕реНрдЯрд░ рд▓рд╛рдпрд╛ рдЧрдпрд╛ рдерд╛, рдФрд░ рджреВрд╕рд░рд╛ рд╡рд╣ рд╕рдорд╕реНрдпрд╛ рдЬреЛ рдореИрдВрдиреЗ рд▓рд╛рдИ рдереА рдЬреЛ рдЖрдкрдХреА рд╕рдорд╕реНрдпрд╛ рдХреЗ рд╕рдорд╛рди рд╣реИред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЙрдиреНрд╣реЛрдВрдиреЗ рдХреЗрд╡рд▓ рдореВрд▓ рдкреЛрд╕реНрдЯрд░ рд╕рдорд╕реНрдпрд╛ рдХреЛ рдареАрдХ рдХрд┐рдпрд╛ред рдореЗрд░рд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ рдФрд░ рдпрджрд┐ рдРрд╕рд╛ рд╣реИ рддреЛ рдПрдХ рдирдпрд╛ рдореБрджреНрджрд╛ рдЦреЛрд▓реЗрдВред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ рдореЗрд░реЗ рдкрд╛рд╕ рдЧрд╣рд░рд╛ рдЧреЛрддрд╛ рд▓рдЧрд╛рдиреЗ рдХрд╛ рд╕рдордп рдирд╣реАрдВ рд╣реИред рдЗрд╕ рдмреАрдЪ, рдпрджрд┐ рдЖрдк logger.log({level: 'error', message: err}); рдЬрд╣рд╛рдВ err рдПрдХ рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБ рд╣реИ рддреЛ рдпрд╣ рдХрд╛рдо рдХрд░реЗрдЧрд╛ред

рдЕрднреА рднреА рдпрд╣ рд╕рдорд╕реНрдпрд╛ рд╣реИ, рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдордп рдХрд╛ рдЧреБрдЪреНрдЫрд╛ рдЦреЛ рдЧрдпрд╛ рд╣реИ, @ the-vampiire рдХрд╛ рд╕рдорд╛рдзрд╛рди рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

рдпрд╣ рдЯрд┐рдХрдЯ рдХреНрдпреЛрдВ рдмрдВрдж рд╣реИ?

logger.error рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдирд╛ рдЕрдм рддрдХ рдХрд╛ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рд╕рдорд╛рдзрд╛рди рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдПрд░рд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдкреНрд░реЙрдкрд░реНрдЯреА рдирд╣реАрдВ рдЬреЛрдбрд╝рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдПрд░рд░ () рдХреЗ рд▓рд┐рдП рд╕рд┐рдВрдЧрд▓ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЬреНрдпрд╛рджрд╛рддрд░ рд▓реЛрдЧ рдЙрдореНрдореАрдж рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБрдПрдВ рдЕрдкрд░рд┐рд╡рд░реНрддрдиреАрдп рд╣реИрдВред рдпрджрд┐ рдЖрдк logger.info рдФрд░ рдЕрдиреНрдп рд╕рднреА рд╕реНрддрд░реЛрдВ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рднреА рдУрд╡рд░рд░рд╛рдЗрдб рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдЖрд╢реНрдЪрд░реНрдп рдХреА рдмрд╛рдд рд╣реИ рдХрд┐ рдЪреАрдЬреЗрдВ рдЕрдкреЗрдХреНрд╖рд╛ рдХреЗ рдЕрдиреБрд░реВрдк рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддреА рд╣реИрдВред рджреЛрдмрд╛рд░рд╛, рдЬрдм рддрдХ рдЖрдк рдЕрдкрдиреА рд╡рд╕реНрддреБ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ, рдЪрд╛рд╣реЗ рдЙрд╕рдХрд╛ рдкреНрд░рдХрд╛рд░ рдХреЛрдИ рднреА рд╣реЛ, рдЗрд╕реЗ рд╕реАрдзреЗ рд╡рд┐рдВрд╕реНрдЯрди рд▓реЙрдЧрд░ рд╡рд┐рдзрд┐ рдкрд░ рди рднреЗрдЬреЗрдВред

рдпрд╣ рд╕реБрд╡рд┐рдзрд╛ рд╡рд┐рдВрд╕реНрдЯрди@3.2.0 . рдХреЗ рдмрд╛рдж рд╕реЗ рд╕рдорд░реНрдерд┐рдд

рдЙрджрд╛рд╣рд░рдг рдЙрдкрдпреЛрдЧ:

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

рдореИрдВ рдЕрднреА рднреА рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рдЪрд▓ рд░рд╣рд╛ рд╣реВрдВред
рдЬрдм рдореИрдВ logger.error(error); рдЬреИрд╕реА рддреНрд░реБрдЯрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ рдХреЗрд╡рд▓ undefined ред
рдХреЗрд╡рд▓ рдЕрдЧрд░ рдореИрдВ рдЗрд╕реЗ logger.error('Something went wrong', error) рддрд░рд╣ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ рдкреВрд░реА рддреНрд░реБрдЯрд┐ рдорд┐рд▓рддреА рд╣реИ рдФрд░ рдЗрд╕реЗ рдкрд╛рд░реНрд╕ рдХрд░ рд╕рдХрддрд╛ рд╣реИред

рдореИрдВ рдЕрднреА рднреА рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рдЪрд▓ рд░рд╣рд╛ рд╣реВрдВред
рдЬрдм рдореИрдВ logger.error(error); рдЬреИрд╕реА рддреНрд░реБрдЯрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ рдХреЗрд╡рд▓ undefined ред
рдХреЗрд╡рд▓ рдЕрдЧрд░ рдореИрдВ рдЗрд╕реЗ logger.error('Something went wrong', error) рддрд░рд╣ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ рдкреВрд░реА рддреНрд░реБрдЯрд┐ рдорд┐рд▓рддреА рд╣реИ рдФрд░ рдЗрд╕реЗ рдкрд╛рд░реНрд╕ рдХрд░ рд╕рдХрддрд╛ рд╣реИред
рдХреНрдпрд╛ рдЖрдкрдиреЗ рдЗрд╕реЗ рдЬреЛрдбрд╝рд╛?

format.errors({ stack: true })

рд╣рд╛рдБ, рдЕрднреА рднреА рд╡рд╣реА рдореБрджреНрджрд╛ред рдореИрдВ рдЗрд╕реЗ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рдкреБрди: рдкреЗрд╢ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддрд╛ рд╣реВрдВред

@ OBrown92 рдореБрдЭреЗ рдЖрдЬ рднреА рдЗрд╕реА рдореБрджреНрджреЗ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рд╛ рд╣реИред рдореИрдВ рдкреБрд╖реНрдЯрд┐ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдЕрдЧрд░ format.errors({ stack: true }) , рд▓реЙрдЧрд░ рдкрд░ рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИ, рдкрд░рд┐рд╡рд╣рди рдХреЗ рд▓рд┐рдП рдирд╣реАрдВред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ logger.error(error); рдФрд░ logger.error('Something went wrong', error) рджреЛрдиреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ, рдЬрдм рдореИрдВ рдЪреБрдиреЗ рд╣реБрдП рдкрд░рд┐рд╡рд╣рди рдХреЗ рд▓рд┐рдП format.errors({ stack: true }) рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реВрдВред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдореБрдЭреЗ undefined рд▓рд┐рдП logger.error(error); , рд▓реЗрдХрд┐рди logger.error('Something went wrong', error) рдареАрдХ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдпрд╣ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реИ рдпрд╛ рдпрд╣ рдПрдХ рдмрдЧ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдЗрд╕рдХрд╛ рдХрд╛рд░рдг рдЦреЛрдЬрдиреЗ рдореЗрдВ рдмрд╣реБрдд рд╕рдордп рдмрд┐рддрд╛рдпрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдХреГрдкрдпрд╛ рдЗрд╕реЗ рдареАрдХ рдХрд░реЗрдВ рдпрд╛ рдЕрдкрдиреЗ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдореЗрдВ рдХрд╣реАрдВ рдЗрд╕рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд░реЗрдВред рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдорджрджрдЧрд╛рд░ рд╣реЛрдЧрд╛ред

рд╡реИрд╕реЗ рднреА, рдореИрдВ рдЗрд╕ рдорд╣рд╛рди рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ рдЖрдкрдХреЗ рдХрд╛рдо рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЖрднрд╛рд░реА рд╣реВрдВред

рдореИрдВ рдЙрд╕реА рдореБрджреНрджреЗ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░ рд░рд╣рд╛ рдерд╛ рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдпрд╣ рдкреИрдХреЗрдЬ рд▓рд┐рдЦрд╛, utils-deep-clone ред рдЗрд╕рдХреА рдЬрд╛рдВрдЪ - рдкрдбрд╝рддрд╛рд▓ рдХрд░реЗрдВред

format.errors is not a function ... рдареАрдХ рд╣реИ, рдпрд╣ рдЖрд╢реНрдЪрд░реНрдп рдХреА рдмрд╛рдд рд╣реИред

@ рд╣реЛрд▓реНрдореНрдмрд░рдб
рдХреНрдпрд╛ рдЖрдкрдиреЗ рд╡рд┐рдВрд╕реНрдЯрди рдкреИрдХреЗрдЬ рд╕реЗ рдкреНрд░рд╛рд░реВрдк рдЖрдпрд╛рдд рдХрд┐рдП рд╣реИрдВ?
рдЙрджрд╛рд╣рд░рдг рдЙрдкрдпреЛрдЧ:
const { format } = require('winston')
рдпрд╛
const winston = require('winston'); const { format } = winston;

@aybhalala yepp, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдЗрд╕рд╕реЗ рдХреЛрдИ рдлрд░реНрдХ рдирд╣реАрдВ рдкрдбрд╝рддрд╛ рдХрд┐ рддреНрд░реБрдЯрд┐ рд╕реНрдЯреИрдХ рдХреЛ рдЗрд╕рдХреЗ рдмрд┐рдирд╛ printf рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

рдЕрджреНрдпрддрди: рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХреЗ рд╕рд╛рде рдЕрднреА рднреА рд╕рдорд╕реНрдпрд╛рдПрдВ рд╣реИрдВ, рдореИрдВ рдереЛрдбрд╝реА рджреЗрд░ рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ

// Grab the default winston logger
const winston = require('winston');

const { format } = winston;
const { combine, timestamp } = format;

// Custom format function that will look for an error object and log out the stack and if 
// its not production, the error itself
const myFormat = format.printf((info) => {
  const { timestamp: tmsmp, level, message, error, ...rest } = info;
  let log = `${tmsmp} - ${level}:\t${message}`;
  // Only if there is an error
  if ( error ) {
    if ( error.stack) log = `${log}\n${error.stack}`;
    if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
  }
  // Check if rest is object
  if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
    log = `${log}\n${JSON.stringify(rest, null, 2)}`;
  }
  return log;
});

 winston.configure({
    transports: [
      new winston.transports.Console({
        level: 'debug',
        timestamp: true,
        handleExceptions: true
    }),
  ];
    format: combine(
      trace(),
      timestamp(),
      myFormat
    ),
  });


// Finally you log like this
logger.error('An error occurred!!!', { error } );

^^ рд╡рд╣ рдЕрдкреЗрдХреНрд╖рд┐рдд рдЙрдкрдпреЛрдЧ рд╣реИред рдЪреВрдВрдХрд┐ рдХреЗрд╡рд▓ рдирд╢реНрд╡рд░ рд▓реЛрдЧ рдЗрд╕рдХрд╛ рдкрддрд╛ рдирд╣реАрдВ рд▓рдЧрд╛ рдкрд╛рдПрдВрдЧреЗ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдкреНрд░рд▓реЗрдЦрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдЪреВрдВрдХрд┐ рдХреЗрд╡рд▓ рдирд╢реНрд╡рд░ рд▓реЛрдЧ рдЗрд╕рдХрд╛ рдкрддрд╛ рдирд╣реАрдВ рд▓рдЧрд╛ рдкрд╛рдПрдВрдЧреЗ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдкреНрд░рд▓реЗрдЦрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП

ЁЯШВ рдЙрд╕ рд╕рд╛рдереА рдХреЛ +1

рдореИрдВ рддреАрд╕рд░реЗ рдкрдХреНрд╖ рдХреЗ рдкрд░рд┐рд╡рд╣рди ( @google-cloud/logging-winston ) рдХреЗ рд╕рд╛рде рд╡рд┐рдВрд╕реНрдЯрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ, рдЗрд╕рд▓рд┐рдП рдореЗрд░реЗ рдкрд╛рд╕ рд╡рд╛рдХреНрдпрд╡рд┐рдиреНрдпрд╛рд╕ рдкрд░ рдереЛрдбрд╝рд╛ рдХрдо рдирд┐рдпрдВрддреНрд░рдг рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдореБрдЭреЗ рдпрд╣ рдФрд░ рдЕрдзрд┐рдХ рд╕рд╣рдЬ рдЬреНрдЮрд╛рди рдпреБрдХреНрдд рд▓рдЧрддрд╛ рд╣реИ:

const error = new Error('something bad happened');
logger.error('was doing this and', error);

рдХрдВрд╕реЛрд▓ рдкрд░ рд▓реЙрдЧ рдЗрди рдХрд░рддреЗ рд╕рдордп рдореИрдВ рд╕рдВрджреЗрд╢ рдкрд░ рд╕реНрдЯреИрдХ рдХреЛ рдЬреЛрдбрд╝рддрд╛ рд╣реВрдВред рд▓реЗрдХрд┐рди рдкрд░рд┐рдгрд╛рдо рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рд╣реИ:

ERROR was doing this andsomething bad happened Error: something bad happened <rest of the stack.>

рдЪреВрдВрдХрд┐ рд╡рд┐рдВрд╕реНрдЯрди рдореВрд▓ рд╕рдВрджреЗрд╢ рдкрд░ meta.message рдХреЛ рдЬреЛрдбрд╝рддрд╛ рд╣реИ, рдЕрдЬреАрдм andsomething рдФрд░ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рд╕рдВрджреЗрд╢ рд╣реИ рдЬреЛ рд╕реНрдЯреИрдХ рдореЗрдВ рднреА рдореБрджреНрд░рд┐рдд рд╣реЛрддрд╛ рд╣реИред рдпрд╣ #1660 рдореЗрдВ рд╡рд░реНрдгрд┐рдд рд╣реИред

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ #1664 рдЗрд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реИред рдЗрд╕ рдмреАрдЪ, рдореИрдВрдиреЗ рдПрдХ рдлреЙрд░реНрдореЗрдЯрд░ рд▓рд┐рдЦрд╛ рдЬреЛ рдЙрд╕ рд╕рдВрдпреЛрдЬрди рдХреЛ "рдкреВрд░реНрд╡рд╡рдд" рдХрд░рддрд╛ рд╣реИ: https://github.com/winstonjs/winston/issues/1660#issuecomment -512226578

@dandv

logger.error('Caught error:', e);

рдпрд╣ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рдХреНрдпреЛрдВрдХрд┐, console.log() рд╡рд┐рдкрд░реАрдд, рд╡рд┐рдВрд╕реНрдЯрди рдХрд╛ logger.<level>(message) рдХреЗрд╡рд▓ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рд▓реЗрддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╕рдВрджреЗрд╢ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рд╡рд╣ рд╕рдВрджреЗрд╢ рдкреИрд░рд╛рдореАрдЯрд░ рдпрд╛ рддреЛ рдПрдХ рд╡рд╕реНрддреБ рдпрд╛ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИ (рдЕрдЧрд░ рдореИрдВ рдЧрд▓рдд рд╣реВрдВ рддреЛ рдХреЛрдИ рдореБрдЭреЗ рд╕рд╣реА рдХрд░реЗрдЧрд╛ рд▓реЗрдХрд┐рди рдпрд╣ рдореЗрд░реА рд╕рдордЭ рд╣реИ)ред

рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЖрдк logger.log({level: <level>, message: <message>}) рднреА рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрди рджреЛ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдореИрдВ рдбреЙрдХреНрд╕ рдХреЗ рдЗрд╕ рднрд╛рдЧ рдХреЛ рдкрдврд╝рдиреЗ рдХреА рд╕рд┐рдлрд╛рд░рд┐рд╢ рдХрд░реВрдВрдЧрд╛: рд╡рд┐рдВрд╕реНрдЯрди рдбреЙрдХреНрд╕ рдСрди рд▓реЙрдЧ рд▓реЗрд╡рд▓ ред рд▓реЙрдЧрд┐рдВрдЧ рд╕реНрддрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрдврд╝рдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ

logger.error(`Caught error: ${e}`);

рдореИрдВ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдпрд╣ рдирд╣реАрдВ рдХрд╣ рд╕рдХрддрд╛ рдХрд┐ рдпрд╣ рд╕реНрдЯреИрдХ рдХреЛ рдЖрдЙрдЯрдкреБрдЯ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╡рд┐рдВрд╕реНрдЯрди рдХреЗ рд╕рд╛рде рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИред рдпрджрд┐ рдЖрдк console.log(`Caught error: ${e}`) рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЗрд╕рдореЗрдВ рд╕реНрдЯреИрдХ рднреА рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдореИрдВрдиреЗ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рд▓рд┐рдЯрд░рд▓реНрд╕ рдХреЗ рд╕рд╛рде рдмрд╣реБрдд рдЕрдзрд┐рдХ рдХрд╛рдо рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╛ рддреЛ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рд▓рд┐рдЯрд░рд▓реНрд╕ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рд╕рд╛рде рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рдпрд╛ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдХрдВрд╕реЛрд▓.рд▓реЙрдЧ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдПрдХ рдПрд░рд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╣рдЪрд╛рдирддрд╛ рд╣реИ рдФрд░ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреЗрд╡рд▓ рдореИрд╕реЗрдЬ рдкреНрд░реЙрдкрд░реНрдЯреА рдХреЛ рдЖрдЙрдЯрдкреБрдЯ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдореЗрд░рд╛ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рдЕрдиреБрдорд╛рди рд╣реИред

logger.error(`Caught error: ${JSON.stringify(e)}`)

рдпрд╣ рдмрдЧ рдереНрд░реЗрдб рдХрд┐рд╕ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИ, рдЗрд╕рдХреЗ рджрд┐рд▓ рдореЗрдВ рдЙрддрд░ рдЬрд╛рддрд╛ рд╣реИред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рддрдХрдиреАрдХреА рд╡рд┐рд╡рд░рдгреЛрдВ рдХреЛ рд╕рдордЭрдирд╛ рд╣реЛрдЧрд╛ред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрджрд┐ рдЖрдк console.log(`Caught error: ${JSON.stringify(e)}`) рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЖрдкрдХреЛ рд╡рд╣реА рдЖрдЙрдЯрдкреБрдЯ Caught error: {} рднреА рдорд┐рд▓рддрд╛ рд╣реИред рдЬреИрд╕рд╛ рдХрд┐ @indexzero рдиреЗ рд╕рдордЭрд╛рдпрд╛:

message рдФрд░ stack рдкрд░ Error stack рдЧреБрдг рдЧреИрд░-рдЧрдгрдирд╛ рдпреЛрдЧреНрдп рд╣реИрдВ рдЬреЛ JSON.stringify рдХреЛ рдХреБрдЫ рдРрд╕рд╛ рдЖрдЙрдЯрдкреБрдЯ рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░рдг рдмрдирддрд╛ рд╣реИ рдЬрд┐рд╕рдХреА рдХреЛрдИ рдЙрдореНрдореАрдж рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред

рдореВрд▓ рд░реВрдк рд╕реЗ, рдХреНрдпреЛрдВрдХрд┐ message рдФрд░ stack рдЧреБрдг рдЧреИрд░-рдЧрдгрдирд╛ рдпреЛрдЧреНрдп рд╣реИрдВ, JSON.stringify рдЙрди рдЧреБрдгреЛрдВ рдкрд░ рдЫреЛрдбрд╝ рджреЗрддрд╛ рд╣реИ рдЬреЛ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдЖрдк рдПрдХ рдЦрд╛рд▓реА рд╡рд╕реНрддреБ рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рд╣реЛрддреЗ рд╣реИрдВ {} ред рдПрдиреНрдпреВрдорд░реЗрдмрд┐рд▓рд┐рдЯреА рдХреЛ рдмреЗрд╣рддрд░ рдврдВрдЧ рд╕реЗ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдореИрдВ рдЗрд╕ рдПрдиреНрдпреВрдорд░реЗрдмрд┐рд▓рд┐рдЯреА рдФрд░ рдкреНрд░реЙрдкрд░реНрдЯреА рдХреЗ рд╕реНрд╡рд╛рдорд┐рддреНрд╡ рдХреЛ рдкрдврд╝рдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВред

рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, рдЬрд┐рд╕ рддрд░рд╣ рд╕реЗ рд╡рд┐рдВрд╕реНрдЯрди 3.0 рдХреЛ рдбрд┐рдЬрд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ (рд╡рд┐рдВрд╕реНрдЯрди рдЯреАрдо рдХреЗ рд▓рд┐рдП рд╕рд╣рд╛рд░рд╛) рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рд╣реИ рдЬреЛ @indexzero рдиреЗ рджрд┐рдпрд╛ рдерд╛ред рдореИрдВ рдЗрд╕реЗ рд╕рдордЭрд╛рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реВрдВрдЧрд╛ред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдЖрдк рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛рдПрдВ:

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

рдбреЙрдХреНрд╕ рд╕реНрдЯреНрд░реАрдо, рдСрдмреНрдЬреЗрдХреНрдЯрдореЛрдб, рдФрд░ рдЬрд╛рдирдХрд╛рд░реА рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реЗ рдЬрд╛рдирдХрд╛рд░реА рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рджреЛ рдЧреБрдг рд╣реИрдВ, info.level , рдФрд░ info.message ред рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ info.message рд╕рдВрдкрддреНрддрд┐ рддреНрд░реБрдЯрд┐ рдЙрджреНрджреЗрд╢реНрдп рдпрд╣ рд╣реИ рдХрд┐ рдЕрдЧрд░ рдЖрдк рд╕рднреА рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд░ рджрд┐рдпрд╛ рд╣реИред рддреЛ рд╣рдо рдПрдХ рдирдИ рд╡рд╕реНрддреБ рдмрдирд╛рдиреЗ рдЬрд╣рд╛рдВ message.stack рдФрд░ message.message (рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдордЭреЗрдВ Error.stack рдФрд░ Error.message ) рдЕрдм рдЧрдгрдирд╛ рдпреЛрдЧреНрдп рд╣реИрдВ, рдФрд░ рд╣рдо рдЙрди рдЕрдиреНрдп рдЧреБрдгреЛрдВ рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рдЙрд╕ рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реЗ рднреА рд╕рдВрд▓рдЧреНрди рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред

рдЖрдЧреЗ рдЖрдк рдЗрд╕ рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдХреЛ рдмрдирд╛рдПрдВрдЧреЗ рдЬреЛ рдКрдкрд░ рджрд┐рдП рдЧрдП enumerateErrorFormat() рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ:

const logger = createLogger({
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new transports.Console()
  ]
});

рдЗрд╕рдореЗрдВ рдЬреЛ рдХреБрдЫ рднреА message рдЖрдк рдкрд╛рд╕ рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЬрд╛рдВрдЪ рд▓реЗрдВрдЧреЗ рдХрд┐ рдпрд╣ рдПрдХ рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБ рд╣реИ рдпрд╛ рдирд╣реАрдВред рдЕрдЧрд░ рдРрд╕рд╛ рд╣реИ рддреЛ рдпрд╣ рдЧрдгрдирд╛ рдХреА рд╕рдорд╕реНрдпрд╛ рдХреЛ рдареАрдХ рдХрд░ рджреЗрдЧрд╛ред рдлрд┐рд░ рдпрд╣ format.json рд╕рдВрджреЗрд╢ рднреЗрдЬрддрд╛ рд╣реИ рдЬреЛ рдХрд┐рд╕реА рднреА рд╡рд╕реНрддреБ (рддреНрд░реБрдЯрд┐ рдпрд╛ рдирд╣реАрдВ) рдХреЛ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХрд░реЗрдЧрд╛ред рдпрджрд┐ рдпрд╣ рдХреЛрдИ рд╡рд╕реНрддреБ рдирд╣реАрдВ рд╣реИ рддреЛ рдпрд╣ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИ рдФрд░ format.json effectivley рдХреБрдЫ рднреА рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдЖрдк рдШрд░ рдореБрдХреНрдд рд╣реИрдВ!

рдлрд┐рд░ рднреА, рдпрд╣ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рд╣рдореЗрдВ рд╡рд╣ enumerateErrorFormat рдирд╣реАрдВ рдмрдирд╛рдирд╛ рдкрдбрд╝реЗ рдХреНрдпреЛрдВрдХрд┐ рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдЖрдорддреМрд░ рдкрд░ рд▓реЙрдЧ рд╣реЛрддреЗ рд╣реИрдВред рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВ рд╕рдордЭрддрд╛ рд╣реВрдВ рдХрд┐ рд╡рд┐рдВрд╕реНрдЯрди рдЯреАрдо рдПрдХ рдлрд┐рдХреНрд╕ рдкрд░ рдХрд╛рдо рдХрд░ рд░рд╣реА рд╣реИ рдЬрд┐рд╕реЗ рдмрд╛рдж рдХреЗ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдЬрд╛рд░реА рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рдХреБрдЫ рдЕрдВрддрд┐рдо рдиреЛрдЯред рдпрд╣ рдХреЗрд╡рд▓ рддрднреА рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм рдЖрдк logger.log({level: <level>, message: <message>}) рдЬрд╣рд╛рдВ рд╕рдВрджреЗрд╢ рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБ рд╣реИред рдЙрджрд╛рд╣рд░рдг:

try {
  throw(new Error('This should work'));
} catch (err) {
  logger.log({level: 'error', message: err});
}

рд╡рд┐рдВрд╕реНрдЯрди рдореЗрдВ рдПрдХ рдФрд░ рдмрдЧ рд╣реИ рдЬрд╣рд╛рдВ рдпрд╣ рдХреЛрдб рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рдЙрдкрд░реЛрдХреНрдд рдореЗрд░реА рдЕрдиреНрдп рдкреЛрд╕реНрдЯ рдореЗрдВ рдмрддрд╛рдпрд╛ рд╣реИ:

try {
  throw(new Error('This will not work'));
} catch (err) {
  logger.error(err);
}

рдЬрдм рд╣рдо logger.error(err) рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдХрд┐рд╕реА рдХрд╛рд░рдг рд╕реЗ info.message рд╕рдВрдкрддреНрддрд┐ рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд рд╣реЛрддреА рд╣реИред рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ @indexzero рдЗрд╕рдХрд╛ рдкрддрд╛

рдмрд╣реБрдд рдЕрдЪреНрдЫреА рд╡реНрдпрд╛рдЦреНрдпрд╛, рдореИрдВ рдмрд╕ рдЗрд╕реЗ logger.error( рд╕рд╛рде рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рддреНрд░реБрдЯрд┐: ${e} ); рдЬрд┐рд╕ рддрд░рд╣ рд╕реЗ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╢рд╛рдмреНрджрд┐рдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, `${e}` рдЖрдк рд╕реНрдЯреИрдХ рдЦреЛ рджреЗрддреЗ рд╣реИрдВ e.toString() рдЬреИрд╕рд╛ рд╣реА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдХреЗрд╡рд▓ рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рдкреНрд░рд┐рдВрдЯ рдХрд░рдирд╛ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реИред

рдпрд╣ рдЕрднреА рднреА рдПрдХ рдореБрджреНрджрд╛ рд╣реИ? рдореБрдЭреЗ рдЕрднреА рднреА рдЗрд╕рд╕реЗ рд╕рдорд╕реНрдпрд╛ рд╣реЛ рд░рд╣реА рд╣реИ:

const { createLogger, format, transports } = require('winston')

const { combine } = format

const errorFormatter = format((info) => {
  console.log(info)
  return info
})


const consoleTransport = new transports.Console({
  format: combine(errorFormatter()),
})

const logger = createLogger({
  transports: [
    consoleTransport,
  ],
})

try {
  throw new Error('Error message')
} catch(err) {
  logger.error(err) // info doesnt have the error object
  logger.error('', err) // info have the error object
}

рдпрд╣ рдЕрднреА рднреА рдПрдХ рдореБрджреНрджрд╛ рд╣реИ? рдореБрдЭреЗ рдЕрднреА рднреА рдЗрд╕рд╕реЗ рд╕рдорд╕реНрдпрд╛ рд╣реЛ рд░рд╣реА рд╣реИ:

const { createLogger, format, transports } = require('winston')

const { combine } = format

const errorFormatter = format((info) => {
  console.log(info)
  return info
})


const consoleTransport = new transports.Console({
  format: combine(errorFormatter()),
})

const logger = createLogger({
  transports: [
    consoleTransport,
  ],
})

try {
  throw new Error('Error message')
} catch(err) {
  logger.error(err) // info doesnt have the error object
  logger.error('', err) // info have the error object
}

рд╡рд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реИ...

рд╕реНрд░реЛрдд рдХреЛрдб рджреЗрдЦрдиреЗ рдХреЗ рдмрд╛рдж, рдореИрдВ рджреЗрдЦ рд╕рдХрддрд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ рдХреМрди рд╕реЗ рдкреИрд░рд╛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ:

рдЗрдВрдЯрд░рдлрд╝реЗрд╕ LeveledLogMethod {
(рд╕рдВрджреЗрд╢: рд╕реНрдЯреНрд░рд┐рдВрдЧ, рдХреЙрд▓рдмреИрдХ: рд▓реЙрдЧрдХреЙрд▓рдмреИрдХ): рд▓рдХрдбрд╝рд╣рд╛рд░рд╛;
(рд╕рдВрджреЗрд╢: рд╕реНрдЯреНрд░рд┐рдВрдЧ, рдореЗрдЯрд╛: рдХреЛрдИ рднреА, рдХреЙрд▓рдмреИрдХ: рд▓реЙрдЧрдХреЙрд▓рдмреИрдХ): рд▓реЙрдЧрд░;
(рд╕рдВрджреЗрд╢: рд╕реНрдЯреНрд░рд┐рдВрдЧ, ...рдореЗрдЯрд╛: рдХреЛрдИ рднреА []): рд▓рдХрдбрд╝рд╣рд╛рд░рд╛;
(infoObject: рд╡рд╕реНрддреБ): рд▓рдХрдбрд╝рд╣рд╛рд░рд╛;
}

рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рдЖрдк рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдкрд╣рд▓реЗ рдкрд░рдо рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдХреЗрд╡рд▓ рддреНрд░реБрдЯрд┐ рдХрд╛ рд╕рдВрджреЗрд╢ рд▓реЗрдЧрд╛ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдХреЗрд╡рд▓ рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХреЛ рд╕рдордЭрддрд╛ рд╣реИ, рдФрд░ рдпрджрд┐ рдЖрдк рджреВрд╕рд░реЗ рдкреИрд░рд╛ рдореЗрдВ рддреНрд░реБрдЯрд┐ рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЖрдк info.stack рдореЗрдВ рд╕реНрдЯреИрдХ рдЯреНрд░реЗрд╕ рддрдХ рдкрд╣реБрдВрдЪ рд╕рдХрддреЗ рд╣реИрдВ

рдмреАрдЯреАрдбрдмреНрд▓реНрдпреВ рдореИрдВ рдЗрд╕реЗ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реЛрдВ рдореЗрдВ рдХрд╣реАрдВ рднреА рдирд╣реАрдВ рдвреВрдВрдв рд╕рдХрд╛

рдореБрдЭреЗ рджреЛ рд╕рдорд╛рдзрд╛рди рдорд┐рд▓реЗ, рдкрд╣рд▓рд╛ рд╣реИ format.errors , рдЬрд┐рд╕рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдкреИрд░реЗрдВрдЯ рд▓реЙрдЧрд░ рдореЗрдВ рд▓реЙрдЧрдлреЙрд░реНрдо рдкрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдлрд┐рд░ format.printf рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рд╕рдВрджреЗрд╢рдлреЙрд░реНрдореЗрдЯрд░ рдмрдирд╛рдПрдВ рдФрд░ рд╕рд╢рд░реНрдд рд░реВрдк рд╕реЗ stack рд╕реЗ рдирд┐рдХрд╛рд▓рд╛ рдЧрдпрд╛ рдлрд╝реАрд▓реНрдб рдЬреЛрдбрд╝реЗрдВ info ( format.errors({ stack: true}) рд╡рд╣ рдЬреЛрдбрд╝ рджреЗрдЧрд╛)ред

рджреВрд╕рд░рд╛ рд╕рдорд╛рдзрд╛рди, рдЬрд┐рд╕реЗ рдореИрдВрдиреЗ рдкрд╕рдВрдж рдХрд┐рдпрд╛ рдерд╛, рд╡рд┐рдВрд╕реНрдЯрди рд╕реНрддрд░ рдХреЗ рд▓реЙрдЧрд░реНрд╕ рдореЗрдВ рд╣реИрдХ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛:

const addArgs = format((info) => {
  const args: any[] = info[Symbol.for('splat')]
  info.args = args ? [...args] : []
  return info
})

const messageFormatter = format.printf(info => {
  const { timestamp: timeString = '', message, args = [] } = info
  const formattedMsgWithArgs = util.formatWithOptions({ colors: true }, message, ...args)
  const msg = `${timeString} - ${info.level}: ${formattedMsgWithArgs}`
  return msg
})

const logger = createLogger({
  format: format.combine(
    addArgs(),
    format.timestamp({ format: 'HH:mm:ss.SSS' })
  ),

  transports: [
    new transports.Console({
      format: format.combine(format.colorize(), messageFormatter),
    }),
  ],
})

const levels = ['debug', 'info', 'error']
levels.forEach((level) => {
  logger[level] = (msg: any, ...remains: any) => {
    if(typeof msg != "string") {
      return logger.log(level, '', msg, ...remains)
    }

    logger.log(level, msg, ...remains)
  }  
})

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдореБрдЭреЗ console.log рд╕рдорд╛рди рддреНрд░реБрдЯрд┐ рд▓реЙрдЧрд┐рдВрдЧ рдорд┐рд▓ рд╕рдХрддреА рд╣реИ

рдореИрдВ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ рдХрд┐ _parent_ рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдкрд░ format.errors рдХреИрд╕реЗ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ @tiagonapoli рдХреА рдЯрд┐рдкреНрдкрдгреА рд╕рдЯреАрдХ рд╣реИред рдЬрдм рдореИрдВ рдРрд╕рд╛ рдХреБрдЫ рдХрд░рддрд╛ рд╣реВрдВ:

winston.loggers.add("default");
const log = winston.loggers.get("default");
/* get a `transportOptions` object and a `transportType` */
transportOptions.format = logform.format.combine(
  logform.format.errors({ stack: true }),
  logform.format.timestamp(),
  logform.format.printf(myFormatter)
);
log.add(new winston.transports[transportType](transportOptions);

Error рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд╕рдВрднрд╛рд▓рдирд╛ рдРрд╕рд╛ рд╣реИ рдЬреИрд╕реЗ рд╡реЗ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдереЗред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЕрдЧрд░ рдореИрдВ рдРрд╕рд╛ рдХреБрдЫ рдХрд░рддрд╛ рд╣реВрдВ:

winston.loggers.add("default");
const log = winston.loggers.get("default");
log.format = logform.format.errors({ stack: true });
/* get a `transportOptions` object and a `transportType` */
transportOptions.format = logform.format.combine(
  logform.format.timestamp(),
  logform.format.printf(myFormatter)
);
log.add(new winston.transports[transportType](transportOptions);

Error рд╡рд╕реНрддреБ рдХреА рд╣реИрдВрдбрд▓рд┐рдВрдЧ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд╛рдо рдХрд░рддреА рд╣реИред

рдореБрдЭреЗ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣рд╛рдБ рджреЛрд╖ рдпрд╣ рд╣реИ рдХрд┐ рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ рдХреЛрдИ рдЕрдВрддрд░ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред

рддреЛ рдпрд╣ рдЕрднреА рднреА 1 рд╕рд╛рд▓ рдХреЗ рдмрд╛рдж рднреА рддрдп рдирд╣реАрдВ рд╣реИ? рдХреНрдпрд╛ рдореБрдЭреЗ рдЗрд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рдВрд╕реНрдЯрди рд▓рдХрдбрд╝рд╣рд╛рд░рд╛ рдХреЛрдб рд╣реИрдХ рдХрд░рдирд╛ рд╣реЛрдЧрд╛?

рд╣рд╛рдБ, рдЗрд╕рдиреЗ рдореБрдЭреЗ рдкрд░реНрдпрд╛рдкреНрдд рд╕рд┐рд░рджрд░реНрдж рджрд┐рдпрд╛ рдХрд┐ рд╡рд┐рдВрд╕реНрдЯрди рдореЗрд░реЗ рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рд╕рд░рд▓ рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЗ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдЕрдзрд┐рдХ рдкрд░реЗрд╢рд╛рдиреА рдХреА рддрд░рд╣ рд▓рдЧрдиреЗ рд▓рдЧрд╛ ... рдореИрдВрдиреЗ рдЕрдкрдирд╛ рдЦреБрдж рдХрд╛ рдЫреЛрдЯрд╛ рд▓реЙрдЧрд░ рдХреНрд▓рд╛рд╕ рд▓рд┐рдЦрдирд╛ рд╕рдорд╛рдкреНрдд рдХрд░ рджрд┐рдпрд╛, рдФрд░ рдореИрдВ рдЕрдиреБрд╢рдВрд╕рд╛ рдХрд░рддрд╛ рд╣реВрдВ рдХрд┐ рдЕрдиреНрдп рд▓реЛрдЧ рднреА рдРрд╕рд╛ рд╣реА рдХрд░реЗрдВ рдЬрдм рддрдХ рдХрд┐ рд╡рд┐рдВрд╕реНрдЯрди рдХреБрдЫ рдРрд╕рд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рдХреА рдЖрдкрдХреЛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рджреЛрд╕реНрддреЛрдВ, рд╕рдЪ рдореЗрдВ? рдпрд╣ рдирд┐рд░рд╛рд╢ рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рд╣реИ...

рдореИрдВ рдПрдХ рдХрдорд┐рдЯрд░ рдирд╣реАрдВ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдореИрдВ рд╢рд╛рдпрдж рдпрд╣ рдХрд╣рдирд╛ рд╕рд╣реА рд╣реВрдВ рдХрд┐ рдпрд╣ "рдирд┐рд╢реНрдЪрд┐рдд" рдирд╣реАрдВ рд╣реЛрдиреЗ рд╡рд╛рд▓рд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдЯреВрдЯрд╛ рдирд╣реАрдВ рд╣реИред рд╡рд┐рдВрд╕реНрдЯрди рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд▓рд╛рдпрдХ рд╣реИред рдЖрдкрдХреЛ рдмрд╕ рдЗрд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ - рдореЗрд░реЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдЕрдЪреНрдЫреА рд╕рд▓рд╛рд╣ рдКрдкрд░ рд╣реИ https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691

рдЕрднреА рдирд╣реАрдВ ?

рдЕрджреНрдпрддрди: рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХреЗ рд╕рд╛рде рдЕрднреА рднреА рд╕рдорд╕реНрдпрд╛рдПрдВ рд╣реИрдВ, рдореИрдВ рдереЛрдбрд╝реА рджреЗрд░ рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ

// Grab the default winston logger
const winston = require('winston');

const { format } = winston;
const { combine, timestamp } = format;

// Custom format function that will look for an error object and log out the stack and if 
// its not production, the error itself
const myFormat = format.printf((info) => {
  const { timestamp: tmsmp, level, message, error, ...rest } = info;
  let log = `${tmsmp} - ${level}:\t${message}`;
  // Only if there is an error
  if ( error ) {
    if ( error.stack) log = `${log}\n${error.stack}`;
    if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
  }
  // Check if rest is object
  if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
    log = `${log}\n${JSON.stringify(rest, null, 2)}`;
  }
  return log;
});

 winston.configure({
    transports: [
      new winston.transports.Console({
        level: 'debug',
        timestamp: true,
        handleExceptions: true
    }),
  ];
    format: combine(
      trace(),
      timestamp(),
      myFormat
    ),
  });


// Finally you log like this
logger.error('An error occurred!!!', { error } );

рдирд┐рд╢рд╛рди рдХрд╣рд╛рдБ рд╕реЗ рдЖрддрд╛ рд╣реИ?

рдирд╣реАрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рд▓реЙрдЧрд┐рдВрдЧ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд▓рд┐рдП рдЕрд╕реНрд╡реАрдХрд╛рд░реНрдп рд╣реИред
рдореЗрдВрдЯреЗрдирд░ рдХреЛ рдХреЗрд╡рд▓ рдбреЙрдХреНрд╕ рдкрд░ рдПрдХ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдЙрджрд╛рд╣рд░рдг рд░рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП рдЬрд╣рд╛рдВ рдпрд╣ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдХреИрд╕реЗ рдПрдХ рддреНрд░реБрдЯрд┐ рд▓реЙрдЧ рдХрд░рдирд╛ рд╣реИ, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛтАЛтАЛрдХрд┐ рдХрд╕реНрдЯрдо рдкреНрд░рд┐рдВрдЯрдл рдкреНрд░рд╛рд░реВрдк рдФрд░ рдЧреИрд░ рдЬреЗрд╕рди рдкреНрд░рд╛рд░реВрдк рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдирд╛ рдФрд░ рдЬрд╣рд╛рдВ рдЖрдк рд▓реЙрдЧрд░ рдЬреИрд╕реЗ рдХреБрдЫ рдХреЗ рд╕рд╛рде рддреНрд░реБрдЯрд┐ рд▓реЙрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рддреНрд░реБрдЯрд┐ (рддреНрд░реБрдЯрд┐)
рд╡рд┐рдВрд╕реНрдЯрди рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд▓рдЧ рд░рд╣рд╛ рдерд╛ рд▓реЗрдХрд┐рди рдпрд╣ рдореБрджреНрджрд╛ рдЕрд╡рд┐рд╢реНрд╡рд╕рдиреАрдп рд░реВрдк рд╕реЗ рдЕрд╕реНрд╡реАрдХрд╛рд░реНрдп рд╣реИ

рд╡рд┐рдВрд╕реНрдЯрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдХреИрд╕реЗ рд▓реЙрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдП, рдЗрд╕ рдкрд░ рдореЗрд░рд╛ рд╡рд┐рдЪрд╛рд░ рд╣реИред рдпрд╣ рдЕрджреНрд╡рд┐рддреАрдп рдирд╣реАрдВ рд╣реИ, рдКрдкрд░ рдХреА рдмрд╣реБрдд рд╕рд╛рд░реА рдЭрд╛рдВрдХрд┐рдпреЛрдВ рдореЗрдВ рд╕рдорд╛рди рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╕рдорд╛рдзрд╛рди рднреА рд╣реИрдВред

рдкреГрд╖реНрдарднреВрдорд┐
рдореИрдВ рдордирдорд╛рдиреЗ рдврдВрдЧ рд╕реЗ рдСрдмреНрдЬреЗрдХреНрдЯ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рдХрд╕реНрдЯрдо рддреНрд░реБрдЯрд┐рдпреЛрдВ рдореЗрдВ рд▓рдкреЗрдЯрдиреЗ рдХреЗ рд▓рд┐рдП @jsdevtools/ono рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдкрд░рд╡рд╛рд╣ рдХрд┐рдП рдмрд┐рдирд╛, рдпрд╣ рд╕рдорд╛рдзрд╛рди рдЕрднреА рднреА рджреЗрд╢реА рдиреЛрдб рддреНрд░реБрдЯрд┐рдпреЛрдВ (рдЬреИрд╕реЗ fs eperm рддреНрд░реБрдЯрд┐рдпреЛрдВ), рдФрд░ рдХрд╕реНрдЯрдо рддреНрд░реБрдЯрд┐ рд╡рд░реНрдЧреЛрдВ рдкрд░ рдареАрдХ рдХрд╛рдо рдХрд░рддрд╛ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИред

рд╡реНрдпрд╛рдЦреНрдпрд╛
рдореВрд▓ рд░реВрдк рд╕реЗ, рдореИрдВ format.errors({stack:true}) рдФрд░ format.metadata() рдкрд░ рдирд┐рд░реНрднрд░ рд╣реВрдВред рдЬреИрд╕рд╛ рдХрд┐ https://github.com/winstonjs/winston/issues/1338#issuecomment -532327143 рджреНрд╡рд╛рд░рд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдпрд╣ рдореВрд▓ рдлреЙрд░реНрдореЗрдЯрд░ рдореЗрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред

рдореЗрдЯрд╛рдбреЗрдЯрд╛ рд╕рднреА рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдХрд╕реНрдЯрдо рдЧреБрдгреЛрдВ рдХреЛ info.metadata рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред

рдореИрдВ 3 рдкреНрд░рдХрд╛рд░ рдХреА рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд┐рдВрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛: рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢, рд╕реНрдЯреИрдХрдЯреНрд░реЗрд╕, рдФрд░ рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдЧреБрдгред рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╕рд╛рджрд╛ рдкрд╛рда рдерд╛ред рдореИрдВрдиреЗ pretty-error рдореЙрдбреНрдпреВрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрдЯреИрдХ info.metadata.stack рд╕реБрдВрджрд░-рдореБрджреНрд░рд┐рдд рдХрд┐рдпрд╛ред рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдЧреБрдгреЛрдВ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдирд╣реАрдВ рдЪрд╛рд╣рддрд╛ рдерд╛ рдХрд┐ рд╕реНрдЯреИрдХрдЯреНрд░реЗрд╕ рдлрд┐рд░ рд╕реЗ рджрд┐рдЦрд╛рдИ рджреЗ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдХреНрд▓реЛрди рдХрд┐рдпрд╛, рдФрд░ рд╕реНрдЯреИрдХрдЯреНрд░реЗрд╕ рдкреНрд░реЙрдкрд░реНрдЯреА рдХреЛ рд╣рдЯрд╛ рджрд┐рдпрд╛ред рдлрд┐рд░ рдореИрдВрдиреЗ fast-safe-stringify рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд╕реБрдВрджрд░-рдореБрджреНрд░рд┐рдд рдХрд┐рдпрд╛, рдЬреЛ рд╡рд╣реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЙрдбреНрдпреВрд▓ рд╣реИ рдЬреЛ рд╡рд┐рдВрд╕реНрдЯрди рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИред

    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

рдкреБрдирд╢реНрдЪ: рдореБрдЭреЗ рдПрдХ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдХрд▓реНрдк рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691 рдореЗрдВ рдЙрд▓реНрд▓рд┐рдЦрд┐рдд рд╕рдорд╛рдзрд╛рди рднреА рдорд┐рд▓рддрд╛ рд╣реИред рдпрд╛рдиреА logger.warn("Oh no", { error: new Error() }) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдлрд┐рд░ рдЕрдкрдиреЗ рдХрд╕реНрдЯрдо рдлреЙрд░реНрдореЗрдЯрд░ рдореЗрдВ info.error рдХрд╛ рд╕рдВрджрд░реНрдн рджреЗрдирд╛ред

@tiagonapoli рдорд╛рддрд╛-рдкрд┐рддрд╛ format.errors рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЖрдкрдХреЗ рд╕рдорд╛рдзрд╛рди рдиреЗ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛:

const logger = createLogger({
  transports: loggerTransports,
});

logger.format = format.errors({ stack: true });

рдЗрд╕ рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛ рдХрд╛рдлреА рджрд░реНрджрдирд╛рдХ рд╣реИ... рдХреНрдпрд╛ рдпрд╣ рдХреЗрд╡рд▓ console.log рдЖрдЙрдЯ рдж рдмреЙрдХреНрд╕ рдЬреИрд╕рд╛ рд╡реНрдпрд╡рд╣рд╛рд░ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рдерд╛?

@ will093 рд╡рд╣реА рдпрд╣рд╛рдБред рдЙрд╕ рдореБрджреНрджреЗ рдкрд░ рдлрд┐рд░ рд╕реЗ рдЧрдпрд╛ рдФрд░ рдпрд╣ рдирд╣реАрдВ рдорд┐рд▓рд╛ рдХрд┐ рдореЗрд░рд╛ console.log рдЕрдЪреНрдЫрд╛ рдФрд░ рд╕рд╛рдл рдХреНрдпреЛрдВ рд╣реИ рдФрд░ рд╡рд┐рдВрд╕реНрдЯрди рдкреНрд░рд╛рд░реВрдк рдмрдХрд╡рд╛рд╕ рд╣реИред

рдореЗрд░рд╛ 2┬в

// Enable console logging when not in production
if (process.env.NODE_ENV !== "production") {
    logger.add(new transports.Console({
        format: format.combine(
            format.colorize(),
            format.simple(),
            format.printf(info => {
                const { level, ...rest } = info;
                let rtn = "";
                // rtn += info.timestamp;
                rtn += "[" + info.level + "] ";
                if (rest.stack) {
                    rtn += rest.message.replace(rest.stack.split("\n")[0].substr(7),"");
                    rtn += "\n";
                    rtn += "[" + level + "] ";
                    rtn += rest.stack.replace(/\n/g, `\n[${level}]\t`);
                } else {
                    rtn += rest.message;
                }
                return rtn;
            }),
        ),
    }));
}

logger.error("Error during schema stitching", e); рд▓рд┐рдП рдЙрджрд╛рд╣рд░рдг

image

@tiagonapoli рдФрд░ @ will093 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕реЗ рдХреЗрд╡рд▓ рдорд╛рддрд╛-рдкрд┐рддрд╛ рдореЗрдВ рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рд╕рдорд╛рдзрд╛рди рд╕реАрдзреЗ рд▓реЙрдЧрд┐рдВрдЧ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдФрд░ рдЕрднреА рднреА рд▓реЙрдЧрд┐рдВрдЧ рд╕рдВрджреЗрд╢реЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХрд╛ рд╕рдмрд╕реЗ рдЖрд╕рд╛рди рддрд░реАрдХрд╛ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ - рдпрд╣рд╛рдВ рдиреНрдпреВрдирддрдо рд╕реЗрдЯрдЕрдк w/рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдХрд╛ рдПрдХ рдкреВрд░реНрдг рдЙрджрд╛рд╣рд░рдг рд╣реИ:

const createLogger = () => {
  const logFormatter = winston.format.printf(info => {
    let { timestamp, level, code, stack, message } = info;

    // print out http error code w/ a space if we have one
    code = code ? ` ${code}` : '';
    // print the stack if we have it, message otherwise.
    message = stack || message;

    return `${timestamp} ${level}${code}: ${message}`;
  });

  return winston.createLogger({
    level: 'info',
    // put the errors formatter in the parent for some reason, only needed there:
    format: winston.format.errors({ stack: true }),
    transports: new winston.transports.Console({
      format: winston.format.combine(
        winston.format.timestamp(),
        logFormatter
      ),
  });
};

рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рдХреЙрд▓ рдХрд┐рдП рдЬрд╛рдиреЗ рдкрд░ рд╕реНрдЯреИрдХ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬреИрд╕реЗ: logger.error(error) , рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм рдЗрд╕реЗ logger.error('a regular message') рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдореЗрд░реЗ рд▓реЙрдЧ рдореЗрдВ рдРрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИ:

2020-09-23T20:05:30.30Z info: Feathers application started on http://localhost:3030
2020-09-23T20:05:35.40Z info: job queue - redis ready, registering queues...
2020-09-23T20:05:40.25Z error 401: NotAuthenticated: invalid authorization header
    at new NotAuthenticated (/path/to/server/node_modules/@feathersjs/errors/lib/index.js:94:17)
    at Object.<anonymous> (/path/to/server/src/hooks/authentication.js:123:456)
    at /path/to/server/node_modules/@feathersjs/commons/lib/hooks.js:116:46

рдпрд╣ рд╡рд┐рдВрд╕реНрдЯрди рдХреЗ logger.error('message here', error) -incompatibility w/ console.log рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ , рдЬреЛ @tiagonapoli рдХрд╛ рдЕрдзрд┐рдХ рд╕рдореНрдорд┐рд▓рд┐рдд рд╕рдорд╛рдзрд╛рди рдХрд░рддрд╛ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИред

рд╕рд╛рде рд╣реА, рдЕрдЧрд░ рдЖрдкрдХреЛ рдЬреЗрд╕рди рд▓реЙрдЧ рдкрд╕рдВрдж рд╣реИрдВ рддреЛ рдЖрдк рдпрд╣рд╛рдВ logFormatter рдЫреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕рдХреЗ рд╕реНрдерд╛рди рдкрд░ winston.format.json() рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдореЗрдВ рдЕрднреА рднреА рд╕реНрдЯреИрдХ рд╢рд╛рдорд┐рд▓ рд╣реЛрдЧрд╛ - рд▓реЗрдХрд┐рди рдпрд╣ рд╕реБрдВрджрд░ рдирд╣реАрдВ рд╣реИред

рдЕрджреНрдпрддрди: рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХреЗ рд╕рд╛рде рдЕрднреА рднреА рд╕рдорд╕реНрдпрд╛рдПрдВ рд╣реИрдВ, рдореИрдВ рдереЛрдбрд╝реА рджреЗрд░ рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ

// Grab the default winston logger
const winston = require('winston');

const { format } = winston;
const { combine, timestamp } = format;

// Custom format function that will look for an error object and log out the stack and if 
// its not production, the error itself
const myFormat = format.printf((info) => {
  const { timestamp: tmsmp, level, message, error, ...rest } = info;
  let log = `${tmsmp} - ${level}:\t${message}`;
  // Only if there is an error
  if ( error ) {
    if ( error.stack) log = `${log}\n${error.stack}`;
    if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
  }
  // Check if rest is object
  if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
    log = `${log}\n${JSON.stringify(rest, null, 2)}`;
  }
  return log;
});

 winston.configure({
    transports: [
      new winston.transports.Console({
        level: 'debug',
        timestamp: true,
        handleExceptions: true
    }),
  ];
    format: combine(
      trace(),
      timestamp(),
      myFormat
    ),
  });


// Finally you log like this
logger.error('An error occurred!!!', { error } );

рдЯреНрд░реЗрд╕ () рдкрд░рд┐рднрд╛рд╖рд╛ рдХрд╣рд╛рдВ рд╣реИ?

рдЕрджреНрдпрддрди: рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХреЗ рд╕рд╛рде рдЕрднреА рднреА рд╕рдорд╕реНрдпрд╛рдПрдВ рд╣реИрдВ, рдореИрдВ рдереЛрдбрд╝реА рджреЗрд░ рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ

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

рдирд┐рд╢рд╛рди рдХрд╣рд╛рдБ рд╕реЗ рдЖрддрд╛ рд╣реИ?

рдЗрд╕ рдкрд░ рдХреЛрдИ рдЬрд╡рд╛рдм?

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

mrgoos picture mrgoos  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

ghost picture ghost  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

Buzut picture Buzut  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

amiram picture amiram  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

JaehyunLee-B2LiNK picture JaehyunLee-B2LiNK  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ