2015年9月23日水曜日

node.jsでのログ出力:morgan

node.jsでのログ出力について備忘録。

morgan

 express 4でアクセスログ出力に使われているモジュール。
 参考にささせていただいたのは以下のサイト。
 http://qiita.com/hoshi-takanori/items/7f5602d7fd7ee0fa6427
 https://github.com/expressjs/morgan

■インストール
1.package.jsonに追加

  例:
{
  "name": "sample_prject",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.12.4",
    "cookie-parser": "~1.3.5",
    "debug": "~2.2.0",
    "ejs": "~2.3.1",
    "express": "~4.12.4",
    "morgan": "~1.5.3",
    "serve-favicon": "~2.2.1",
    "validator": "^3.40.1"
  }
}

2.インストール
 $ npm install
 
(expressでテンプレートを作るとついてくる)
書式:morgan(format[, options])


"format"は、ログのフォーマットを指定する引数。あらかじめ定義されたフォーマットがある。


combined
Apache combinedログフォーマット。デフォルト。tokenを使って書くと以下の通り
:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
出力される内容は以下の通り。
::ffff:192.168.33.1 - - [23/Sep/2015:17:04:07 +0000] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36"

formatcombinedApache combinedログフォーマット。デフォルト。tokenを使って書くと以下の通り
:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
commonApache commonログフォーマット。tokenを使って書くと以下の通り
:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]
devhttp status code毎に色付けして表示されるログ。サーバエラーの場合は赤、クライアントエラーの場合は黄色、Ridirectはシアンで表示される。tokenを使って書くと以下の通り
:remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms
shortデフォルト(combined)より短いフォーマット。tokenを使って書くと以下の通り
:remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms
tiny一番短いログフォーマット。tokenを使って書くと以下の通り
:method :url :status :res[content-length] - :response-time ms
optionsimmediateリクエストを受けた時点でログ出力をする。サーバがCrashしたとき絵も出力されるが、レスポンス時間やコンテキスト長などレスポンスに関する情報は記録されない
skip特定の条件でログを出力しない場合に使う。以下の例では、HTTPのステータスコードが400未満の場合はログ出力をしない。デフォルトは、falseになっている(つまりすべて出力)。
例)
morgan('combined', {
  skip: function (req, res) { return res.statusCode < 400 }
})
streamOutputストリーム。デフォルトは、process.stdoutになっている

使用できるtokenは以下の通り。
:date[format]現時刻。指定できるフォーマットは以下の通り。
clf  common log format。例:10/Oct/2000:13:55:36 +0000
iso  ISO 8601 date time format。例:2000-10-10T13:55:36.000Z
web RFC1123 date time format。例:Tue, 10 Oct 2000 13:55:36 GMT

:http-versionリクエストされたHTTPのバージョン
:methodリクエストのHTTPメソッド
:referrerリクエストのReferrerヘッダー。ミススペルでRefererがあった場合はそれを使う。
:remote-addrリクエストのリモートアドレス。req.ipが使われる。そうでなければreq.connection.remoteAddressが使われる
:remote-user基本認証された場合のユーザID。
:req[header]リクエストの[header]で指定されたヘッダー
:res[header]レスポンスの[header]で指定されたヘッダー
:response-timeリクエストがmorganに来てから、レスポンスヘッダーがかかれるまでの所要時間(ms)
:statusレスポンスのstatus code。レスポンスがクライアントに送信される前に、クライアント側からTCP/IPセッションがクローズされるなどが発生した場合は、ブランクとなる。
:urlリクエストされたURL。req.originalUrlがあればそれを、なければreq.urlが使われる
:user-agentリクエストのUser-Agentヘッダーの値。

また作成することもできる。以下は、content-typeを示す"type"というtokenを作成する例。

morgan.token('type', function(req, res){ return req.headers['content-type']; })

 ・使用例
morganの実施の使用例を以下に。

ログをファイルに出力する例
pathモジュールを入れておく。
$ npm install path --save
var express = require('express')
var fs = require('fs')
var morgan = require('morgan')

var app = express()

// create a write stream (in append mode)
var accessLogStream = fs.createWriteStream(__dirname + '/access.log', {flags: 'a'})

// setup the logger
app.use(morgan('combined', {stream: accessLogStream}))

app.get('/', function (req, res) {
  res.send('hello, world!')
})
ちなみに、createWriteStreamの仕様については以下を参照。
https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_options


ログファイルをローテーションする例。
file-stream-rotatorというモジュールを使う。
$ npm install file-stream-rotator --save
var FileStreamRotator = require('file-stream-rotator')
var express = require('express')
var fs = require('fs')
var morgan = require('morgan')

var app = express()
var logDirectory = __dirname + '/log'

// ディレクトリがなければ作成する
fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory)

// write streamをローテーションする設定
var accessLogStream = FileStreamRotator.getStream({
  filename: logDirectory + '/access-%DATE%.log',
  frequency: 'daily',
  verbose: false,
  date_format: "YYYY-MM-DD"
})

// 今回はcombinedで出力
app.use(morgan('combined', {stream: accessLogStream}))

app.get('/', function (req, res) {
  res.send('hello, world!')
})


独自tokenを使う例
Webアプリなどでも使われる(らしい)UUIDを生成して、それをログに記録する例。
var express = require('express')
var morgan = require('morgan')
var uuid = require('node-uuid')

morgan.token('id', function getId(req) {
  return req.id
})

var app = express()

app.use(assignId)
app.use(morgan(':id :method :url :response-time'))

app.get('/', function (req, res) {
  res.send('hello, world!')
})

function assignId(req, res, next) {
  req.id = uuid.v4()
  next()
}
ちなみに、node-uuidの仕様については以下を参照。
https://github.com/broofa/node-uuid
◆winston