Denoでコンソールとログファイルにログを出力する
Denoでコンソール出力をログファイルにも残しておきたいと思いました。
ミニマルなやり方の日本語解説記事が見当たらなかったので解説します。
std/logを使う
標準ライブラリに用意されています。
現在の最新版は@0.99.0
です。
consoleとfileに出力する
上記ライブラリのREADMEを参考にログを作成します。
要件は以下とします。
- ログレベルは
DEBUG
以上(つまりすべて) - 出力ファイル名は
./app.log
決め打ち - 出力フォーマットは
[日時] [レベル] [内容]
こんな感じでlogger.ts
を作ります。
import * as log from "https://deno.land/std@0.99.0/log/mod.ts";
// 出力ファイル名
const filename = "./app.log";
// 出力フォーマット
const formatter = "{datetime} {levelName} {msg}";
await log.setup({
handlers: {
// console出力形式の定義
console: new log.handlers.ConsoleHandler("DEBUG", {
formatter,
}),
// file出力形式の定義
file: new log.handlers.FileHandler("DEBUG", {
filename,
formatter,
}),
},
loggers: {
default: {
level: "DEBUG",
handlers: ["console", "file"],
},
},
});
// getLogger()を無引数で実行すると"default"のloggerを取得する
const Logger = log.getLogger();
console.log(`logfile: ${filename}`);
export { Logger };
これを読み込んで使います。
import { Logger } from "./logger.ts";
Logger.debug("This log is debug!");
Logger.info("This log is info!");
Logger.warning("This log is warning!");
Logger.error("This log is error!");
実行します。ログファイルに書き込むため、--allow-write=app.log
権限が必要です。
❯ deno run --allow-write=app.log main.ts
Check file:///Users/kawarimidoll/ghq/github.com/kawarimidoll/deno-log-practice/main.ts
logfile: ./app.log
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) DEBUG This log is debug!
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) INFO This log is info!
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) WARNING This log is warning!
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) ERROR This log is error!
ちゃんとレベルごとに色がついて出力されます。
app.log
の内容も確認しておきましょう。
❯ cat app.log
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) DEBUG This log is debug!
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) INFO This log is info!
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) WARNING This log is warning!
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) ERROR This log is error!
ログをファイルに残すことが出来ました。
フォーマットを調整する
各Handlerのformatter
オプションには関数を渡すことができるので、より細かいフォーマットの調整ができます。
まず、datetime
の出力がSun Jun 20 2021 09:35:23 GMT+0900 (日本標準時)
のようにDate
型そのままの出力になっているのがイケてません。
このままでは読みづらいし後から集計もしづらいので、 JavaScript ISO8601形式の日時表記を生成 - Qiita を参考にフォーマットします。
また、小さなことですが、DEBUG
INFO
WARNING
ERROR
でログ本文の開始位置がずれてしまうのも気になるので、padEnd()
を使ってこの差を吸収します。
logger.ts
を以下のように修正します。
import * as log from "https://deno.land/std@0.99.0/log/mod.ts";
+ import { LogRecord } from "https://deno.land/std@0.99.0/log/logger.ts";
// 出力ファイル名
const filename = "./app.log";
// 出力フォーマット
- const formatter = "{datetime} {levelName} {msg}";
+ const formatter = (logRecord: LogRecord) => {
+ const { datetime, levelName, msg } = logRecord;
+
+ // 日付の形式を調整
+ const d = new Date(datetime.getTime() - datetime.getTimezoneOffset() * 6e4);
+ const logTime = d.toISOString().slice(0, -5) +
+ d.toString().replace(/^.*GMT([-+]\d{2})(\d{2}).*$/, "$1:$2");
+
+ // levelの文字数を調整
+ return `${logTime} ${levelName.padEnd(7)} ${msg}`;
+ };
await log.setup({
// 以降省略
これで再度実行します。
❯ deno run --allow-write=app.log main.ts
Check file:///Users/kawarimidoll/ghq/github.com/kawarimidoll/deno-log-practice/main.ts
logfile: ./app.log
2021-06-20T09:39:03+09:00 DEBUG This log is debug!
2021-06-20T09:39:03+09:00 INFO This log is info!
2021-06-20T09:39:03+09:00 WARNING This log is warning!
2021-06-20T09:39:03+09:00 ERROR This log is error!
日付フォーマットが見やすくなっており、ログ本文の頭も揃っています。良さげです。
app.log
も確認します。
❯ cat app.log
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) DEBUG This log is debug!
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) INFO This log is info!
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) WARNING This log is warning!
Sun Jun 20 2021 09:35:23 GMT+0900 (日本標準時) ERROR This log is error!
2021-06-20T09:39:03+09:00 DEBUG This log is debug!
2021-06-20T09:39:03+09:00 INFO This log is info!
2021-06-20T09:39:03+09:00 WARNING This log is warning!
2021-06-20T09:39:03+09:00 ERROR This log is error!
FileHandler
は標準ではファイルを上書きではなく追記するため、前のフォーマットのログも残っています。
以後は整形されたログで記録されていきます。
おわりに
非常に簡単なものですが、フォーマットしたログをコンソールとファイルへ出力することができました。
割と汎用性があると思うのでDenoでコードを書くときは使えそうです。
より実践的にするなら、出力先ファイルを指定できるようにしたり、default
以外のログを作ったり、RotatingFileHandler
を使ったりすると良いかもしれません。
今回のリポジトリはこちらです。
Discussion
出力フォーマットに
"{datetime} {levelName} {msg}"
こんな簡単な書き方があったのか!と思ったけどバージョン0.214から remove string formatter で消えてしまったらしい。残念!
でもこの記事に0.99.0というバージョンが書いてあったので、0.99.0の頃はあった事が確認できたのは助かった!