# errno を ChromiumのLOGで出力するには
*本日は同僚のmomohatt@から献上していただいたネタです。*
Chromiumでは以下のようにログを書くことができる。
```cpp=
LOG(ERROR) << "error";
```
`<<`演算子のあとには上記のように文字列を渡すこともできるし、`<<`演算子が定義されている型をそのまま渡すことができる。
ただし`errno`を渡したときだけ挙動が異なる。
```cpp=
LOG(ERROR) << errno;
```
こうすると残念ながら`0`しか出てこない。
どうすれば出てくるか?
## errnoとは
[`errno`](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/errno.3.html)はエラーの番号を保存している特別な変数で、errno.hヘッダーの中で定義されている。
システムコールなどが`errno`の値を設定する。この値はそれぞれ意味が定まっているので、なんのエラーかを掘り出すことができる。
`errno`はいろんなところから上書きされる値なので、ログに出力しようとしても副作用で値が変わっていることなどがありえる。
出力までの間に変わってしまうことのないように、base/logging.hの中では工夫されている。
## ErrnoLogMessage
[ErrnoLogMessage](https://source.chromium.org/chromium/chromium/src/+/main:base/logging.cc;l=1097;drc=d03f4ca8789f7d7f49934c6892d4539b8c9c8252)はLogMessageを継承したクラス。
これは[GetLastSystemErrorCode](https://source.chromium.org/chromium/chromium/src/+/main:base/logging.cc;l=1054;drc=150d8c7e45daeef094be8ec8852e3486eed8f59d)で獲得する`errno`をコンストラクタに受け取り、`err_`メンバ変数として保存しておく。そしてErrorLogMessage破壊時に`": " << SystemErrorCodeToString(err_)`をログの末尾に出してくれる。
なのでErrorLogMessageを使うログであれば`errno`の値を文字列で常に出してくれそう。
これは[PLOG](https://source.chromium.org/chromium/chromium/src/+/main:base/logging.h;l=553;drc=b1ccd0cb58f9440bcefe163360a4f5d522ad31ad)で使われている。
```cpp=
errno = 32;
PLOG(ERROR) << "hello";
// output
hello: Broken pipe (32)
```
このように`errno`の値を出したければPLOGを使えば良い。
## なぜ`0`が出力されるのか
ところで`LOG(ERROR) << errno`だと常に`0`が出力される。(途中で副作用でerrnoが上書きされ0じゃなくなることはある。)これはなぜか?
LogMessageのインスタンスの中には[base::ScopedClearLastError型の`last_error_`](https://source.chromium.org/chromium/chromium/src/+/main:base/logging.h;l=673;drc=b1ccd0cb58f9440bcefe163360a4f5d522ad31ad)という変数がある。
[ScopedClearLastError](https://source.chromium.org/chromium/chromium/src/+/main:base/scoped_clear_last_error.h;l=22;drc=e4622aaeccea84652488d1822c28c78b7115684f)はその時点での`errno`の値を`last_errno_`に保存し、`errno`の値は0にリセットしておいてくれる。
Scopedの名前の通り、スコープが切れると、つまりdestructorが走ると保存しておいた`last_errno_`を`errno`に戻してくれる。
今回のケースではLogMessageが破壊されるときに`last_error_`も破壊されるので、`errno`に戻ってくる。ただし、その前にログはstreamに流されているので`errno`の値は`0`にリセットされたままである。なのでLOG(ERROR)では`0`が出力される。
なんのためにやってるのかあまり良くわからない。
ログの出力中に起きたエラーを出せるようにしたい?
コメントには
> This is useful since the LogMessage class uses a lot of Win32 calls
> that will lose the value of GLE and the code that called the log function
> will have lost the thread error value when the log call returns.
とあるが、storeしても特に使われていなさそう...?
TODO(elkurin): investigate
ちなみに、これを消すとLOG(ERROR)で`errno`の値が出力されるようになった。が、副作用で変な値になることはあるので、やはりPLOGを使うのがベストだと思う。