---
breaks: false
tags: public-tech
---
# Logs でログをとる
この記事は [OCaml Tips Advent Calendar 2022](https://adventar.org/calendars/8396) の13日目です。
OCaml のログライブラリとして [Logs](https://github.com/dbuenzli/logs)
があります。`INFO` や `DEBUG` といったレベルごとのロギングが可能です。
使うには、まずインストールして `dune` ファイルに記述します。
```
$ opam install logs
$ vim bin/dune
(executable
(public_name yourfavname)
(name main)
(libraries yourfavname logs logs.fmt))
```
使うには、まず `reporter` とログレベルをセットしたあとに `Logs.debug`,
`Logs.info`, `Logs.err` などを呼び出します。
これらの関数の引数に渡す一引数関数には printf のように振る舞う関数が渡されてくるので、
これをつかってログメッセージを出力します。
デフォルトでは、ログメッセージは stdout に出力されます。
```ocaml=
(* repoter をセット *)
Logs.set_reporter (Logs_fmt.reporter ());
(* level をセット *)
Logs.set_level (Some Logs.Info (* Logs.Debug なども使える *));
(* ログ *)
let username = "anqou" in
Logs.info (fun m -> m "Hello, %s" username);
Logs.debug (fun m -> m "Hello, %s, debugging here" username)
(* 出力
$ dune exec bin/main.exe
main.exe: [ERROR] Hello, anqou, error
main.exe: [INFO] Hello, anqou
# ログレベルとして Info を選んだので debug は表示されない
*)
```
カスタムの reporter を定義することで、
ログメッセージのプレフィクスや、ログの出力先を変更できます。
以下のコードは出力先を stderr に変更しつつ、引数で渡された `procname` を
角括弧でくくってプレフィクスとします。
```ocaml=
let set_logs_reporter procname =
let reporter procname ppf =
let report _src level ~over k msgf =
let k _ =
over ();
k ()
in
let f h _tags k ppf fmt =
Format.kfprintf k ppf
("%a[%s] @[" ^^ fmt ^^ "@]@.")
Logs.pp_header (level, h) procname
in
msgf @@ fun ?header ?tags fmt -> f header tags k ppf fmt
in
{ Logs.report }
in
Logs.set_reporter (reporter procname Format.err_formatter)
;;
set_logs_reporter "main"
```
## 参考
- https://erratique.ch/software/logs/doc/Logs/index.html