diff --git a/CHANGELOG.md b/CHANGELOG.md index bea6b8a..fe9e6cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ # Change Log ## 0.9.20 - +- The language server logs will now be in local time of whatever machine they are running on, rather than UTC. ## 0.9.19 - Added configuration option to control the max cache size while resolving references in semantic analysis, defaulting to 500MB diff --git a/Cargo.toml b/Cargo.toml index 9adf36f..cef9053 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ clap = { version = "4.2", features = ["cargo", "derive"] } crossbeam = "0.8" crossbeam-deque = "0.8.1" crossbeam-utils = "0.8.7" +chrono = { version = "0.4", default-features = false, features = ["clock"] } env_logger = "0.11" hashlink = "0.12" itertools = "0.14" diff --git a/src/logging.rs b/src/logging.rs index d783d7e..a88943c 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -1,8 +1,11 @@ // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT +use std::io::Write; use std::sync::LazyLock; +use chrono::Local; + macro_rules! info { ($($arg:tt)*) => { crate::log_with_fn!(log::info, log::Level::Info, $($arg)*) @@ -73,10 +76,36 @@ pub fn init() { let max_level = dummy_logger.filter(); env_logger::Builder::from_default_env() .filter_level(log::LevelFilter::Trace) + .format(local_time_format) .init(); set_global_log_level(max_level); } +/// Replicates `env_logger`'s default record format, except the timestamp is +/// rendered in the system's local time zone +fn local_time_format( + buf: &mut env_logger::fmt::Formatter, + record: &log::Record<'_>, +) -> std::io::Result<()> { + // ISO 8601 with seconds precision (env_logger's default), but local time + // with the local UTC offset instead of the "Z" suffix. + let ts = Local::now().format("%Y-%m-%dT%H:%M:%S%:z"); + let level = record.level(); + let style = buf.default_level_style(level); + // Formatting 'style' normally enables it, doing it with :# disables it + write!(buf, "[{ts} {style}{level:<5}{style:#}")?; + let target = record.target(); + if !target.is_empty() { + write!(buf, " {target}")?; + } + let msg = record.args().to_string(); + if msg.contains('\n') { + writeln!(buf, "] {}", msg.replace('\n', "\n ")) + } else { + writeln!(buf, "] {msg}") + } +} + pub fn set_global_log_level(level: log::LevelFilter) { log::set_max_level(level); }