如何使用 Morgan 在请求和响应之间正确拆分日志记录?

How to properly split logging between requests and responses with Morgan?

Morgan's documentation 描述了可以拆分请求和响应的日志记录:

split / dual logging

The morgan middleware can be used as many times as needed, enabling combinations like:

  • Log entry on request and one on response
  • Log all requests to file, but errors to console

在他们唯一的相关示例中,有一些评论描述了一个中间件将错误响应记录到控制台,另一个请求记录到文件:

// log only 4xx and 5xx responses to console
app.use(morgan('dev', {
  skip: function (req, res) { return res.statusCode < 400 }
}))

// log all requests to access.log
app.use(morgan('common', {
  stream: fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'})
}))

这似乎实现了将所有请求记录到文件并将错误记录到控制台的第二个示例,但不是第一个。

我有点迷茫,我不明白是什么告诉 morgan 只记录请求或只记录响应。我是否需要关心将这些中间件放在哪里?

目前,我有一个用于请求和响应的日志条目,我猜:

morgan('[:date[clf]] :remote-addr :url :method HTTP/:http-version :status :remote-user :res[content-length] :referrer :user-agent :response-time ms', {
  stream: {
    write: (message) => {
      winston.silly(message.trim());
    }
  }
});

那么,如何在 morgan 中间件调用中正确记录 requests,在另一个中间件调用中正确记录 responses

我已经使用 immediate 选项在请求和响应之间拆分 Morgan 日志记录:

immediate

Write log line on request instead of response. This means that a requests will be logged even if the server crashes, but data from the response (like the response code, content length, etc.) cannot be logged.

因此,不要使用这种混合日志记录:

app.use(morgan(':remote-addr :url :method HTTP/:http-version :status :res[content-length] :user-agent :response-time ms', {
  stream: {
    write: (message) => {
      winston.info(message.trim());
    }
  }
}));

可以将它们分开,并以正确的顺序登录:

// Logs requests
app.use(morgan(':remote-addr :url :method HTTP/:http-version :user-agent', {
  // https://github.com/expressjs/morgan#immediate
  immediate: true,
  stream: {
    write: (message) => {
      winston.info(message.trim());
    }
  }
}));

// Logs responses
app.use(morgan(':remote-addr :url :method :status :res[content-length] :response-time ms', {
  stream: {
    write: (message) => {
      winston.info(message.trim());
    }
  }
}));

注意:由于 express just enhances Node's own request and response objects,我相信它在内部 res.on('finish', req => { /* log stuff */ }),当它没有设置为 immediate