まえがき
以前の記事「ElixirとPlugで静的Webサーバを作ってみる」で、Plug.Loggerモジュールの標準の形式でアクセスログの出力を行った。しかし、このままでは、出力サンプル程度のログ情報しか出力されないので、出力内容をカスタマイズする。
PlugパイプラインでのPlug.Loggerモジュール呼び出し
上記の記事のプログラムでは、Plugパイプラインの中でPlug.Loggerモジュールを呼び出している。ログ出力をカスタマイズするには、Plug.Loggerモジュールの代わりに、カスタマイズしたモジュールを呼び出す。
defmodule SimpleHttpd.PlugTop do
...
def call(conn, [app: app]) do
...
conn = Plug.Logger.call(conn, :debug)
...
ログ出力モジュールのカスタマイズ
Plug.Loggerモジュールの挙動は単純で、Plugパイプラインから呼び出される call/2ファンクションで、Conn.register_before_send/2ファンクションを使って、リクエストに対する処理が終わったときに、Logger.log/2ファンクションを呼び出して、ログ出力を行う。
Plugモジュールに組み込まれている Plug.Loggerモジュールの大まかな構成を図示する。
defmodule Plug.Logger do
...
def call(conn, level) do
Logger.log(level, ...) # リクエストに対する処理開始時点のログ出力
...
Conn.register_before_send(conn, fn conn ->
Logger.log(level, ...) # リクエストに対する処理終了時点のログ出力
conn
end)
end
end
ログ出力をカスタマイズするには、Plug.Loggerモジュールをひな形にして、自身のログ出力モジュールを作成すれば良い。以下に、サンプルを掲げる。
defmodule SimpleHttpd.Logger do
require Logger
def init(plug_opts) do
plug_opts
end
def call(conn, level) do
start = System.monotonic_time()
Plug.Conn.register_before_send(conn, fn conn ->
Logger.log(level, fn ->
stop = System.monotonic_time()
diff = System.convert_time_unit(stop - start, :native, :microsecond)
# ログ出力データ。不正な文字のエスケープ等、適切なフォーマッティングを行うこと。
[to_string(conn.scheme), ?,,
conn.method, ?,,
conn.request_path, ?,,
conn.query_string, ?,,
Integer.to_string(conn.status), ?,,
conn.host, ?,,
Integer.to_string(diff)]
end)
conn
end)
end
end
最後に、Plugパイプラインから、作成したモジュールを呼び出す。
conn = SimpleHttpd.Logger.call(conn, :debug)
あるいは、Plug Builderで呼び出す。
plug SimpleHttpd.Logger, log: :debug
Loggerによるログ出力は、実行のやり方に応じて、コンソールやファイルに出力される。