給定單元的 *.journal
文件在哪裡?
我有一個用於 sshd 的 systemd 服務單元:
$ systemctl status sshd * ssh.service - OpenBSD Secure Shell server Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2020-09-30 18:54:10 UTC; 6s ago Process: 13923 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS) Process: 13918 ExecReload=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS) Process: 6287 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS) Main PID: 6296 (sshd) Tasks: 1 (limit: 4915) CGroup: /system.slice/ssh.service `-6296 /usr/sbin/sshd -D Sep 30 18:54:10 machine systemd[1]: Starting OpenBSD Secure Shell server... Sep 30 18:54:10 machine sshd[6296]: Server listening on 0.0.0.0 port 22. Sep 30 18:54:10 machine sshd[6296]: Server listening on :: port 22. Sep 30 18:54:10 machine systemd[1]: Started OpenBSD Secure Shell server.
我有一些
*.journal
它寫的文件:$ find /var/log/journal -type f -name 'system@*.journal' -exec grep -l 'OpenBSD' {} + /var/log/journal/0123456789abcdef0123456789abcdef/system@0123456789abcdef0123456789abcdef-000000000100bfdd-0005ac0c092a655f.journal /var/log/journal/0123456789abcdef0123456789abcdef/system@0123456789abcdef0123456789abcdef-000000000102d6c3-0005ac2251abe7d9.journal /var/log/journal/0123456789abcdef0123456789abcdef/system@0123456789abcdef0123456789abcdef-00000000010fc6d5-0005ac9be551a106.journal /var/log/journal/0123456789abcdef0123456789abcdef/system@0123456789abcdef0123456789abcdef-0000000000e043b9-0005aad981c2d167.journal /var/log/journal/0123456789abcdef0123456789abcdef/system@0123456789abcdef0123456789abcdef-00000000010d9bf1-0005ac875e1241e7.journal
鑑於前者,我如何找到後者?
日誌文件不按單位排序。發布日誌條目的單元只是與條目相關聯的元數據。日誌文件也不總是在
/var
./run
如果配置為非持久,它們也可以在中找到。為特定單位提取日記帳分錄的正確方法是使用
journalctl -u <unit_name>
或使用sd-journal
API。此外,日誌是一個二進製文件,因此它的格式並不完全適合解析。我什至不確定期刊的內部格式是否遵循穩定的規範。journalctl
或者 API 絕對是讀取這些文件的方式。如果您詢問此問題是為了備份(或發送故障排除)特定文件,則需要將所有這些文件視為一個單元。
由於您專門詢問了這些日誌文件的文件命名約定,因此我花了一些時間對此進行了調查。重新啟動後,唯一的文件
/run/log/journal
是/run/log/journal/c13e4a2f54334a95891a6a471db3b7e0/system@edd0c14e44a240038601194807d5c28e-0000000000000001-0005b08ccb2c37b3.journal
.我將其分解為以下內容以嘗試理解命名約定:
/run/ <-- run/var log/journal/ <-- standard location c13e4a2f54334a95891a6a471db3b7e0/ <-- _MACHINE_ID system@ <-- system/user edd0c14e44a240038601194807d5c28e- <-- Some bus/boot/session ID? 0000000000000001- <-- Sequence number (also looks like offsets as 4-KB blocks in hex) 0005b08ccb2c37b3 <-- Timestamp (time since epoch in hex) .journal <-- Extension
當我看一台已經執行了一段時間的機器時,所有
system@*.journal
文件都是80M,而所有user@*.journal
文件都是8.0M。有瞭如此一致的大小,它確實表明文件拆分只是日誌輪換。我還可以通過查看修改日期來確認這一點(隨著我們按順序進行,我看到日期在增加)。為了弄清楚其中的一些事情(例如
_MACHINE_ID
),我必須查看與日記條目相關的原始元數據。元數據比你能得到的要多journalctl
。我用 sd-journal API 編寫了一個快速程序並"Hello"
從服務中列印出來。我在日記中找到了它,並附有以下數據。令人驚訝的是,每個printf
._UID=0 _GID=0 _CAP_EFFECTIVE=3fffffffff _TRANSPORT=stdout _STREAM_ID=2ee82c395817429b975770acb1306d11 SYSLOG_IDENTIFIER=counter _PID=6523 _COMM=counter _EXE=/usr/local/bin/counter _CMDLINE=/usr/local/bin/counter _SYSTEMD_CGROUP=/system.slice/counter.service _SYSTEMD_UNIT=counter.service _SYSTEMD_INVOCATION_ID=711962f5d7bf487b9a262b824c297a42 MESSAGE=Hello PRIORITY=6 SYSLOG_FACILITY=3 _BOOT_ID=bf0d96cbab2144e3a8544b0e8a0eacc6 _MACHINE_ID=c13e4a2f54334a95891a6a471db3b7e0 _HOSTNAME=simswe24 _TRANSPORT=journal _SELINUX_CONTEXT=unconfined
如果您對我編寫的用於調查此問題的 sd-journal 程序感興趣,它就在這裡:
// Compile with `gcc journalctl.c -lsystemd` #include <systemd/sd-journal.h> #include <stdio.h> int main() { // Open the log sd_journal* journal; if ( sd_journal_open(&journal, SD_JOURNAL_LOCAL_ONLY) < 0 ) { return 1; // Couldn't open journal } // Subscribe to specific logs: // Messages from the service itself int r = sd_journal_add_match(journal, "_SYSTEMD_UNIT=counter.service", 0); r = r ? r : sd_journal_add_disjunction(journal); // Messages from PID 1 (systemd) about this service r = r ? r : sd_journal_add_match(journal, "_PID=1", 0); r = r ? r : sd_journal_add_match(journal, "UNIT=counter.service", 0); r = r ? r : sd_journal_add_disjunction(journal); if ( r < 0 ) { return 1; // Could not subscribe to all journal entries } r = sd_journal_seek_head(journal); if ( r < 0 ) { return 1; // Problem finding the head of the log } // Read the log int skip_seek=1; while( skip_seek || (sd_journal_next(journal) > 0 ) ) { const void* data = 0; size_t length; skip_seek = 0; sd_journal_restart_data(journal); SD_JOURNAL_FOREACH_DATA(journal, data, length) { printf("%s\n", data); }; } sd_journal_close(journal); return 0; }