breaking,log: set stderr as default log output, add .set_output_stream() to allow for opting in the old default of stdout (#23444)

This commit is contained in:
gechandesu 2025-01-21 20:13:21 +03:00 committed by GitHub
parent 8654cb9885
commit 4e68a86025
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 76 additions and 37 deletions

View file

@ -52,3 +52,22 @@ fn main() {
l.fatal('fatal') // panic, marked as [noreturn]
}
```
## Backwards compatibility
After 2025/01/21, the `log` module outputs to `stderr` by default.
Before that, it used `stdout` by default.
If you want to restore the previous behaviour, you have to explicitly call l.set_output_stream():
```v
import os
import log
fn main() {
// log.info('this will be printed to stderr after 2025/01/21 by default')
mut l := log.ThreadSafeLog{}
l.set_output_stream(os.stdout())
log.set_logger(l)
log.info('this will be printed to stdout')
}
```

View file

@ -19,8 +19,8 @@ pub enum LogTarget {
both
}
// tag_to_cli returns the tag for log level `l` as a colored string.
fn tag_to_cli(l Level, short_tag bool) string {
// tag_to_console returns the tag for log level `l` as a colored string.
fn tag_to_console(l Level, short_tag bool) string {
if short_tag {
return match l {
.disabled { ' ' }

View file

@ -5,6 +5,7 @@ module log
import os
import time
import io
// TimeFormat define the log time string format, come from time/format.v
pub enum TimeFormat {
@ -25,10 +26,12 @@ pub enum TimeFormat {
tf_custom_format // 'MMMM Do YY N kk:mm:ss A' output like: January 1st 22 AD 13:45:33 PM
}
const stderr = os.stderr()
// Log represents a logging object
pub struct Log {
mut:
level Level
level Level = .debug
output_label string
ofile os.File
output_target LogTarget // output to console (stdout/stderr) or file or both.
@ -36,6 +39,9 @@ mut:
custom_time_format string = 'MMMM Do YY N kk:mm:ss A' // timestamp with custom format
short_tag bool
always_flush bool // flush after every single .fatal(), .error(), .warn(), .info(), .debug() call
output_stream io.Writer = stderr
//
show_notice_about_stdout_to_stderr_change bool = true // this field is temporary, and should be deleted after 2025-03-01
pub mut:
output_file_name string // log output to this file
}
@ -77,6 +83,12 @@ pub fn (mut l Log) set_output_path(output_file_path string) {
l.ofile = ofile
}
// set_output_stream sets the output stream to write log e.g. stderr, stdout, etc.
pub fn (mut l Log) set_output_stream(stream io.Writer) {
l.show_notice_about_stdout_to_stderr_change = false
l.output_stream = stream
}
// log_to_console_too turns on logging to the console too, in addition to logging to a file.
// You have to call it *after* calling .set_output_path(output_file_path).
pub fn (mut l Log) log_to_console_too() {
@ -131,14 +143,31 @@ fn (mut l Log) log_file(s string, level Level) {
}
}
// log_cli writes log line `s` with `level` to stdout.
fn (l &Log) log_cli(s string, level Level) {
timestamp := l.time_format(time.utc())
e := tag_to_cli(level, l.short_tag)
println('${timestamp} [${e}] ${s}')
if l.always_flush {
// log_stream writes log line `s` with `level` to stderr or stderr depending on set output stream.
fn (mut l Log) log_stream(s string, level Level) {
if l.show_notice_about_stdout_to_stderr_change {
l.show_notice_about_stdout_to_stderr_change = false
// Show a warning at runtime, once, before the first logged message, that describes the stdout -> stderr change,
// and how to opt in explicitly for the old behaviour:
println(' NOTE: the `log.Log` output goes to stderr now by default, not to stdout.')
println(' Call `l.set_output_stream(os.stdout())` explicitly, to opt in for the previous behavior.')
println(' Call `l.set_output_stream(os.stderr())` explicitly, if you want to silence this message (it will be removed after 2025-03-01 .')
flush_stdout()
}
timestamp := l.time_format(time.utc())
tag := tag_to_console(level, l.short_tag)
msg := '${timestamp} [${tag}] ${s}\n'
arr := msg.bytes()
l.output_stream.write(arr) or {}
if l.always_flush {
if mut l.output_stream is os.File {
match l.output_stream.fd {
1 { flush_stdout() }
2 { flush_stderr() }
else {}
}
}
}
}
// send_output writes log line `s` with `level` to either the log file or the console
@ -148,7 +177,7 @@ pub fn (mut l Log) send_output(s &string, level Level) {
l.log_file(s, level)
}
if l.output_target == .console || l.output_target == .both {
l.log_cli(s, level)
l.log_stream(s, level)
}
}