8

Usually log messages are written to stderr. I'm wondering if it is a good idea/practice to split log messages so that errors and warnings go to stderr while debug/informational/notice messages go to stdout instead? Or is this irrelevant given that many dedicated logging processes only read from stdin anyway, which requires source log messages in stderr and stdout be combined and redirect to logger's stdin.

[Update]

The two answers below both mentioned syslog, I think I need to clarify the setup in detail.

The daemon processes I asked are running in foreground by themselves. Daemonization is managed by supervising processes such as runit or supervisord. In both cases, the stderr and stdout of the daemon processes will be captured by the supervising processes, and it's the supervising processes' job to decide how and where to store the logs (might be syslog, or somewhere else in the network over UDP). The daemon processes don't have to worry about what and where to write logs, as they just write to stdout/stderr.

In the case of runit, its logging facility svlogd will read from its stdin for the redirected log messages, which are combined stderr/stdout of the managed daemon process. As for supervisord, it can record stderr and stdout to separate log files.

So in this specific settings, is it a good practice to split logs between stderr and stdout, or just write to one of them?

Andrew B
  • 33,868
Rio
  • 345
  • 2
  • 11

4 Answers4

6

First, something important to clarify: STDOUT and STDERR are rarely relevant within the context of a daemon process once it has successfully started, unless you're invoking one with a debugging switch.

The whole point of a daemon is that it needs to disassociate itself from having a controlling terminal, so that it can persist after logout. Once there is no terminal, all messages need to be sent to either a syslog daemon or a log file managed directly by the process.

If you are not actually referring to daemons, and really just mean any shell script or similar that you're writing yourself, then the logic should generally be this:

  • STDOUT: Anything you want being trapped by pipes or basic output redirection.
  • STDERR: "Out of band" messages. Things you want hitting someone's terminal anyway, even if they're doing some kind of redirection. (hence why they're associated with errors) Let the user decide if they also want to redirect these messages as well, i.e. redirecting STDERR to STDIN as you mentioned.
Andrew B
  • 33,868
4

If it's a daemon, I recommend using the syslog interface to log your messages direct to the logs. Run "man 3 syslog" for info. If necessary, your program can also have a debug option (with a parameter that specifies the priority) that tells the daemon program not to run in the background, and to log to stderr too.

I'd write a logging function that takes a priority and string as an argument. It should call syslog() to log the message properly, and if the priority is greater than or equal to the global debug priority value, output message to stderr as well as syslog(). Call syslog(..., "%s", msg) to avoid percent characters in the message from being screwed up. (Or make your function take a variable number of arguments and pass the arglist to vsyslog().)

Make sure you call openlog(..., LOG_PID, LOG_DAEMON) in your program's initialisation. You could add | LOG_PERROR after LOG_DAEMON if you are in debug mode, which would avoid having to write the logging function mentioned above. But then you'd lose the ability to filter based on priority.

You might (if using Ubuntu) need to configure /etc/rsyslog.conf to ensure that daemon messages are being logged.

PS -- Use the logger command if your daemon is a shell script

4

I would not suggest co-mingling stdout and stderr inside your program, but how you handle it outside is up to you. stdout was intended for processed data meant for a pipeline, while stderr is specifically for non-data messages. This makes certain behaviors possible, such as batch processing, without altering the existing interactive behavior. Your case is different - there is a good chance stdout means little to nothing.

Because runit has a slightly different take on logging via svlog, and the service you are writing most likely will not daemonize (which in this case means "detach from a tty") then it will be up to you if you want to capture everything to a single log, or not, via the /etc/sv/<servicename>/run script. For the most part, most run scripts use

exec 2>&1 

to fuse the two streams together, as most services don't pass along data via stdout. If you do want to use svlog you will need to create a script at /etc/sv/<servicename>/log/run with the appropriate command to start it. It probably looks similar (but not exactly like) this:

#!/bin/sh
exec 2>&1
exec svlog -tt main

where main is a symlink to a logging directory.

Avery Payne
  • 14,804
4

I don't think you should use both stdout and stderr for logging. If you have log messages with different severities, they should be tagged with a prefix to make it easy to filter/sort them using svlogd.

I'd say using both stdout and stderr for logging would violate the principle of least surprise.