Skip to content

Commit c106d85

Browse files
authored
feat(tracing): output logs to file (#377)
1 parent 1fd4284 commit c106d85

File tree

10 files changed

+264
-33
lines changed

10 files changed

+264
-33
lines changed

Cargo.lock

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ syn = { version = "2.0", default-features = false }
212212
# tracing/logging
213213
log = "0.4.21"
214214
tracing = { version = "0.1.38", features = [ "log" ], default-features = false }
215+
tracing-appender = "0.2"
215216
tracing-log = "0.1.3"
216217
tracing-opentelemetry = "0.31.0"
217218
tracing-subscriber = "0.3.16"

crates/cli/src/args.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,17 @@ pub struct SequencerNodeArgs {
133133

134134
impl SequencerNodeArgs {
135135
pub async fn execute(&self) -> Result<()> {
136-
// Initialize logging with tracer
137-
let tracer_config = self.tracer_config();
138-
katana_tracing::init(self.logging.log_format, tracer_config).await?;
136+
let logging = katana_tracing::LoggingConfig {
137+
stdout_format: self.logging.stdout.stdout_format,
138+
stdout_color: self.logging.stdout.color,
139+
file_enabled: self.logging.file.enabled,
140+
file_format: self.logging.file.file_format,
141+
file_directory: self.logging.file.directory.clone(),
142+
file_max_files: self.logging.file.max_files,
143+
};
144+
145+
katana_tracing::init(logging, self.tracer_config()).await?;
146+
139147
self.start_node().await
140148
}
141149

crates/cli/src/full.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,17 @@ pub struct FullNodeArgs {
6161

6262
impl FullNodeArgs {
6363
pub async fn execute(&self) -> Result<()> {
64-
// Initialize logging with tracer
65-
let tracer_config = self.tracer_config();
66-
katana_tracing::init(self.logging.log_format, tracer_config).await?;
64+
let logging = katana_tracing::LoggingConfig {
65+
stdout_format: self.logging.stdout.stdout_format,
66+
stdout_color: self.logging.stdout.color,
67+
file_enabled: self.logging.file.enabled,
68+
file_format: self.logging.file.file_format,
69+
file_directory: self.logging.file.directory.clone(),
70+
file_max_files: self.logging.file.max_files,
71+
};
72+
73+
katana_tracing::init(logging, self.tracer_config()).await?;
74+
6775
self.start_node().await
6876
}
6977

crates/cli/src/options.rs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#[cfg(feature = "server")]
1111
use std::net::IpAddr;
1212
use std::num::NonZeroU128;
13+
use std::path::PathBuf;
1314

1415
use clap::Args;
1516
use katana_genesis::Genesis;
@@ -30,7 +31,7 @@ use katana_primitives::block::{BlockHashOrNumber, GasPrice};
3031
use katana_primitives::chain::ChainId;
3132
#[cfg(feature = "server")]
3233
use katana_rpc_server::cors::HeaderValue;
33-
use katana_tracing::{gcloud, otlp, LogFormat, TracerConfig};
34+
use katana_tracing::{default_log_file_directory, gcloud, otlp, LogColor, LogFormat, TracerConfig};
3435
use serde::{Deserialize, Serialize};
3536
use serde_utils::serialize_opt_as_hex;
3637
use url::Url;
@@ -41,6 +42,7 @@ use crate::utils::{parse_block_hash_or_number, parse_genesis};
4142

4243
const DEFAULT_DEV_SEED: &str = "0";
4344
const DEFAULT_DEV_ACCOUNTS: u16 = 10;
45+
const DEFAULT_LOG_FILE_MAX_FILES: usize = 7;
4446

4547
#[cfg(feature = "server")]
4648
#[derive(Debug, Args, Clone, Serialize, Deserialize, PartialEq)]
@@ -433,11 +435,59 @@ pub struct ForkingOptions {
433435
#[derive(Debug, Args, Clone, Serialize, Deserialize, Default, PartialEq)]
434436
#[command(next_help_heading = "Logging options")]
435437
pub struct LoggingOptions {
436-
/// Log format to use
437-
#[arg(long = "log.format", value_name = "FORMAT")]
438+
#[command(flatten)]
439+
pub stdout: StdoutLoggingOptions,
440+
441+
#[command(flatten)]
442+
pub file: FileLoggingOptions,
443+
}
444+
445+
#[derive(Debug, Args, Clone, Serialize, Deserialize, Default, PartialEq)]
446+
pub struct StdoutLoggingOptions {
447+
#[arg(long = "log.stdout.format", value_name = "FORMAT")]
448+
#[arg(default_value_t = LogFormat::Full)]
449+
pub stdout_format: LogFormat,
450+
451+
/// Sets whether or not the formatter emits ANSI terminal escape codes for colors and other
452+
/// text formatting
453+
///
454+
/// Possible values:
455+
/// - always: Colors on
456+
/// - auto: Auto-detect
457+
/// - never: Colors off
458+
#[arg(long = "color", value_name = "COLOR")]
459+
#[arg(default_value_t = LogColor::Always)]
460+
pub color: LogColor,
461+
}
462+
463+
#[derive(Debug, Args, Clone, Serialize, Deserialize, Default, PartialEq)]
464+
pub struct FileLoggingOptions {
465+
/// Enable writing logs to files.
466+
#[arg(long = "log.file")]
467+
#[serde(default)]
468+
pub enabled: bool,
469+
470+
#[arg(requires = "enabled")]
471+
#[arg(long = "log.file.format", value_name = "FORMAT")]
438472
#[arg(default_value_t = LogFormat::Full)]
439-
pub log_format: LogFormat,
473+
pub file_format: LogFormat,
474+
475+
/// The path to put log files in
476+
#[arg(requires = "enabled")]
477+
#[arg(long = "log.file.directory", value_name = "PATH")]
478+
#[arg(default_value_os_t = default_log_file_directory())]
479+
#[serde(default = "default_log_file_directory")]
480+
pub directory: PathBuf,
481+
482+
/// Maximum number of daily log files to keep.
483+
///
484+
/// If `0` is supplied, no files are deleted (unlimited retention).
485+
#[arg(requires = "enabled")]
486+
#[arg(long = "log.file.max-files", value_name = "COUNT")]
487+
#[arg(default_value_t = DEFAULT_LOG_FILE_MAX_FILES)]
488+
pub max_files: usize,
440489
}
490+
441491
#[derive(Debug, Args, Default, Clone, Serialize, Deserialize, PartialEq)]
442492
#[command(next_help_heading = "Gas Price Oracle Options")]
443493
pub struct GasPriceOracleOptions {

crates/cli/src/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub fn print_intro(args: &SequencerNodeArgs, chain: &ChainSpec) {
5656
let account_class_hash = accounts.peek().map(|e| e.1.class_hash());
5757
let seed = &args.development.seed;
5858

59-
if args.logging.log_format == LogFormat::Json {
59+
if args.logging.stdout.stdout_format == LogFormat::Json {
6060
info!(
6161
target: LOG_TARGET,
6262
"{}",

crates/node-bindings/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ impl Katana {
510510
}
511511

512512
if self.json_log {
513-
cmd.args(["--log.format", "json"]);
513+
cmd.args(["--log.stdout.format", "json"]);
514514
}
515515

516516
if let Some(fork_block_number) = self.fork_block_number {

crates/tracing/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ version.workspace = true
99
clap.workspace = true
1010
serde.workspace = true
1111
thiserror.workspace = true
12+
dirs = "6.0.0"
1213
tracing.workspace = true
14+
tracing-appender.workspace = true
1315
tracing-log.workspace = true
1416
tracing-subscriber = { workspace = true, features = [ "chrono", "env-filter", "json", "time", "tracing-log" ] }
1517

crates/tracing/src/fmt.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,42 @@ use serde::{Deserialize, Serialize};
44
use tracing_subscriber::fmt::format::Writer;
55
use tracing_subscriber::fmt::time::{self};
66

7+
/// Controls when ANSI escape codes are emitted in log output.
8+
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, Default, Eq)]
9+
pub enum LogColor {
10+
/// Colors on.
11+
#[default]
12+
Always,
13+
/// Auto-detect.
14+
Auto,
15+
/// Colors off.
16+
Never,
17+
}
18+
19+
impl Display for LogColor {
20+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21+
match self {
22+
Self::Always => write!(f, "always"),
23+
Self::Auto => write!(f, "auto"),
24+
Self::Never => write!(f, "never"),
25+
}
26+
}
27+
}
28+
29+
impl clap::ValueEnum for LogColor {
30+
fn value_variants<'a>() -> &'a [Self] {
31+
&[Self::Always, Self::Auto, Self::Never]
32+
}
33+
34+
fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
35+
match self {
36+
Self::Always => Some(clap::builder::PossibleValue::new("always")),
37+
Self::Auto => Some(clap::builder::PossibleValue::new("auto")),
38+
Self::Never => Some(clap::builder::PossibleValue::new("never")),
39+
}
40+
}
41+
}
42+
743
/// Format for logging output.
844
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, Default, Eq)]
945
pub enum LogFormat {

0 commit comments

Comments
 (0)