systemd の StandardOutput と StandardError
以前の記事で書いたように systemd の機能で標準出力をファイルに追記するようにしてロガーはシンプルに標準出力に書き込むようにしています
console.log でいい感じに整形してくれるので楽なんですよね
depth 問題があって省略されて必要な部分が残らないこともありますけど

ひさびさにその設定を見ていたら ふと思ったのですが標準出力しか設定していないです
StandardOutput は指定しているのに StandardError は未指定です

自分が書き込むのはすべて標準出力に統一してるのですがライブラリや Node.js など実行する環境側で出力されるものは標準エラー出力になることもありそうです

そういう特殊なものはむしろ systemd 標準の journal に送ったほうがいいのかもと思うところもあったりしますが 時系列を考えると同じログファイルに混ざっていて欲しいところもあります

とりあえず同じファイルに出力しようとしたのですが シェルの 「2>&1」 相当の記法がわかりません
シェルを通して本来のプログラムを実行して 標準エラー出力をすべて標準出力にまとめるようにすることもできますが あまりスッキリしないのでできれば避けたいです

ドキュメントを見てると fd:stdout のような記法があるみたいなので 「StandardError=fd:stdout」 でいいのかなと思ったのですが 構文エラーのようで起動ができなくなりました

もう少し読んでみると StandardError では inherit を使えば 標準出力のファイルディスクリプタが複製されると書いています
https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#StandardError=

また StandardError のデフォルト値 DefaultStandardError は inherit になっています
ということで何も設定してないこの状態で期待通りの動きになっていました

StandardOutput=file:/tmp/output

とだけ書けば標準出力も標準エラー出力も /tmp/output に書き込まれます
一応動かしてみたところ期待通りに動作しました



ちなみに fd を試していたときに同名指定も試しました

StandardOutput=file:/tmp/output
StandardError=file:/tmp/output

append なら問題なさそうでも通常の書き込みだと問題が出そうに思います
例えばこういうの

node index.js > out 2> out

[index.js]
console.log("out1")
console.error("err1")
console.log("out2")
console.error("err2")
console.log("out3")
console.error("err3")

[out]
err1
err2
err3

append モードじゃないとファイルの書き込み位置が更新されないので同じ場所に書き込んで上書きされます

同じ文字数だと分かりづらいですが こうするとそれぞれが持ってる書き込み位置に書き込んでることがわかりやすいと思います

[index.js]
console.error("AB")
console.log("a")
console.log("bcdefghijk")
console.error("CDEFG")
a
bCDEFG
ijk

自動で追加される改行があるので少しわかりづらさはありますけど AB が a と改行で上書きされて cd.. は CD.. で上書きされます
G の次の改行で h が上書きされてそれ以降は上書きされないので ijk が残ります

同じ名前を指定すると こうなるんだろうなと思ったのですが StandardOutput と StandardError に同じものを指定してもこうはならず両方が出力されていました
中でうまく管理されているようですね
ただ基本は同じのを 2 回書かずに inherit でいいと思います
サービスのログは標準出力に流して systemd で管理する
これまでウェブサーバーなどのデーモン化するアプリケーションでログを出力するときは いつもロガーを自作して設定で指定したファイルに書き込んでました
ほぼ使いまわしですが微妙に面倒な部分でもあるんですよね
それに極稀にキャッチされないエラーがあって標準出力の方に流れていたり

最初から全部 console.log で標準出力に流せばいいのでは と思ったこともありましたが systemd のサービスとするときにうまくできませんでした
systemd のサービスの設定で StandardOutput というものがあり標準出力をどこに送るか設定できます

StandardOutput=file:/path/to/log

のようにすれば指定のファイルに書き込めます
これを使おうとしたのですが この機能に対応した systemd のバージョンは 236 です
そのとき使う OS は CentOS7 だったのですが CentOS7 の systemd は 219 です
systemd が古くて使えません

その後 CentOS8 になり systemd が 239 になりました
やっと使えると思ったのですが問題がありました
file: だと新規にファイルを作成します
リダイレクトで > を使うようなものです
再起動のたびにログがクリアされます
リダイレクトで > の代わりに >> を使うような感じで 追記モードで扱う必要があります
追記モードにするには

StandardOutput=append:/path/to/log

と file: を append: にします
しかし append: は systemd 240 からです
AlmaLinux8 でも CentOS8 の頃からバージョンは上がっていないので 239 です
1 足りないので使えません

一応 shell script を起動するサービスとして そのスクリプトが本来のプログラムを実行して標準出力を目的のファイルへリダイレクトするようにするという方法もあったのですが 余計なものを挟みたくなかったのでこの方法は使いませんでした

最近は AlmaLinux9 が出ていて AlmaLinux9 は 250 でした
やっと使えます

ということで今度なにか作るときには console.log で出力して systemd の設定ファイルでログファイルの場所を指定する感じにしようと思ってます
systemctl 使わず Apache を操作する
動かしたい PHP のページがあるけど ちょうど使える環境がない
Docker に CentOS のイメージ入ってたしこれでいいか

みたいな感じで試してみたら systemctl が動かない!


Docker だと PID 1 が systemd じゃなくて systemd が起動していません
そのせいで systemctl コマンドは使えません

Apache の場合 httpd コマンドを実行するだけでバックグラウンドで動作します
再起動や停止するには httpd -k に stop などのコマンドを指定します

httpd -k stop
httpd -k restart

また systemd が使えないと apachectl も同様に使えません

System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
/run がいっぱいだった
vm の web ページにアクセスするとつながらない
ping は通る
ssh もつながる

systemd で httpd の restart すると失敗

放置してる vm のサービスおかしくなるのは メモリ不足かストレージ不足のどっちかが多いのでログを見ても oom とかそういうのはなさそう
df 見ると /run が 100%

ここってこんなものだったかなぁ……?

使用率は

/run/systemd/sessions

だけで 9 割近く

連番で最後は 99999 だったので 10 万ファイル??

tmpfs で再起動したら消えるやつだし と

cd /run/systemd/sessions
ls * | xargs rm

してスッキリさせたら restart できた

どうしてこんなにいっぱいになってたんだろう?