简体   繁体   中英

Systemd service and structured logging

I have a systemd service which is of type simple .

I want my service to log key-value pairs.

Up to now my simple service just prints it log to stdout in a custom key-value syntax.

I would like to avoid my custom key-value syntax it use an official way to do structured logging.

Is there a way to use structured logs with systemd?

For example my service writes this to stdout:

{"key1": "value1", "key2": 1234}

It would be great of systemd could read the string as json.

You can log structured data to systemd and then view it as is or in json format

Let's say we log key-value pairs in json format

systemd-cat -t "struct_logs" echo '{"key1": "value1", "key2": 1234}'

Then we read them as is

sudo journalctl -t 'struct_logs' --lines 1 --no-pager

Apr 30 21:46:14 linux-ar struct_logs[17455]: {"key1": "value1", "key2": 1234}

Or in json format

sudo journalctl -t 'struct_logs' --lines 1 --no-pager -o json-pretty
{
        "__CURSOR" : "s=b6d07ffffffffff2787cea140a0db88a5;i=db8;b=c9b2132ffffffffe5807625fe;m=9fa5b3f81;t=58fffffff87eab;x=6402818ea7e32a5b",
        "__REALTIME_TIMESTAMP" : "1556671574343339",
        "__MONOTONIC_TIMESTAMP" : "42854989697",
        "_BOOT_ID" : "fffffffffffff24ec7a237b5e5807625fe",
        "PRIORITY" : "6",
        "_MACHINE_ID" : "fffffffffff66c86aaaaaaaaaa",
        "_HOSTNAME" : "linux-ar",
        "_TRANSPORT" : "stdout",
        "_UID" : "1000",
        "_GID" : "100",
        "SYSLOG_IDENTIFIER" : "struct_logs",
        "MESSAGE" : "{\"key1\": \"value1\", \"key2\": 1234}",
        "_PID" : "17455"
}

Going further you can recover your exact log messages with the help of jq

sudo journalctl -t 'struct_logs' --lines 1 --no-pager -o json-pretty | jq -r '.MESSAGE'
{"key1": "value1", "key2": 1234}

It could be possible also to log custom keys provided that the user has the proper rights to do that. A service should be able to do that

sudo logger --journald <<end
MESSAGE_ID=67feb6ffbaf24c5cbec13c008dd72309
MESSAGE=The dogs bark, but the caravan goes on.
SYSLOG_IDENTIFIER=struct_logs
KEY=bark
VALUE=goes on
end

Hope this helps.

Have a look at Structured logging to journald from within a docker container ; your application should use the sd_journal_send method if you want to specify custom fields.

If your application is unable to do that you can also output json - which will end up in the MESSAGE field you can then parse yourself. For example - I wrote SystemdJournal2Gelf to send the journal entries to Graylog and it also supports json output in the MESSAGE , sending it to Graylog as separate fields for filtering

If you don't want to modify the application you could use a separate script - something like this:

[Service]
ExecStart=/bin/sh -c '/bin/my-app | while read l; do echo "$l" | logger --journald; done'

You could even convert json to key/value pairs if you want, or use StandardOutput to send your standard-output to a socket where you have a separate service listening.

Well, systemd does not make it easy to do structured logging from text stream. It want your to take a dependencies on its library and use sd_journal_send (see for example http://0pointer.de/blog/projects/journal-submit.html ). I have not found any "text form" standard that allow systemd to understand that your line should not be smushed together in the MESSAGE fields but rather should be interpreted as a key-value pair. I guess a solution would be to write a helper process that parse your stdout and then call the systemd logger. You would then pipe your process stdout process into

However, I did found this answer that pipe directly into the journald socket. With clever use of jq, you could write something that exploit that. But that seems hacky: I do not know if systemd really intend to keep any compatibility on that socket.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM