рдирдорд╕реНрддреЗ
рдЬрдм рдореИрдВ рдПрдХ рдЬреЗрд╕рди рдкреНрд░рд╛рд░реВрдк рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ рд╡рд┐рдВрд╕реНрдЯрди 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 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(),
});
рдЬреЛ рдореБрдЭреЗ рдпрд╣ рдЙрддреНрдкрд╛рджрди рдореЗрдВ рджреЗрддрд╛ рд╣реИ
рдФрд░ рдпрд╣ рд╡рд┐рдХрд╛рд╕ рдореЗрдВ
рдореИрдВрдиреЗ рдЗрд╕реЗ рдЕрдЬреНрдЮрд╛рдд рдЧреБрдгреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╕реНрдЯрдо рддреНрд░реБрдЯрд┐ рд╡рд░реНрдЧреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд▓рд┐рдЦрд╛ рд╣реИ, рдФрд░ рд╕реНрдЯреИрдХ рдХреЛ рд╕рд╛рдл рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рднреА рд▓рд┐рдЦрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рд╡реЗ рдирдИ рд▓рд╛рдЗрдиреЗрдВ рдЬреЗрд╕рди-рдЖрдзрд╛рд░рд┐рдд рд▓реЙрдЧрд┐рдВрдЧ рдореЗрдВ рднрдпрд╛рдирдХ рд╣реИрдВред
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
рд▓рд┐рдП рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдпрд╛ред
рдореИрдВ рдЙрд╕реА рдореБрджреНрджреЗ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░ рд░рд╣рд╛ рдерд╛ рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдпрд╣ рдкреИрдХреЗрдЬ рд▓рд┐рдЦрд╛, utils-deep-clone ред рдЗрд╕рдХреА рдЬрд╛рдВрдЪ - рдкрдбрд╝рддрд╛рд▓ рдХрд░реЗрдВред
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
рдЕрдзрд┐рдХ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд╕рдВрд╕реНрдХрд░рдг:
рд▓реЗрдХрд┐рди рдпрд╣ рд╡рд╣реА рд╣реИ рдЬреЛ рдореИрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рд╕реБрдВрджрд░ рд▓реЙрдЧ рдФрд░ рдЙрддреНрдкрд╛рджрди рдореЗрдВ JSON рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд░рддрд╛ рд╣реВрдВ:
рдЬреЛ рдореБрдЭреЗ рдпрд╣ рдЙрддреНрдкрд╛рджрди рдореЗрдВ рджреЗрддрд╛ рд╣реИ
рдФрд░ рдпрд╣ рд╡рд┐рдХрд╛рд╕ рдореЗрдВ