Winston: рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ 3.0 рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБрдУрдВ рдХреЗ рд▓рд┐рдП {} рд▓реЙрдЧрд┐рдВрдЧ рдХрд░ рд░рд╣рд╛ рд╣реИ

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

рдирдорд╕реНрддреЗ
рдЬрдм рдореИрдВ рдПрдХ рдЬреЗрд╕рди рдкреНрд░рд╛рд░реВрдк рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ рд╡рд┐рдВрд╕реНрдЯрди 3.0 рдЦрд╛рд▓реА рддреНрд░реБрдЯрд┐ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рд▓реЙрдЧрд┐рдВрдЧ рдХрд░рдиреЗ рдореЗрдВ рдХреБрдЫ рдкрд░реЗрд╢рд╛рдиреА рд╣реЛ рд░рд╣реА рд╣реИред

module.exports = winston.createLogger({
  format: format.combine(
    format.label({ label: 'my label'}),
    format.timestamp(),
    format.prettyPrint()
  ),
  transports: [
    new (winston.transports.Console)({
      level: error
    })
  ]
}); 

рдЕрдкреЗрдХреНрд╖рд┐рдд рд▓реЙрдЧ рдХрд░рддрд╛ рд╣реИ

 {error: [stack trace here] }
 ```

 while 

рдореЙрдбреНрдпреВрд▓.рдПрдХреНрд╕рдкреЛрд░реНрдЯреНрд╕ = рд╡рд┐рдВрд╕реНрдЯрди.рдХреНрд░рд┐рдПрдЯрд▓реЙрдЧрд░ ({
рдкреНрд░рд╛рд░реВрдк: format.combine(
format.label ({рд▓реЗрдмрд▓: 'рдореЗрд░рд╛ рд▓реЗрдмрд▓'}),
format.timestamp (),
рдкреНрд░рд╛рд░реВрдк.рдЬреЗрд╕рди ()
),
рдкрд░рд┐рд╡рд╣рди: [
рдирдпрд╛ (рд╡рд┐рдВрд╕реНрдЯрди.рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯреНрд╕.рдХрдВрд╕реЛрд▓)({
рд╕реНрддрд░: рддреНрд░реБрдЯрд┐
})
]
});

logs the erroneous

{рддреНрд░реБрдЯрд┐: {} }

when it is passed 

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

Manually creating a format with 

рд╡рд┐рдВрд╕реНрдЯрди.рдкреНрд░рд╛рд░реВрдк.рдкреНрд░рд┐рдВрдЯрдл
````
рдЧрд▓рдд рдкрд░рд┐рдгрд╛рдо рднреА рд▓реМрдЯрд╛рдпрд╛ред

рдХреНрдпрд╛ рдХрд┐рд╕реА рдХреЛ рдЗрд╕рдХреЗ рд▓рд┐рдП рдХрд╛рдордХрд╛рдЬ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрддрд╛ рд╣реИ?

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

рдЕрдзрд┐рдХ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд╕рдВрд╕реНрдХрд░рдг:

function format() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

const logger = createLogger({
  format: format(),
});

рд▓реЗрдХрд┐рди рдпрд╣ рд╡рд╣реА рд╣реИ рдЬреЛ рдореИрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рд╕реБрдВрджрд░ рд▓реЙрдЧ рдФрд░ рдЙрддреНрдкрд╛рджрди рдореЗрдВ JSON рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд░рддрд╛ рд╣реВрдВ:

function prodFormat() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

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

const logger = createLogger({
  level: process.env.LOG_LEVEL || 'info',
  exitOnError: false,
  transports: [new transports.Console()],
  format: isProd ? prodFormat() : devFormat(),
});

рдЬреЛ рдореБрдЭреЗ рдпрд╣ рдЙрддреНрдкрд╛рджрди рдореЗрдВ рджреЗрддрд╛ рд╣реИ

bildschirmfoto 2018-09-21 um 16 46 35

рдФрд░ рдпрд╣ рд╡рд┐рдХрд╛рд╕ рдореЗрдВ

bildschirmfoto 2018-09-21 um 16 47 04

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

рдПрдХ рдЙрдкрд╛рдп:

function errorReplacer(key, value) {
  if (value instanceof Error) {
    return { message: value.message, stack: value.stack };
  }
  return value;
}

const logFormat = winston.format.printf((info) => {
  return `${JSON.stringify(info, errorReplacer)}`;
});

module.exports = winston.createLogger({
  format: format.combine(
    format.label({ label: 'my label' }),
    format.timestamp(),
    logFormat
  ), ...

рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдЗрд╕рд╕реЗ рд╕рд╣рд╛рдпрддрд╛ рдорд┐рд▓реЗрдЧреАред

рд╕рдорд╛рдзрд╛рди рдореЗрд░реЗ рдХрд╛рдо рдирд╣реАрдВ рдЖрдпрд╛ (info.message рдХрд╣реАрдВ рдЦреЛ рд░рд╣рд╛ рд╣реИ)

рд╡реЗрд░рд┐рдПрдВрдЯ рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб:

const winston = require('winston')
const MESSAGE = Symbol.for('message')

/*
 * function replacer (key, value)
 * Handles proper stringification of Buffer output.
 */
const replacer = function (key, value) {
  return value instanceof Buffer
    ? value.toString('base64')
    : value
}

var json_log = winston.format(function (info, opts) {
  var display = info
  if (info._error) {
    display = Object.assign({}, info, { message: info._error })
    delete display._error
  }
  info[MESSAGE] = JSON.stringify(display, opts.replacer || replacer, opts.space)
  return info
})

var preserve_error_message = format(function (info, opts) {
  if (_.isError(info)) {
    info._error = info.message
  }
  return info
})

const logger = winston.createLogger({
  levels: ...,
  format: format.combine(format.timestamp(), preserve_error_message()),
  transports: [
    new transports.Console({
    level: this.config.console.level,
    format: json_log({ space: 2 })
  })
]

рдпрд╣ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╕реБрд░реБрдЪрд┐рдкреВрд░реНрдг рдирд╣реАрдВ рд▓рдЧрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП info.message рдХреЛ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдзрд┐рдХрд╛рд░реА рдЬрдм info рдПрдХ Error рдЖрджрд░реНрд╢ рд╣реЛрдЧрд╛ (рдпрд╣ рддрдм рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм info рдирд┐рдпрдорд┐рдд рд╣реЛ рд╡рд╕реНрддреБ)

рдореИрдВ рднреА рдЗрд╕рдореЗрдВ рднрд╛рдЧ рд░рд╣рд╛ рд╣реВрдВред рдХреНрдпрд╛ рд╡рд┐рдВрд╕реНрдЯрди рдХреЛ рдЗрд╕реЗ рд▓реАрдХ рд╕реЗ рд╣рдЯрдХрд░ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП? @indexzero рдЖрдк рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛ рд╕реЛрдЪрддреЗ рд╣реИрдВ?

Logform json рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рджреЗрдЦрдиреЗ рдХреЗ рдмрд╛рдж рдореИрдВ рдЕрдм рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдХреИрд╕реЗ opts.replacer рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рдорд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЬрдм рд╕рдВрдпреЛрдЬрди рдореИрдВ рдПрдХ рдФрд░ рд╕рдорд╛рдзрд╛рди рдХреЗ рд╕рд╛рде рдЖрдпрд╛ рдерд╛ рдЗрд╕ stackoverflow рдкрдж рдореМрдЬреВрджрд╛ рдмрдлрд░ stringification рд╕рд╛рде:

'use strict';

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

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

function replaceErrors(key, value) {
    if (value instanceof Buffer) {
        return value.toString('base64');
    } else if (value instanceof Error) {
        var error = {};

        Object.getOwnPropertyNames(value).forEach(function (key) {
            error[key] = value[key];
        });

        return error;
    }

    return value;
}


var error = new Error('foooo');
error.my_custom_stuff = 'bar';

logger.log('error', 'Hello, this is a raw logging event', { error });

рдЬреЛ рдкреНрд░рд┐рдВрдЯ рдХрд░рддрд╛ рд╣реИ:

{"error":{"stack":"Error: foooo\n    at Object.<anonymous> (/home/dino/work/winston/examples/json.js:31:13)\n    at Module._compile (module.js:662:30)\n    at Object.Module._extensions..js (module.js:673:10)\n    at Module.load (module.js:575:32)\n    at tryModuleLoad (module.js:515:12)\n    at Function.Module._load (module.js:507:3)\n    at Function.Module.runMain (module.js:703:10)\n    at startup (bootstrap_node.js:193:16)\n    at bootstrap_node.js:660:3","message":"foooo","my_custom_stuff":"bar"},"level":"error","message":"Hello, this is a raw logging event"}

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

рдЕрдкрдиреЗ рд╕рдЯреАрдХ рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдирд╣реАрдВ рд╣реИрдВ рд▓реЗрдХрд┐рди рдЖрдк рд╕реАрдзреЗ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рд▓реЙрдЧ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВ:

logger.log(new Error('my error message'));

(рдпрд╣ https://github.com/winstonjs/winston/pull/1234) рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

рдпрджрд┐ рдЖрдкрдХреЛ рд▓реЙрдЧрд┐рдВрдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХрд┐рд╕реА рдмрдбрд╝реЗ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдЕрдВрджрд░ рддреНрд░реБрдЯрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ Node.js Errors JSON рдСрдмреНрдЬреЗрдХреНрдЯ рдирд╣реАрдВ рд╣реИрдВ, рд▓реЗрдХрд┐рди https://www.npmjs.com/package рдЬреИрд╕реА рдЪреАрдЬреЗрдВ рд╣реИрдВред /utils-error-to-json рдпрд╛ рд╢рд╛рдпрдж parse(stringify(error)) рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬреЛ JSON рдлреЙрд░реНрдореЗрдЯрд░ рдХреЗ рд╕рд╛рде рдпрд╣ рдХрд╛рдо рдХрд░реЗрдЧрд╛ред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ @dhensen рдХрд╛ рд╕рдорд╛рдзрд╛рди рдпрд╣реА рдХрд░рддрд╛ рд╣реИ, рддреНрд░реБрдЯрд┐ рдХреЛ JSON рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рддрд╛ рд╣реИ - рддрд╛рдХрд┐ рдЖрдк рдРрд╕рд╛ рдХреБрдЫ рдХрд░ рд╕рдХреЗрдВ, рдкреИрдХреЗрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХреЗрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рдЖрдо рддреМрд░ рдкрд░ рд╡рд┐рдВрд╕реНрдЯрди

рдЖрдЧреЗ рдмрдврд╝рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рдмрдВрдж рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдпрджрд┐ рдирдИ рд╕рдорд╕реНрдпрд╛рдПрдВ/рдкреНрд░рд╢реНрди рдЙрддреНрдкрдиреНрди рд╣реЛрддреЗ рд╣реИрдВ рддреЛ рдмреЗрдЭрд┐рдЭрдХ рдлрд┐рд░ рд╕реЗ рдЦреЛрд▓реЗрдВ рдпрд╛ рдПрдХ рдирдпрд╛ рдореБрджреНрджрд╛ рдмрдирд╛рдПрдВ! рдзрдиреНрдпрд╡рд╛рдж!

рдпрд╣рд╛рдВ рддрдХ тАЛтАЛтАЛтАЛрдХрд┐ parse(stringify(error)) рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЖрдк рддрдм рднреА рд╕реНрдЯреИрдХ рдЯреНрд░реЗрд╕ рдЦреЛ рджреЗрддреЗ рд╣реИрдВред
рдореИрдВ рдЗрд╕ рддрд░рд╣ рдПрдХ рдХрд╕реНрдЯрдо рдлреЙрд░реНрдореЗрдЯрд░ рдмрдирд╛рдХрд░ рдпрд╣ рдХрд╛рдо рдХрд░рдиреЗ рдореЗрдВ рдХрд╛рдордпрд╛рдм рд░рд╣рд╛:

const formatErrorConverter = winston.format(
    info =>
        info instanceof Error
            ? Object.assign({ level: info.level, message: info.message, stack: info.stack }, info)
            : info,
);

рдФрд░ рдпрд╣ рдХрд╛рдлреА рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ!

instance of Error рдХреЗрд╡рд▓ рд╢реАрд░реНрд╖-рд╕реНрддрд░реАрдп рдлреЙрд░реНрдореЗрдЯрд░ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдкрд░рд┐рд╡рд╣рди-рд╕реНрддрд░ рдХреЗ рд╕реНрд╡рд░реВрдкрдХреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдХреНрдпрд╛ рдХреЛрдИ рд╕рдордЭрд╛ рд╕рдХрддрд╛ рд╣реИ рдХреНрдпреЛрдВ?

рдЕрдзрд┐рдХ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд╕рдВрд╕реНрдХрд░рдг:

function format() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

const logger = createLogger({
  format: format(),
});

рд▓реЗрдХрд┐рди рдпрд╣ рд╡рд╣реА рд╣реИ рдЬреЛ рдореИрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рд╕реБрдВрджрд░ рд▓реЙрдЧ рдФрд░ рдЙрддреНрдкрд╛рджрди рдореЗрдВ JSON рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд░рддрд╛ рд╣реВрдВ:

function prodFormat() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

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

const logger = createLogger({
  level: process.env.LOG_LEVEL || 'info',
  exitOnError: false,
  transports: [new transports.Console()],
  format: isProd ? prodFormat() : devFormat(),
});

рдЬреЛ рдореБрдЭреЗ рдпрд╣ рдЙрддреНрдкрд╛рджрди рдореЗрдВ рджреЗрддрд╛ рд╣реИ

bildschirmfoto 2018-09-21 um 16 46 35

рдФрд░ рдпрд╣ рд╡рд┐рдХрд╛рд╕ рдореЗрдВ

bildschirmfoto 2018-09-21 um 16 47 04

рдореИрдВрдиреЗ рдЗрд╕реЗ рдЕрдЬреНрдЮрд╛рдд рдЧреБрдгреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╕реНрдЯрдо рддреНрд░реБрдЯрд┐ рд╡рд░реНрдЧреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд▓рд┐рдЦрд╛ рд╣реИ, рдФрд░ рд╕реНрдЯреИрдХ рдХреЛ рд╕рд╛рдл рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рднреА рд▓рд┐рдЦрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╡реЗ рдирдИ рд▓рд╛рдЗрдиреЗрдВ рдЬреЗрд╕рди-рдЖрдзрд╛рд░рд┐рдд рд▓реЙрдЧрд┐рдВрдЧ рдореЗрдВ рднрдпрд╛рдирдХ рд╣реИрдВред

const replacer = (key, value) => {
  if (value instanceof Error) {
    return Object.getOwnPropertyNames(value).reduce((all, valKey) => {
      if(valKey === 'stack') {
        return {
          ...all,
          at: value[valKey].split('\n').filter(va => va.trim().slice(0, 5) != 'Error').map((va, i) => `stack ${i} ${va.trim().slice(3).trim()}`)
        }
      } else {
        return {
          ...all,
          [valKey]: value[valKey]
        }
      }

    }, {});

  } else {
    return value;
  }
}

рдирддреАрдЬрд╛:

{"at":["stack 0 /Users/sarahriehl/Documents/code/boilerplate/logging/routes/log.js:24:15","stack 1 Layer.handle [as handle_request] (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/layer.js:95:5)","stack 2 next (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/route.js:137:13)","stack 3 Route.dispatch (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/route.js:112:3)","stack 4 Layer.handle [as handle_request] (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/layer.js:95:5)","stack 5 /Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:281:22","stack 6 Function.process_params (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:335:12)","stack 7 next (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:275:10)","stack 8 Function.handle (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:174:3)","stack 9 router (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:47:12)"],"message":"argh!!!","level":"error","timestamp":"Thu 2019-02-14 01:58:58 -0600"}

рдореИрдВрдиреЗ рд╕реНрдерд╛рдиреАрдп рд╡рд┐рдХрд╛рд╕ рдкрд░реНрдпрд╛рд╡рд░рдг рдФрд░ GCP Stackdriver Logging рд▓рд┐рдП рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдпрд╛ред

https://github.com/mrdulin/blog/issues/75

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

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

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

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

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

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

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

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