初始项目【传送门】
安装
npm i morgan
使用
编辑app.js,新增:
const morgan = require('morgan');
app.use(morgan('short'))
用apifox调用一个接口localhost:3000/api/sign-up
看看输出,没有使用morgan
的时候输出是:
Executing (default): SELECT "id", "firstName", "lastName", "email" FROM "Users" AS "User" ORDER BY "User"."id" DESC LIMIT 5;
使用morgan的时候,输出增加了日志
Executing (default): SELECT "id", "firstName", "lastName", "email" FROM "Users" AS "User" ORDER BY "User"."id" DESC LIMIT 5;
::1 - GET /api/sign-up HTTP/1.1 200 152 - 45.585 ms
打印日志到本地
morgan支持stream配置项,可以实现日志落地:
const fs = require('fs')
const path = require('path')
const accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'});
app.use(morgan('short', {stream: accessLogStream}));
调用一下接口,项目根目录下多出了一个access.log
文件,这里记录日志内容
::1 - GET /api/sign-up HTTP/1.1 200 152 - 43.344 ms
morgan(format, options)
- format可以是预定义的几种字符串类型或者是自定义方法,预定义的类型有:
tiny / short / dev / common / combined
- token是format的组成部分,例如
:remote-user
:method
:url
等等
// common的输出格式
:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]
// short的输出格式
:remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms
使用预定义格式
morgan('tiny')
使用预定义的token自由组合输出格式
morgan(':method :url :status :res[content-length] - :response-time ms')
使用自定义方法的输出格式
morgan(function (tokens, req, res) {
return [
tokens.method(req, res),
tokens.url(req, res),
tokens.status(req, res),
tokens.res(req, res, 'content-length'), '-',
tokens['response-time'](req, res), 'ms'
].join(' ')
})
使用morgan.format()方法自定义format
morgan.format('common', ':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]')
app.use(morgan('common', {
stream: accessLogStream,
// skip: function(req,res) { return res.statusCode < 400 }
}));
使用morgan.token()方法自定义token
// 自定义token
morgan.token('body',function(req,res){
return req.body ? JSON.stringify(req.body) : '-'
})
// 自定义format,其中包含自定义的token
morgan.format('short', ':remote-addr :remote-user [:date[clf]] :method :body :url HTTP/:http-version :status :res[content-length] - :response-time ms');
// 使用自定义的format
app.use(morgan('short'));
options可选配置
- immediate 布尔值,默认是false,请求返回后再记录日志;当为true时,一收到请求就记录日志。
- skip 是否跳过记录
- stream 日志的输出流配置
// skip配置
app.use(morgan('common', {
stream: accessLogStream,
skip: function(req,res) { return res.statusCode < 400 }
}));
日志切割file-stream-rotator
把日志全部放在一个文件里,没有进行管理,时间长了文件会变得很大,而且不利于查看,这时候就需要用日志分割了。我们使用file-stream-rotator这个工具
npm install file-stream-rotator
编辑app.js
const FileStreamRotator = require('file-stream-rotator')
const logDirectory = path.join(__dirname, 'log')
fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory)
const rotateLogStream = FileStreamRotator.getStream({
date_format: 'YYYYMMDD',
filename: path.join(logDirectory,'access-%DATE%.log'),
frequency: 'daily',
verbose: false,
max_logs: 10
})
rotateLogStream.on('rotate',function(oldFile,newFile)){
// 旧日志删除或压缩前的回调
}
参数解析
- filename: 定义日志文件的名称
- date_format: 根据moment.js替换filename中的
DATA
字段 - frequency: 切割的频率,可选值有daily、custom、test,如果设置为test则会按分钟进行日志切割,前提是没有filename的设置和分钟切割不冲突。若没有设置frequency,日志名称末尾也会自带'YYYY-MM-DD'
- size: 日志的大小限制,采用数字+单位,可用单位有k / m / g,例如
10k
- max_logs: 需要保留的日志文件数,多余的自动删除,可以直接用数字,表示文件个数;或者数字+d,表示保留天数
// test模式
FileStreamRotator.getStream({filename: '/logs/access-%DATE%.log',frequency: 'test', verbose: false})
// 根据日志大小切割,并配置保存的日志文件数量,audit_file存放位置
FileStreamRotator.getStream({filename: '/logs/access.log',size: '50k' max_logs: 5, verbose: false, audit_file:"/tmp/logaudit.json", extension: '.log'})
最后编辑.gitignore
文件让git不要追踪logs文件的变化
logs/
最终代码
const express = require('express');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const multer = require('multer')
const PATH = './uploads/'
const fs = require('fs')
const path = require('path')
// router import
const user = require('./routes/user')
const app = express();
const FileStreamRotator = require('file-stream-rotator')
const logDirectory = path.join(__dirname, 'log')
fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory)
const rotateLogStream = FileStreamRotator.getStream({
date_format: 'YYYYMMDD',
filename: path.join(logDirectory,'access-%DATE%.log'),
frequency: 'daily',
verbose: false,
max_logs: 10,
size: '50k'
})
// const accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'});
// morgan.token('from',function(req,res){
// return req.query.from || '-'
// })
morgan.token('body',function(req,res){
return req.body ? JSON.stringify(req.body) : '-'
})
morgan.format('short', ':remote-addr :remote-user [:date[clf]] :method :body :url HTTP/:http-version :status :res[content-length] - :response-time ms');
app.use(express.json())
app.use(morgan('short', {
stream: rotateLogStream,
// stream: accessLogStream,
skip: function(req,res) { return res.statusCode < 400 }
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// Routing
app.use('/api', user)
// set port, listen for requests
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
参考
www.cnblogs.com/chyingp/p/n… github.com/expressjs/m… github.com/rogerc/file…