node.js 如何在多个模块中使用 Winston?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14531232/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use Winston in several modules?
提问by Alexander
I have several modules - let's say server.js, module1.js,...,moduleN.js.
我有几个模块 - 比如说 server.js、module1.js、...、moduleN.js。
I would like define the log file in my server.js:
我想在我的 server.js 中定义日志文件:
winston.add(winston.transports.File, { filename: 'mylogfile.log' });
and then use it in all my modules.
然后在我所有的模块中使用它。
What is the best way to do that? I could exports.winston=winston;in each module and then set it in the server.js, but is there any better solution?
最好的方法是什么?我可以exports.winston=winston;在每个模块中然后在 server.js 中设置它,但是有没有更好的解决方案?
Thank you in advance!
先感谢您!
回答by Nick
The default logger concept handles this nicely.
默认记录器概念很好地处理了这个问题。
Winston defines a default logger that any straight require (and subsequent require) to winston will retrieve. Thus you simply configure this default logger once, and it's available for subsequent module use via vanilla require('winston') in its glorious tweaked multi-transport mode.
Winston 定义了一个默认记录器,任何对 winston 的直接要求(和后续要求)都将检索该记录器。因此,您只需配置此默认记录器一次,它就可以通过 vanilla require('winston') 在其出色的调整多传输模式下供后续模块使用。
e.g. here is my complete logging setup that defines 3 transports. I swap Loggly for MongoDB sometimes.
例如,这是我定义了 3 种传输的完整日志记录设置。我有时会将 Loggly 换成 MongoDB。
server.js
服务器.js
var logger=require('./log.js');
// requires winston and configures transports for winstons default logger- see code below.
all other .js files
所有其他 .js 文件
var logger=require('winston'); // this retrieves default logger which was configured in log.js
logger.info("the default logger with my tricked out transports is rockin this module");
log.js - this is a one time configuration of the DEFAULT logger
log.js - 这是 DEFAULT 记录器的一次性配置
var logger = require('winston');
var Loggly = require('winston-loggly').Loggly;
var loggly_options={ subdomain: "mysubdomain", inputToken: "efake000-000d-000e-a000-xfakee000a00" }
logger.add(Loggly, loggly_options);
logger.add(winston.transports.File, { filename: "../logs/production.log" });
logger.info('Chill Winston, the logs are being captured 3 ways- console, file, and Loggly');
module.exports=logger;
Alternatively for more complex scenarios you can use winston containers and retrieve the logger from a named container in other modules. I haven't used this.
或者,对于更复杂的场景,您可以使用 winston 容器并从其他模块中的命名容器中检索记录器。我没用过这个。
My only issue with this was a missing logs directories on my deployment host which was easily fixed.
我唯一的问题是我的部署主机上缺少日志目录,这很容易修复。
Hope this helps.
希望这可以帮助。
回答by Nick Mitchinson
What I do ( which may not be the best way ) is use a 'global' module where I export all the stuff that I use through my applications. For instance:
我所做的(这可能不是最好的方法)是使用“全局”模块,在其中导出我通过应用程序使用的所有内容。例如:
//Define your winston instance
winston.add(winston.transports.File, { filename: 'mylogfile.log' });
exports.logger = winston;
exports.otherGlobals = ....
Now just require this globally used module from your other modules
现在只需要从其他模块中使用这个全局使用的模块
var Global = require(/path/to/global.js);
Because the file is cached after the first time it is loaded (which you can verify by including a log statement in your global; it will only log once), there's very little overhead in including it again. Putting it all into one file is also easier than requiring ALL your globally used modules on every page.
因为文件在第一次加载后被缓存(您可以通过在全局中包含一个日志语句来验证;它只会记录一次),再次包含它的开销很小。将它们全部放入一个文件中也比要求在每一页上放置所有全局使用的模块更容易。
回答by user3575777
I wanted to use custom colours and levels.
我想使用自定义颜色和级别。
So I removed the default console-transport and set a colorized one
所以我删除了默认的控制台传输并设置了一个彩色的
here is my logger.js
这是我的logger.js
var logger = require('winston');
logger.setLevels({
debug:0,
info: 1,
silly:2,
warn: 3,
error:4,
});
logger.addColors({
debug: 'green',
info: 'cyan',
silly: 'magenta',
warn: 'yellow',
error: 'red'
});
logger.remove(logger.transports.Console);
logger.add(logger.transports.Console, { level: 'debug', colorize:true });
module.exports = logger;
Loading from app.js:
从 app.js 加载:
var logger = require('./lib/log.js');
Loading from other modules:
从其他模块加载:
var logger = require('winston');
回答by chrisvdb
Slightly off topic (as the OP asks about Winston), but I like the 'child-logger' approach by Bunyan:
有点偏离主题(因为 OP 询问温斯顿),但我喜欢 Bunyan 的“儿童记录器”方法:
var bunyan = require('bunyan');
var log = bunyan.createLogger({name: 'myapp'});
app.use(function(req, res, next) {
req.log = log.child({reqId: uuid()});
next();
});
app.get('/', function(req, res) {
req.log.info({user: ...});
});
It solves the OP's problem as the logger is available through the req object (hence no need for 'require(log)' in each module). Additionally, all log entries belonging to a particular request will have a unique ID that connects them together.
它解决了 OP 的问题,因为记录器可通过 req 对象使用(因此不需要每个模块中的“require(log)”)。此外,属于特定请求的所有日志条目都将具有将它们连接在一起的唯一 ID。
{"name":"myapp","hostname":"pwony-2","pid":14837,"level":30,"reqId":"XXXX-XX-XXXX","user":"[email protected]","time":"2014-05-26T18:27:43.530Z","v":0}
I'm not sure if Winston supports this as well.
我不确定温斯顿是否也支持这一点。
回答by Kevin Struillou
I'm creating a new Winston logger.
我正在创建一个新的 Winston 记录器。
log.js
日志文件
'use strict';
const winston = require('winston');
module.exports = new(winston.Logger)({
transports: [
new(winston.transports.Console)({
level: 'info'
})
]
});
a.js
js
const log = require('./log');
log.info("from a.js");
b.js
js
const log = require('./log');
log.info("from b.js");
回答by Haijin
I am working on Winston 3.0.0right now. And it seems the way to configure the default logger has changed a little bit. The way that works for me is folloing:
我现在正在开发Winston 3.0.0。似乎配置默认记录器的方式发生了一些变化。对我有用的方法如下:
log.js// the setting for global logger
log.js// 全局记录器的设置
const winston= require('winston');
winston.configure({
level:"debug",
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
),
transports: [
new winston.transports.Console()
]
});
The other part is the same.
In the beginning of you application, require('log.js'), and also require ('winston'),While in all other files, simply require('winston')
另一部分是一样的。在您应用程序的开头require('log.js'),以及require ('winston'),在所有其他文件中,只需require('winston')
.
.
回答by veeresh yh
if you want to make the logger a global variable- you have to do specifically by assign it to the global variable like so
如果你想让记录器成为一个全局变量 - 你必须像这样将它分配给全局变量
logger.js
记录器.js
var winston = require('winston')
var winston = winston.createLogger({
transports: [
new (winston.transports.Console)(),
new (winston.transports.File)({
filename: './logs/logger.log'
})
]
});
module.exports=winston;
app.js
应用程序.js
let logger = require('./logger')
global.__logger = logger
someController.js
someController.js
__logger.info('created log successfully')
Note: it's good practice to assign a prefix for every global variable so you will know that is a global one. i'm using __ as prefix (double low dash)
注意:为每个全局变量分配一个前缀是一种很好的做法,这样您就会知道这是一个全局变量。我使用 __ 作为前缀(双低破折号)
回答by Carmine Ingaldi
In my team we have created a private npm package with all default configs (as you've shown in previous answers)
在我的团队中,我们创建了一个包含所有默认配置的私有 npm 包(如您在之前的答案中所示)
I've just one question: would it be a good practice to declare the logger object as a global in order to avoid import in each and every module?
我只有一个问题:将记录器对象声明为全局对象以避免在每个模块中进行导入是否是一个好习惯?
回答by Kiran Mali
Here is my logger configuration with winston version is 3.2.1.
这是我的 winston 版本的记录器配置是3.2.1.
It storing logs in application.logfile and for error stack trace I am using errors({ stack: true })and small trick in printffunction to print stack trace in error case.
它将日志存储在application.log文件中并用于我正在使用的错误堆栈跟踪,errors({ stack: true })以及printf在错误情况下打印堆栈跟踪的小技巧。
Configuration
配置
const {format, transports} = require('winston');
const { timestamp, colorize, printf, errors } = format;
const { Console, File } = transports;
LoggerConfig = {
level: process.env.LOGGER_LEVEL || 'debug',
transports: [
new Console(),
new File({filename: 'application.log'})
],
format: format.combine(
errors({ stack: true }),
timestamp(),
colorize(),
printf(({ level, message, timestamp, stack }) => {
if (stack) {
// print log trace
return `${timestamp} ${level}: ${message} - ${stack}`;
}
return `${timestamp} ${level}: ${message}`;
}),
),
expressFormat: true, // Use the default Express/morgan request formatting
colorize: false, // Color the text and status code, using the Express/morgan color palette (text: gray, status: default green, 3XX cyan, 4XX yellow, 5XX red).
ignoreRoute: function (req, res) {
return false;
} // optional: allows to skip some log messages based on request and/or response
}
Declare
宣布
I am using this same configuration in express-winstonand for general log also. I declared __loggerobject globally so that you don't need to import every time in every file. Generally in node js all the global variable prefix with 2 time underscore(__) so it will be good to follow this.
我express-winston也在一般日志中使用相同的配置。我__logger全局声明了对象,这样您就不需要每次都在每个文件中导入。通常在节点 js 中,所有全局变量前缀都带有 2 次下划线(__),所以最好遵循这一点。
Server.js
服务器.js
const winston = require('winston');
const expressWinston = require('express-winston');
/**
* winston.Logger
* logger for specified log message like console.log
*/
global.__logger = winston.createLogger(LoggerConfig);
/**
* logger for every HTTP request comes to app
*/
app.use(expressWinston.logger(LoggerConfig));
Use
用
__loggeris global so you can use it any place, for example:
__logger是全局的,因此您可以在任何地方使用它,例如:
blog.controller.js
blog.controller.js
function save(req, res) {
try {
__logger.debug('Blog add operation');
.
.
return res.send(blog);
} catch (error) {
__logger.error(error);
return res.status(500).send(error);
}
}
Hope this will help !
希望这会有所帮助!
回答by Jason
I use a factory function and pass in the module name so it can be added to the meta data:
我使用工厂函数并传入模块名称,以便将其添加到元数据中:
logger-factory.js
logger-factory.js
const path = require('path');
const { createLogger, format, transports } = require('winston');
const { combine, errors, timestamp } = format;
const baseFormat = combine(
timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
errors({ stack: true }),
format((info) => {
info.level = info.level.toUpperCase();
return info;
})(),
);
const splunkFormat = combine(
baseFormat,
format.json(),
);
const prettyFormat = combine(
baseFormat,
format.prettyPrint(),
);
const createCustomLogger = (moduleName) => createLogger({
level: process.env.LOG_LEVEL,
format: process.env.PRETTY_LOGS ? prettyFormat : splunkFormat,
defaultMeta: { module: path.basename(moduleName) },
transports: [
new transports.Console(),
],
});
module.exports = createCustomLogger;
app-harness.js (so I can run the exported index module)
app-harness.js(所以我可以运行导出的索引模块)
const index = require('./index');
// https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html
const sampleEvent = {
"Records": [
{
"eventVersion": "2.1",
"eventSource": "aws:s3",
"awsRegion": "us-east-2",
"eventTime": "2019-09-03T19:37:27.192Z",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "AWS:AIDAINPONIXQXHT3IKHL2"
},
"requestParameters": {
"sourceIPAddress": "205.255.255.255"
},
"responseElements": {
"x-amz-request-id": "D82B88E5F771F645",
"x-amz-id-2": "vlR7PnpV2Ce81l0PRw6jlUpck7Jo5ZsQjryTjKlc5aLWGVHPZLj5NeC6qMa0emYBDXOo6QBU0Wo="
},
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "828aa6fc-f7b5-4305-8584-487c791949c1",
"bucket": {
"name": "lambda-artifacts-deafc19498e3f2df",
"ownerIdentity": {
"principalId": "A3I5XTEXAMAI3E"
},
"arn": "arn:aws:s3:::lambda-artifacts-deafc19498e3f2df"
},
"object": {
"key": "b21b84d653bb07b05b1e6b33684dc11b",
"size": 1305107,
"eTag": "b21b84d653bb07b05b1e6b33684dc11b",
"sequencer": "0C0F6F405D6ED209E1"
}
}
}
]
};
index.handler(sampleEvent)
.then(() => console.log('SUCCESS'))
.catch((_) => console.log('FAILURE'));
index.js
索引.js
const logger = require('./logger-factory')(__filename);
const app = require('./app');
exports.handler = async function (event) {
try {
logger.debug('lambda triggered with event', { event });
await app.run(event);
logger.debug(`lambda finished`);
} catch(error) {
logger.error('lambda failed: ', error);
// rethrow the error up to AWS
throw error;
}
}
app.js
应用程序.js
const logger = require('./logger-factory')(__filename);
const run = async (event) => {
logger.info('processing S3 event', event);
try {
logger.info('reading s3 file')
// throws because I used "Record" instead of "Records"
const s3 = event.Record[0].s3;
// use s3 to read the file
} catch (error) {
logger.error('failed to read from S3: ', error);
throw error;
}
};
module.exports = { run };
when I run the application locally at WARNlevel:
当我在本地运行应用程序时WARN:
~/repos/ghe/lambda-logging (master * u=)> LOG_LEVEL=warn node -r dotenv/config ./src/app-harness.js
{
module: 'app.js',
level: 'ERROR',
message: "failed to read from S3: Cannot read property '0' of undefined",
stack: "TypeError: Cannot read property '0' of undefined\n" +
' at Object.run (/Users/jason.berk/repos/ghe/lambda-logging/src/app.js:8:28)\n' +
' at Object.exports.handler (/Users/jason.berk/repos/ghe/lambda-logging/src/index.js:7:15)\n' +
' at Object.<anonymous> (/Users/jason.berk/repos/ghe/lambda-logging/src/test-harness.js:44:7)\n' +
' at Module._compile (internal/modules/cjs/loader.js:1158:30)\n' +
' at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)\n' +
' at Module.load (internal/modules/cjs/loader.js:1002:32)\n' +
' at Function.Module._load (internal/modules/cjs/loader.js:901:14)\n' +
' at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)\n' +
' at internal/main/run_main_module.js:18:47',
timestamp: '2020-05-11 17:34:06'
}
{
module: 'index.js',
level: 'ERROR',
message: "lambda failed: Cannot read property '0' of undefined",
stack: "TypeError: Cannot read property '0' of undefined\n" +
' at Object.run (/Users/jason.berk/repos/ghe/lambda-logging/src/app.js:8:28)\n' +
' at Object.exports.handler (/Users/jason.berk/repos/ghe/lambda-logging/src/index.js:7:15)\n' +
' at Object.<anonymous> (/Users/jason.berk/repos/ghe/lambda-logging/src/test-harness.js:44:7)\n' +
' at Module._compile (internal/modules/cjs/loader.js:1158:30)\n' +
' at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)\n' +
' at Module.load (internal/modules/cjs/loader.js:1002:32)\n' +
' at Function.Module._load (internal/modules/cjs/loader.js:901:14)\n' +
' at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)\n' +
' at internal/main/run_main_module.js:18:47',
timestamp: '2020-05-11 17:34:06'
}
when I run at DEBUGlevel:
当我在DEBUG级别运行时:
~/repos/ghe/lambda-logging (master * u=)> LOG_LEVEL=debug node -r dotenv/config ./src/test-harness.js
{
module: 'index.js',
event: {
Records: [
{
eventVersion: '2.1',
eventSource: 'aws:s3',
awsRegion: 'us-east-2',
eventTime: '2019-09-03T19:37:27.192Z',
eventName: 'ObjectCreated:Put',
userIdentity: { principalId: 'AWS:AIDAINPONIXQXHT3IKHL2' },
requestParameters: { sourceIPAddress: '205.255.255.255' },
responseElements: {
'x-amz-request-id': 'D82B88E5F771F645',
'x-amz-id-2': 'vlR7PnpV2Ce81l0PRw6jlUpck7Jo5ZsQjryTjKlc5aLWGVHPZLj5NeC6qMa0emYBDXOo6QBU0Wo='
},
s3: {
s3SchemaVersion: '1.0',
configurationId: '828aa6fc-f7b5-4305-8584-487c791949c1',
bucket: {
name: 'lambda-artifacts-deafc19498e3f2df',
ownerIdentity: { principalId: 'A3I5XTEXAMAI3E' },
arn: 'arn:aws:s3:::lambda-artifacts-deafc19498e3f2df'
},
object: {
key: 'b21b84d653bb07b05b1e6b33684dc11b',
size: 1305107,
eTag: 'b21b84d653bb07b05b1e6b33684dc11b',
sequencer: '0C0F6F405D6ED209E1'
}
}
}
]
},
level: 'DEBUG',
message: 'lambda triggered with event',
timestamp: '2020-05-11 17:38:21'
}
{
module: 'app.js',
Records: [
{
eventVersion: '2.1',
eventSource: 'aws:s3',
awsRegion: 'us-east-2',
eventTime: '2019-09-03T19:37:27.192Z',
eventName: 'ObjectCreated:Put',
userIdentity: { principalId: 'AWS:AIDAINPONIXQXHT3IKHL2' },
requestParameters: { sourceIPAddress: '205.255.255.255' },
responseElements: {
'x-amz-request-id': 'D82B88E5F771F645',
'x-amz-id-2': 'vlR7PnpV2Ce81l0PRw6jlUpck7Jo5ZsQjryTjKlc5aLWGVHPZLj5NeC6qMa0emYBDXOo6QBU0Wo='
},
s3: {
s3SchemaVersion: '1.0',
configurationId: '828aa6fc-f7b5-4305-8584-487c791949c1',
bucket: {
name: 'lambda-artifacts-deafc19498e3f2df',
ownerIdentity: { principalId: 'A3I5XTEXAMAI3E' },
arn: 'arn:aws:s3:::lambda-artifacts-deafc19498e3f2df'
},
object: {
key: 'b21b84d653bb07b05b1e6b33684dc11b',
size: 1305107,
eTag: 'b21b84d653bb07b05b1e6b33684dc11b',
sequencer: '0C0F6F405D6ED209E1'
}
}
}
],
level: 'INFO',
message: 'processing S3 event',
timestamp: '2020-05-11 17:38:21'
}
{
message: 'reading s3 file',
level: 'INFO',
module: 'app.js',
timestamp: '2020-05-11 17:38:21'
}
{
module: 'app.js',
level: 'ERROR',
message: "failed to read from S3: Cannot read property '0' of undefined",
stack: "TypeError: Cannot read property '0' of undefined\n" +
' at Object.run (/Users/jason.berk/repos/ghe/lambda-logging/src/app.js:8:28)\n' +
' at Object.exports.handler (/Users/jason.berk/repos/ghe/lambda-logging/src/index.js:7:15)\n' +
' at Object.<anonymous> (/Users/jason.berk/repos/ghe/lambda-logging/src/test-harness.js:44:7)\n' +
' at Module._compile (internal/modules/cjs/loader.js:1158:30)\n' +
' at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)\n' +
' at Module.load (internal/modules/cjs/loader.js:1002:32)\n' +
' at Function.Module._load (internal/modules/cjs/loader.js:901:14)\n' +
' at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)\n' +
' at internal/main/run_main_module.js:18:47',
timestamp: '2020-05-11 17:38:21'
}
{
module: 'index.js',
level: 'ERROR',
message: "lambda failed: Cannot read property '0' of undefined",
stack: "TypeError: Cannot read property '0' of undefined\n" +
' at Object.run (/Users/jason.berk/repos/ghe/lambda-logging/src/app.js:8:28)\n' +
' at Object.exports.handler (/Users/jason.berk/repos/ghe/lambda-logging/src/index.js:7:15)\n' +
' at Object.<anonymous> (/Users/jason.berk/repos/ghe/lambda-logging/src/test-harness.js:44:7)\n' +
' at Module._compile (internal/modules/cjs/loader.js:1158:30)\n' +
' at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)\n' +
' at Module.load (internal/modules/cjs/loader.js:1002:32)\n' +
' at Function.Module._load (internal/modules/cjs/loader.js:901:14)\n' +
' at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)\n' +
' at internal/main/run_main_module.js:18:47',
timestamp: '2020-05-11 17:38:21'
}

