Stderr and Stdout: Understanding Logs and Outputs
Standard output (stdout
) and standard error (stderr
) are two concepts that, while simple, play a core role in log recording, error handling, and data stream management. This article will explore the differences and applications of stdout
and stderr
, especially how to use them effectively in a Python environment.
Standard Output (stdout
) and Standard Error (stderr
)
In most operating systems, standard output and standard error are two main output streams of a process. They provide a mechanism for the process to send information and error messages to a terminal or file. Although these two streams might be physically the same (for example, both displayed on the same terminal interface), they are used for different purposes logically:
- Standard Output (
stdout
): Typically used to output the results of program execution or normal running information. - Standard Error (
stderr
): Specifically used for outputting error messages or warnings, which are usually intended to be seen or recorded even when standard output is redirected.
print
and logging
in Python
In Python, the print
function by default sends information to stdout
, while the logging
module sends log messages to stderr
by default. This is done to differentiate normal program output from log (including error and debug information) output, making it easier for developers to manage and filter output information.
Using print
print
is the most basic output function in Python, used to send information to the standard output stream. It is simple to use and suitable for quick debugging or displaying information to users. For example:
|
|
Using logging
The logging
module provides a flexible framework for adding log messages in applications. Unlike print
, logging
supports different log levels (DEBUG, INFO, WARNING, ERROR, CRITICAL), allowing developers to adjust the detail and output location of logs as needed. For example:
|
|
tqdm and stderr
In complex or long-running programs, using a progress bar is an effective way to show process progress to users. The tqdm
library in Python is a widely used tool for adding progress bars in the command line. tqdm
outputs progress information to stderr
by default, to avoid interfering with normal program output (stdout
).
Diverting stdout
and stderr
In some cases, separating normal output from errors or log messages, for example, redirecting them to different files or terminals, is beneficial. In the command line, this can be achieved using the redirection operators >
and 2>
. In Python code, more fine-grained control can be achieved by configuring the logging
module or using specific file objects.
|
|
Through command line redirection, Python’s print
function, or even the logging
module, it is possible to flexibly control and divert these two types of output, making error handling, logging, and user interaction clearer and more orderly.
Managing stdout
and stderr
with nohup
When deploying long-running background processes, the nohup
command becomes an important tool. nohup
, or “no hang up,” allows commands to continue running after the user logs out, which is especially useful for remotely initiated tasks. A key feature of nohup
is its ability to manage stdout
and stderr
.
By default, running a command with nohup
will merge and redirect stdout
and stderr
to the nohup.out
file unless otherwise specified. This means that both regular output and error messages are captured in the same file, facilitating later review. However, in some cases, it may be more useful to separate these two outputs.
Using nohup
to separate stdout
and stderr
To output stdout
and stderr
to different files while using nohup
, you can combine redirection operators. For example:
|
|
This command redirects stdout
to output.log
, stderr
to error.log
, and runs in the background with &
. Thus, even if the terminal or SSH session is closed, the program will continue to run, and its output will be properly recorded.
Buffering behavior in Python
stdout
and stderr
behave differently when buffering data. By default, stdout
is line-buffered; when connected to a terminal, it caches data until it receives a newline character or the buffer is full; in non-interactive mode, stdout
is block-buffered (like files). Meanwhile, stderr
is always line-buffered (before Python 3.9 version, in non-interactive mode it was block-buffered). The following content is from the official documentation sys — System-specific parameters and functions — Python 3.12.2 documentation
When interactive, the
stdout
stream is line-buffered. Otherwise, it is block-buffered like regular text files. Thestderr
stream is line-buffered in both cases. You can make both streams unbuffered by passing the[u](<https://docs.python.org/3.12/using/cmdline.html#cmdoption-u>)
command-line option or setting the[PYTHONUNBUFFERED](<https://docs.python.org/3.12/using/cmdline.html#envvar-PYTHONUNBUFFERED>)
environment variable.Changed in version 3.9: Non-interactive
stderr
is now line-buffered instead of fully buffered.
The smaller the buffering granularity, the more timely the output, but the higher the IO cost. Before Python 3.8, stdout
and stderr
had the same buffering granularity, which was not quite reasonable; after version 3.9, stderr
received a smaller buffering granularity, meaning that each write operation’s output would be more immediate than stdout
. This difference makes stderr
suitable for error and log information, ensuring that these messages have a higher priority than standard output even if the program crashes or exits abnormally.
In C++, standard error is unbuffered (see later), more aggressive, but I personally think this makes more sense.
Fortunately, in Python, you can disable this buffering behavior by using python -u
or setting the PYTHONUNBUFFERED
environment variable, or by directly manipulating sys.stdout.flush()
to control the timing of output.
Performance in Python concurrent environments
When using stdout
and stderr
in a multi-threaded or multi-process environment, the output may become interleaved or chaotic, as outputs from different threads or processes may interfere with each other when written to the terminal or file. One way to solve this problem is to create independent output files for each thread or process, or to use thread locks or process synchronization mechanisms (such as multiprocessing.Lock
) to synchronize access to stdout
or stderr
.
Controlling stdout
and stderr
in Python
In complex applications, you may need to more flexibly control the destination of the output stream. Python provides several ways to achieve this:
- Redirecting
stdout
andstderr
: You can redirect the standard output and error output of a Python program by changing the values ofsys.stdout
andsys.stderr
. This is especially useful for capturing and analyzing output or redirecting output to non-standard output devices such as graphical interfaces. - Using the
subprocess
module: When running external commands or scripts, thesubprocess
module allows you to control thestdout
andstderr
streams of the command, including redirecting them to variables within the Python program or separating or merging them. - Advanced applications of the logging module: Python’s
logging
module supports logging output to multiple destinations, including files, standard output, networks, etc. By configuring different log handlers, you can implement complex log management schemes, such as diverting logs to different outputs based on log level or message content.
Recommendations
- Manage output carefully: When designing software, clearly distinguish between outputs for user interaction (
stdout
) and outputs for error reporting or log recording (stderr
). This helps improve the usability and maintainability of the program. - Optimize performance: Consider the performance impact of output operations, especially in scenarios of high-frequency logging or data output. Proper use of buffering and batch processing can reduce the impact on performance.
- Considerations for security: Appropriately filter and desensitize before outputting sensitive information to avoid exposing sensitive data through logs.
By deeply understanding and flexibly applying stdout
and stderr
, you can build more robust and manageable Python applications, effectively handle logs and outputs, and enhance user experience and application stability.
Buffering Behavior in C++
In C++, stdout
(usually corresponding to std::cout
) and stderr
(corresponding to std::cerr
) have different buffering strategies:
std::cout
is line-buffered by default, which means that when it is connected to a terminal, the output is flushed at each newline or when the buffer is full.std::cerr
is unbuffered by default, so data written tostd::cerr
is output immediately, which is very useful for reporting error information as it reduces the risk of losing error messages due to program crashes.
Redirecting stdout
and stderr
In C++ programs, there are various ways to redirect stdout
and stderr
. A common method is to use the freopen
function to redirect standard output or error output to a file during program execution:
|
|
This method can be used to direct output to a file, which is convenient for later analysis and debugging.
Using in a C++ Multithreaded Environment
When using std::cout
and std::cerr
in a multithreaded C++ program, you may encounter race conditions that result in disordered output. To avoid this, it is recommended to use mutex locks (such as std::mutex
) to synchronize access to these streams:
|
|
Controlling Output in C++
The C++ standard library provides std::streambuf
, which can be used to implement finer-grained control over std::cout
and std::cerr
, including redirection and custom buffering behaviors. By inheriting std::streambuf
and overriding the relevant member functions, you can create custom buffering strategies or redirect output to GUI components, network connections, etc.
Recommendations
- Make rational use of buffering: Choose an appropriate buffering strategy according to the application scenario. For error messages that need immediate feedback, use
std::cerr
or manually flushstd::cout
. - Avoid using standard output directly in multithreaded environments: Use mutex locks or other synchronization mechanisms to ensure the consistency and order of output.
- Use redirection and custom
streambuf
: To handle output more flexibly, consider using redirection or customstreambuf
for special output needs, such as logging, network transmission, etc.
By mastering these advanced techniques, you can effectively manage and control the output of C++ programs while ensuring their robustness and flexibility.