Last active
June 17, 2021 21:38
-
-
Save moreati/b40db27759d068e0ac120a12e98c64a4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Determine whether stderr is connected to systemd journal, and hence whether | |
structured events can be written to the journal. | |
Based on https://systemd.io/JOURNAL_NATIVE_PROTOCOL/#automatic-protocol-upgrading | |
""" | |
import os | |
import sys | |
def stderr_is_systemd_journal() -> bool: | |
try: | |
journal_stream = os.environ['JOURNAL_STREAM'] | |
except KeyError: | |
return False | |
try: | |
part1, part2 = journal_stream.split(':', maxsplit=1) | |
except ValueError: | |
return False | |
try: | |
journal_dev = int(part1, 10) | |
journal_inode = int(part2, 10) | |
except ValueError: | |
return False | |
stderr_stat = os.fstat(sys.stderr.fileno()) | |
return (stderr_stat.st_dev, stderr_stat.st_ino) == (journal_dev, journal_inode) | |
def main(): | |
stderr_stat = os.fstat(sys.stderr.fileno()) | |
print(f"{stderr_stat.st_dev=} {stderr_stat.st_ino=}") | |
print(f"{os.environ.get('JOURNAL_STREAM')=}") | |
print(f"{stderr_is_systemd_journal()=}") | |
if stderr_is_systemd_journal(): | |
print("Hello systemd journal") | |
if __name__ == '__main__': | |
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
"fmt" | |
"os" | |
"strconv" | |
"strings" | |
"syscall" | |
) | |
// StdErrIsJournal returns true if standard error is connected to the systemd | |
// journal, false otherwise | |
func StderrIsJournal() (bool, error) { | |
// When a processes is started by systemd and standard error is connected | |
// to the journal, then $JOURNAL_STREAM contains the device and inode | |
// number of the standard error file descriptor (e.g. "123:789"). | |
// https://www.freedesktop.org/software/systemd/man/systemd.exec.html#%24JOURNAL_STREAM | |
js := os.Getenv("JOURNAL_STREAM") | |
parts := strings.SplitN(js, ":", 2) | |
if len(parts) != 2 { | |
return false, errors.New(js) | |
} | |
journalDev, err := strconv.ParseUint(parts[0], 10, 64) | |
if err != nil { | |
return false, err | |
} | |
journalIno, err := strconv.ParseUint(parts[1], 10, 64) | |
if err != nil { | |
return false, err | |
} | |
stat, err := os.Stderr.Stat() | |
if err != nil { | |
return false, err | |
} | |
statRaw, ok := stat.Sys().(*syscall.Stat_t) | |
if !ok { | |
return false, errors.New("couldn't convert stat") | |
} | |
return journalDev == statRaw.Dev && journalIno == statRaw.Ino, nil | |
} | |
func main() { | |
x, y := StderrIsJournal() | |
fmt.Println(x, y) | |
} |
:~/tmp$ go build journal_detect.go
:~/tmp$ ./journal_detect
false <nil>
:~/tmp$ systemd-run --user ./journal_detect
Running as unit: run-r4668e6b91b744684a0f6ac2bf75defee.service
:~/tmp$ journalctl --user -u run-r4668e6b91b744684a0f6ac2bf75defee.service
-- Logs begin at Fri 2020-05-15 13:14:09 BST, end at Thu 2021-06-17 22:26:20 BST. --
Jun 17 22:26:20 martha systemd[2428]: Started /home/alex/tmp/./main.
Jun 17 22:26:20 martha journal_detect[293679]: true <nil>
Jun 17 22:26:20 martha systemd[2428]: run-r4668e6b91b744684a0f6ac2bf75defee.service: Succeeded.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Invoked from a terminal the script correctly detects that stderr is not attached to the journal. The journal is available, but stderr is a different file.
Invoked as a (temporary) systemd unit the script correctly detects that stderr is the journal, and it can adjust behaviour as desired.