入门
morgan是express默认的日志中间件,也可以脱离express,作为node.js的日志组件单独使用
- 简单例子index.js:
var express = require('express');
var app = express();
var morgan = require('morgan');
app.use(morgan('short'));
app.use(function(req, res, next){
res.send('ok');
});
app.listen(3000);
node index.js
运行程序,并在浏览器里访问 http://127.0.0.1:3000
,打印日志如下:
::1 - GET / HTTP/1.1 200 2 - 3.487 ms
::1 - GET /favicon.ico HTTP/1.1 200 2 - 0.591 ms
核心API
morgan的API非常少,使用频率最高的就是morgan(),作用是返回一个express日志中间件。
morgan(format, options)
参数说明如下:
- format:可选,morgan与定义了几种日志格式,每种格式都有对应的名称,比如
combined
、short
等,默认是- ----default
。不同格式的差别可参考这里。 - options:可选,配置项,包含
stream
(常用)、skip
、immediate
。 - stream:日志的输出流配置,默认是process.stdout。
- skip:是否跳过日志记录,使用方式可以参考这里。
- immediate:布尔值,默认是false。当为true时,一收到请求,就记录日志;如果为false,则在请求返回后,再记录日志。
自定义日志格式:
morgan.format(name, format); // 自定义日志格式
morgan.token(name, fn); // 自定义token
- format:
name
是自定义的名称,format
是自定义的模块变量组合,例子:
morgan.format('test', '[test] :method :url :status');
app.use(morgan('test'));
输出:
[test] GET / 304
[test] GET /favicon.ico 200
- token:
name
模块的字符,fn
渲染时运行并返回 设定string
值,例子:
// 自定义token
morgan.token('from', function(req, res){
return req.query.from || '-';
});
// 自定义format,其中包含自定义的token
morgan.format('test', '[test] :method :url :status :from');
运行程序,并在浏览器里先后访问 http://127.0.0.1:3000/hello?from=app
和 http://127.0.0.1:3000/hello?from=pc
[test] GET /hello?from=app 200 app
[test] GET /favicon.ico 304 -
[test] GET /hello?from=pc 200 pc
[test] GET /favicon.ico 304 -
中级使用
将日志打印到本地文件
var express = require('express');
var app = express();
var morgan = require('morgan');
var fs = require('fs');
var path = require('path');
var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'});
app.use(morgan('short', {stream: accessLogStream}));
app.use(function(req, res, next){
res.send('ok');
});
app.listen(3000);
高级使用
日志切割
一个线上应用,如果所有的日志都落地到同一个本地文件,时间久了,文件会变得非常大,既影响性能,又不便于查看。这时候,就需要用到日志分割了。
借助file-stream-rotator
插件,可以轻松完成日志分割的工作。
var FileStreamRotator = require('file-stream-rotator')
var express = require('express')
var fs = require('fs')
var morgan = require('morgan')
var path = require('path')
var app = express()
var logDirectory = path.join(__dirname, 'log')
// ensure log directory exists
fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory)
// create a rotating write stream
var accessLogStream = FileStreamRotator.getStream({
date_format: 'YYYYMMDD',
filename: path.join(logDirectory, 'access-%DATE%.log'),
frequency: 'daily',
verbose: false
})
// setup the logger
app.use(morgan('combined', {stream: accessLogStream}))
app.get('/', function (req, res) {
res.send('hello, world!')
})
app.listen(3000)
日志写入数据库
有的时候,我们会有这样的需求,将访问日志写入数据库。这种需求常见于需要实时查询统计的日志系统。
在morgan
里该如何实现呢?从文档上,并没有看到适合的扩展接口。于是查阅了下morgan
的源码,发现实现起来非常简单。
回顾下之前日志写入本地文件的例子,最关键的两行代码如下。通过stream
指定日志的输出流。
var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'});
app.use(morgan('short', {stream: accessLogStream}));
在morgan内部,大致实现是这样的(简化后)。
// opt为配置文件
var stream = opts.stream || process.stdout;
var logString = createLogString(); // 伪代码,根据format、token的定义,生成日志
stream.write(logString);
于是,可以用比较取巧的方式来实现目的:声明一个带write
方法的对象,并作为stream
配置传入。
var express = require('express');
var app = express();
var morgan = require('morgan');
// 带write方法的对象
var dbStream = {
write: function(line){
console.log(line);// 正常输出
saveToDatabase(line); // 伪代码,保存到数据库
}
};
// 将 dbStream 作为 stream 配置项的值
app.use(morgan('short', {stream: dbStream}));
app.use(function(req, res, next){
res.send('ok');
});
app.listen(3000);
相关
如果觉得文章对你有点用的话,麻烦拿出手机,这里有一个你我都有的小福利(每天一次): 打开支付宝首页搜索“8601304”,即可领红包。谢谢支持