diff --git a/CHANGELOG.md b/CHANGELOG.md index 7eac3117..9426b21d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - The DLS will now correctly report missing template names in 'in each' constructs - Fixed error where the DLS would fail to match references from within in a template to symbols defined in parents of objects instantiating the template +- Added environment variable to control max per-log output length for most logging from the DLS, defaulting to 1000 characters. ## 0.9.17 - Fixed linter wrongly throwing an error on space after `defined` keyword diff --git a/USAGE.md b/USAGE.md index ab1d23ad..9032f504 100644 --- a/USAGE.md +++ b/USAGE.md @@ -84,6 +84,9 @@ instantiated. including direct instantiation sites (so this is a super-set of `goto-implementations`) +## Relevant environment variables +* `MAX_LOG_MESSAGE_LENGTH` When set, will truncate any outputted logs that are longer than the value. Defaults to 1000 bytes. Set to 0 to turn off truncation. + ## In-Line Linting Configuration It may be desireable to control linting on a per-file basis, rather than relying on the linting configuration. This can be done with in-line diff --git a/src/actions/analysis_queue.rs b/src/actions/analysis_queue.rs index c190bf74..0ea52fe9 100644 --- a/src/actions/analysis_queue.rs +++ b/src/actions/analysis_queue.rs @@ -28,7 +28,7 @@ use crate::file_management::CanonPath; use crate::vfs::{TextFile, Vfs}; use crate::server::ServerToHandle; -use log::{info, debug, trace, error}; +use crate::logging::{info, debug, trace, error}; use crossbeam::channel; // Maps in-process device jobs the timestamps of their dependencies diff --git a/src/actions/analysis_storage.rs b/src/actions/analysis_storage.rs index 5f5b6edf..43452a3c 100644 --- a/src/actions/analysis_storage.rs +++ b/src/actions/analysis_storage.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 and MIT //! Stores currently completed analysis. -use log::{debug, info, trace}; +use crate::logging::{debug, trace, info}; use crossbeam::channel; diff --git a/src/actions/hover.rs b/src/actions/hover.rs index e149bbd0..797f8c77 100644 --- a/src/actions/hover.rs +++ b/src/actions/hover.rs @@ -1,6 +1,6 @@ // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT -use log::*; +use crate::logging::*; use crate::span::{Range, ZeroIndexed}; use serde::{Deserialize, Serialize}; diff --git a/src/actions/mod.rs b/src/actions/mod.rs index ed91df54..3c430a7b 100644 --- a/src/actions/mod.rs +++ b/src/actions/mod.rs @@ -3,7 +3,6 @@ //! Actions that the DLS can perform: responding to requests, watching files, //! etc. -use log::{debug, info, trace, error, warn}; use thiserror::Error; use crossbeam::channel; use serde::Deserialize; @@ -40,6 +39,7 @@ use crate::Span; use crate::span; use crate::span::{ZeroIndexed, FilePosition}; use crate::vfs::Vfs; +use crate::logging::{debug, info, trace, error}; use jsonrpc::error::{standard_error, StandardError}; use serde_json::Value; @@ -80,7 +80,7 @@ macro_rules! make_canon_path { macro_rules! ignore_non_file_uri { ($expr: expr, $uri: expr, $log_name: expr) => { $expr.map_err(|_| { - log::trace!("{}: Non-`file` URI scheme, ignoring: {:?}", $log_name, $uri); + crate::logging::trace!("{}: Non-`file` URI scheme, ignoring: {:?}", $log_name, $uri); }) }; } @@ -594,7 +594,7 @@ impl InitActionContext { .extend(includes.into_iter()); } } else { - warn!( + info!( "File in compile information file is not .dml; \ {:?}", file diff --git a/src/actions/notifications.rs b/src/actions/notifications.rs index d66a0be8..7ab62688 100644 --- a/src/actions/notifications.rs +++ b/src/actions/notifications.rs @@ -8,9 +8,9 @@ use crate::file_management::CanonPath; use crate::span::{Span}; use crate::vfs::{Change, VfsSpan}; use crate::lsp_data::*; +use crate::logging::{debug, error}; use jsonrpc::error::StandardError; -use log::{debug, error, warn}; use serde::{Serialize, Deserialize}; use lsp_types::notification::ShowMessage; @@ -211,7 +211,7 @@ impl BlockingNotificationAction for DidChangeConfiguration { let new_config = match settings { Ok(value) => value.dml, Err(err) => { - warn!("Received unactionable config: {:?} (error: {:?})", params.settings, err); + error!("Received unactionable config: {:?} (error: {:?})", params.settings, err); return Err(().into()); } }; diff --git a/src/actions/requests.rs b/src/actions/requests.rs index b4e2f651..80c151e1 100644 --- a/src/actions/requests.rs +++ b/src/actions/requests.rs @@ -3,7 +3,6 @@ //! Requests that the DLS can respond to. use jsonrpc::error::StandardError; -use log::{debug, error, info, trace, warn}; use serde::{Deserialize, Serialize}; use std::collections::HashSet; @@ -19,6 +18,7 @@ use crate::actions::semantic_lookup::{DLSLimitation, declarations_at_fp, definit use crate::analysis::{Named, DeclarationSpan, LocationSpan}; use crate::analysis::symbols::SimpleSymbol; use crate::config::Config; +use crate::logging::{debug, error, info, trace}; pub use crate::lsp_data::request::{ ApplyWorkspaceEdit, @@ -65,17 +65,17 @@ fn warn_miss_lookup(error: AnalysisLookupError, file: Option<&str>) { if let Some(f) = file { f.to_string() } else { "the opened file".to_string() }), AnalysisLookupError::NoIsolatedAnalysis => - warn!( + info!( "No syntactical analysis available{}", if let Some(f) = file { format!(" for the file '{}'", f) } else { "".to_string() }), AnalysisLookupError::NoLintAnalysis => - warn!( + info!( "No linting analysis available{}", if let Some(f) = file { format!(" for the file '{}'", f) } else { "".to_string() }), AnalysisLookupError::NoDeviceAnalysis => - warn!( + info!( "No semantic analysis available{}, may need to open a file \ with a 'device' declaration that imports{}, directly or \ indirectly.", @@ -985,8 +985,8 @@ impl SentRequest for WorkspaceConfiguration { let new_config = match settings { Ok(value) => value, Err(err) => { - warn!("Received unactionable config: {:?} (error: {:?})", - &response, err); + error!("Received unactionable config: {:?} (error: {:?})", + &response, err); return; } }; diff --git a/src/actions/work_pool.rs b/src/actions/work_pool.rs index f4a7863e..1a77f22a 100644 --- a/src/actions/work_pool.rs +++ b/src/actions/work_pool.rs @@ -1,8 +1,9 @@ // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT use crate::server::DEFAULT_REQUEST_TIMEOUT; +use crate::logging::{info, error}; + use lazy_static::lazy_static; -use log::{info, warn}; use std::sync::{mpsc, Mutex}; use std::time::{Duration, Instant}; use std::{fmt, panic}; @@ -62,7 +63,7 @@ where if work.len() >= *NUM_THREADS { // there are already N ongoing tasks, that may or may not have timed out // don't add yet more to the queue fail fast to allow the work pool to recover - warn!("Could not start `{}` as at work capacity, {:?} in progress", description, *work,); + error!("Could not start `{}` as at work capacity, {:?} in progress", description, *work,); return receiver; } if work.iter().filter(|desc| *desc == &description).count() >= MAX_SIMILAR_CONCURRENT_WORK { @@ -96,7 +97,7 @@ where if elapsed >= *WARN_TASK_DURATION { let secs = elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1_000_000_000_f64; - warn!("`{}` took {:.1}s", description, secs); + info!("`{}` took {:.1}s", description, secs); } }); receiver diff --git a/src/analysis/mod.rs b/src/analysis/mod.rs index 4ae33565..a2d93ae1 100644 --- a/src/analysis/mod.rs +++ b/src/analysis/mod.rs @@ -21,7 +21,7 @@ use std::sync::Mutex; use lsp_types::{DiagnosticSeverity}; use logos::Logos; -use log::{debug, error, info, trace}; +use crate::logging::{debug, error, info, trace}; use rayon::prelude::*; use crate::actions::SourcedDMLError; diff --git a/src/analysis/parsing/parser.rs b/src/analysis/parsing/parser.rs index 466bb756..dd686391 100644 --- a/src/analysis/parsing/parser.rs +++ b/src/analysis/parsing/parser.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 and MIT use logos::Lexer; use regex::Regex; -use log::trace; +use crate::logging::trace; use lazy_static::lazy_static; use crate::span::{Range, ZeroIndexed, Position}; diff --git a/src/analysis/parsing/statement.rs b/src/analysis/parsing/statement.rs index 5d3da738..aa7cb5f0 100644 --- a/src/analysis/parsing/statement.rs +++ b/src/analysis/parsing/statement.rs @@ -1,6 +1,6 @@ // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT -use log::error; +use crate::logging::error; use crate::lint::rules::indentation::{IndentEmptyLoopArgs, IndentContinuationLineArgs}; diff --git a/src/analysis/parsing/structure.rs b/src/analysis/parsing/structure.rs index c0b9104b..3abddcca 100644 --- a/src/analysis/parsing/structure.rs +++ b/src/analysis/parsing/structure.rs @@ -1,7 +1,7 @@ // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT // Types, traits, and structs for the structure of a DML file -use log::{trace}; +use crate::logging::{trace}; use crate::analysis::parsing::expression::{Expression, ensure_string_concatenation}; diff --git a/src/analysis/scope.rs b/src/analysis/scope.rs index e82e4eb4..dd51b8f6 100644 --- a/src/analysis/scope.rs +++ b/src/analysis/scope.rs @@ -8,7 +8,7 @@ use crate::analysis::reference::{Reference}; use crate::analysis::structure::objects::Method; -use log::{debug, trace}; +use crate::logging::{debug, trace}; pub trait Scope : DeclarationSpan + Named { // Need this to create default mappings diff --git a/src/analysis/structure/expressions.rs b/src/analysis/structure/expressions.rs index 460a3b5e..aa19b922 100644 --- a/src/analysis/structure/expressions.rs +++ b/src/analysis/structure/expressions.rs @@ -1,6 +1,6 @@ // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT -use log::{error}; +use crate::logging::{error}; use std::num::{IntErrorKind, ParseIntError}; diff --git a/src/analysis/structure/statements.rs b/src/analysis/structure/statements.rs index 4d99edc0..0724d286 100644 --- a/src/analysis/structure/statements.rs +++ b/src/analysis/structure/statements.rs @@ -1,6 +1,6 @@ // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT -use log::error; +use crate::logging::error; use crate::analysis::{DeclarationSpan, LocalDMLError}; diff --git a/src/analysis/structure/toplevel.rs b/src/analysis/structure/toplevel.rs index c4016b43..cdd9cffd 100644 --- a/src/analysis/structure/toplevel.rs +++ b/src/analysis/structure/toplevel.rs @@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter, self as fmt}; use std::path::PathBuf; -use log::trace; +use crate::logging::trace; use crate::analysis::structure::objects::{Bitorder, CBlock, CompositeObject, CompObjectKind, Constant, Device, diff --git a/src/analysis/templating/objects.rs b/src/analysis/templating/objects.rs index bdf764fd..a247fdef 100644 --- a/src/analysis/templating/objects.rs +++ b/src/analysis/templating/objects.rs @@ -4,7 +4,7 @@ use std::collections::{HashMap, HashSet}; use std::iter; use std::sync::Arc; -use log::{debug, trace, error}; +use crate::logging::{debug, trace, error}; use lsp_types::DiagnosticSeverity; use slotmap::{DefaultKey, Key, SlotMap}; diff --git a/src/analysis/templating/topology.rs b/src/analysis/templating/topology.rs index 7a1b0c75..3678eb59 100644 --- a/src/analysis/templating/topology.rs +++ b/src/analysis/templating/topology.rs @@ -10,7 +10,7 @@ use std::sync::Mutex; use itertools::Itertools; use lazy_static::lazy_static; -use log::{debug, error, trace}; +use crate::logging::{debug, error, trace}; use lsp_types::DiagnosticSeverity; use crate::analysis::DeclarationSpan; diff --git a/src/analysis/templating/traits.rs b/src/analysis/templating/traits.rs index ab2eaed7..11e3774f 100644 --- a/src/analysis/templating/traits.rs +++ b/src/analysis/templating/traits.rs @@ -23,7 +23,7 @@ use crate::analysis::templating::topology::Rank; use crate::analysis::DeclarationSpan; -use log::{debug, error, trace}; +use crate::logging::{debug, error, trace}; use lsp_types::DiagnosticSeverity; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/cmd.rs b/src/cmd.rs index 0bf0c9dc..e809ebea 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -41,7 +41,7 @@ use std::time::{Duration, Instant}; use serde_json; use lazy_static::lazy_static; -use log::debug; +use crate::logging::debug; /// Runs the DLS in command line mode. pub fn run(compile_info_path: Option, diff --git a/src/config.rs b/src/config.rs index 6783c48f..459e4674 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,7 +10,7 @@ use std::path::PathBuf; use serde::de::Deserializer; use serde::{Deserialize, Serialize}; -use log::{error, trace}; +use crate::logging::{error, trace}; use crate::lsp_data::SerializeError; diff --git a/src/dfa/client.rs b/src/dfa/client.rs index b404ee11..05693505 100644 --- a/src/dfa/client.rs +++ b/src/dfa/client.rs @@ -28,7 +28,7 @@ use crate::server::{self, Notification}; use crate::cmd; use crate::lsp_data::{parse_file_path, parse_uri}; -use log::{debug, trace}; +use crate::logging::{debug, trace}; #[derive(Debug, PartialEq)] pub struct Diagnostic { diff --git a/src/dfa/main.rs b/src/dfa/main.rs index f373cd9d..5280b431 100644 --- a/src/dfa/main.rs +++ b/src/dfa/main.rs @@ -15,8 +15,6 @@ use subprocess::ExitStatus; use clap::{command, arg, Arg, ArgAction}; use dls::dfa::ClientInterface; - - use log::debug; pub fn main() { diff --git a/src/file_management.rs b/src/file_management.rs index cd2de599..e0747f88 100644 --- a/src/file_management.rs +++ b/src/file_management.rs @@ -1,7 +1,7 @@ // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT //! Contains utilities and file management -use log::{debug, error, trace}; +use crate::logging::{debug, error, trace}; use std::collections::HashMap; use std::fs; diff --git a/src/lint/mod.rs b/src/lint/mod.rs index f5d2210f..8d69b929 100644 --- a/src/lint/mod.rs +++ b/src/lint/mod.rs @@ -6,7 +6,7 @@ use std::fs; use std::path::{Path, PathBuf}; use std::str::FromStr; use lazy_static::lazy_static; -use log::{debug, error, trace}; +use crate::logging::{debug, error, trace}; use rules::linelength::{BreakBeforeBinaryOpOptions, BreakFuncCallOpenParenOptions, BreakMethodOutputOptions, diff --git a/src/logging.rs b/src/logging.rs index 01b7f377..d783d7e2 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -1,6 +1,70 @@ // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT +use std::sync::LazyLock; + +macro_rules! info { + ($($arg:tt)*) => { + crate::log_with_fn!(log::info, log::Level::Info, $($arg)*) + }; +} + +macro_rules! trace { + ($($arg:tt)*) => { + crate::log_with_fn!(log::trace, log::Level::Trace, $($arg)*) + }; +} + +macro_rules! debug { + ($($arg:tt)*) => { + crate::log_with_fn!(log::debug, log::Level::Debug, $($arg)*) + }; +} + +macro_rules! error { + ($($arg:tt)*) => { + crate::log_with_fn!(log::error, log::Level::Error, $($arg)*) + }; +} + +#[allow(clippy::crate_in_macro_def)] +#[macro_export] +macro_rules! log_with_fn { + ($log:path, $level:expr, $($arg:tt)*) => { + if (log::log_enabled!($level)) { + $log!("{}", $crate::format_truncated!(*crate::logging::MAX_LOG_MESSAGE_LENGTH, $($arg)*)); + } + } +} + +pub (crate) use {debug, error, info, trace}; + +pub static MAX_LOG_MESSAGE_LENGTH: LazyLock> = + LazyLock::new(|| { + std::env::var("MAX_LOG_MESSAGE_LENGTH").ok() + .or_else(||Some("1000".to_string())) + .and_then(|s| s.parse().ok()) + }); + +#[macro_export] +macro_rules! format_truncated { + ($trunc_len:expr, $($arg:tt)*) => {{ + let s = format!($($arg)*); + 'check_block: { + if let Some(max_len) = $trunc_len { + if max_len > 0 && s.len() > max_len { + let mut slice_index = max_len; + while !s.is_char_boundary(slice_index) { + slice_index -= 1; + } + break 'check_block [&s[..slice_index], " ..."].concat(); + } + } + s + } + }}; +} + pub fn init() { // Slightly dumb way to do this, build the logger once with defaults // to get the max level for all modules from env, then build again @@ -16,3 +80,29 @@ pub fn init() { pub fn set_global_log_level(level: log::LevelFilter) { log::set_max_level(level); } + +#[cfg(test)] +mod tests { + #[test] + fn test_format_truncated() { + let s = format_truncated!(Some(5), "Hello, world!"); + assert_eq!(s, "Hello ..."); + let s = format_truncated!(Some(20), "Hello, world!"); + assert_eq!(s, "Hello, world!"); + let s = format_truncated!(None, "Hello, world!"); + assert_eq!(s, "Hello, world!"); + } + + #[test] + fn test_format_unicode() { + // These particular emojis are 4 bytes each + let s = format_truncated!(Some(8), "😀😀😀😀😀"); + assert_eq!(s, "😀😀 ..."); + let s = format_truncated!(Some(7), "😀😀😀😀😀"); + assert_eq!(s, "😀 ..."); + let s = format_truncated!(Some(11), "😀😀😀😀😀"); + assert_eq!(s, "😀😀 ..."); + let s = format_truncated!(Some(30), "😀😀😀😀😀"); + assert_eq!(s, "😀😀😀😀😀"); + } +} diff --git a/src/server/dispatch.rs b/src/server/dispatch.rs index 514da630..5e4ee43e 100644 --- a/src/server/dispatch.rs +++ b/src/server/dispatch.rs @@ -5,7 +5,7 @@ use std::thread; use std::time::Duration; use jsonrpc::error::StandardError::InternalError; -use log::{info, error, debug}; +use crate::logging::{info, error, debug}; use crate::actions::work_pool; use crate::actions::work_pool::WorkDescription; diff --git a/src/server/io.rs b/src/server/io.rs index 5a7ff886..76999d65 100644 --- a/src/server/io.rs +++ b/src/server/io.rs @@ -1,7 +1,7 @@ // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT use jsonrpc::error::{RpcError, StandardError, standard_error}; -use log::{debug, trace}; +use crate::logging::{debug, trace}; use serde_json::Value; use super::{Notification, Request, RequestId}; diff --git a/src/server/message.rs b/src/server/message.rs index 054b43b4..eee5b56b 100644 --- a/src/server/message.rs +++ b/src/server/message.rs @@ -10,7 +10,7 @@ use jsonrpc::error::{ standard_error, StandardError::{self, InvalidParams, InvalidRequest, ParseError}, }; -use log::debug; +use crate::logging::debug; use lsp_types::notification::ShowMessage; use serde::ser::{SerializeStruct, Serializer}; use serde::Deserialize; diff --git a/src/server/mod.rs b/src/server/mod.rs index 582a9efd..ac10a093 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -25,8 +25,9 @@ pub use crate::server::message::{ RequestId, Response, ResponseError, ResponseWithMessage, }; use crate::version; +use crate::logging::{debug, error, info, trace}; + use jsonrpc::error::StandardError; -use log::{debug, error, info, trace, warn}; pub use lsp_types::notification::{Exit as ExitNotification, ShowMessage}; pub use lsp_types::request::Initialize as InitializeRequest; pub use lsp_types::request::Shutdown as ShutdownRequest; @@ -117,11 +118,7 @@ pub(crate) fn maybe_notify_unknown_configs(_out: &O, unknowns: &[Stri write!(msg, "{}`{}` ", if first { ' ' } else { ',' }, key).unwrap(); first = false; } - warn!("{}", msg); - // out.notify(Notification::::new(ShowMessageParams { - // typ: MessageType::WARNING, - // message: msg, - // })); + info!("{}", msg); } #[allow(dead_code)] @@ -492,7 +489,7 @@ impl LsService { } } else { - warn!( + error!( "Server has not yet received an `initialize` request, ignoring {}", $method, ); } @@ -535,7 +532,7 @@ impl LsService { self.dispatcher.dispatch(request, ctx); } else { - warn!( + error!( "Server has not yet received an `initialize` request, cannot handle {}", $method, ); self.output.failure_message( diff --git a/src/vfs/mod.rs b/src/vfs/mod.rs index 0ad4dad0..64ac0aa8 100644 --- a/src/vfs/mod.rs +++ b/src/vfs/mod.rs @@ -1,6 +1,6 @@ // © 2024 Intel Corporation // SPDX-License-Identifier: Apache-2.0 and MIT -use log::trace; +use crate::logging::trace; use std::collections::HashMap; use std::cmp::Ordering;