add file logging
Some checks are pending
Deny / audit (push) Waiting to run

This commit is contained in:
Boog900 2024-11-20 16:06:31 +00:00
parent 86bbf55954
commit fd4a1746b1
No known key found for this signature in database
GPG key ID: 42AB1287CB0041C2
12 changed files with 235 additions and 31 deletions

67
Cargo.lock generated
View file

@ -1082,6 +1082,7 @@ dependencies = [
"toml",
"tower 0.5.1 (git+https://github.com/Cuprate/tower.git?rev=6c7faf0)",
"tracing",
"tracing-appender",
"tracing-subscriber",
]
@ -1144,6 +1145,15 @@ dependencies = [
"parking_lot_core",
]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]]
name = "diff"
version = "0.1.13"
@ -1987,6 +1997,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.19"
@ -2149,6 +2165,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.20"
@ -2889,6 +2911,37 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a693d0c8cf16973fac5a93fbe47b8c6452e7097d4fcac49f3d7a18e39c76e62e"
[[package]]
name = "time"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "tinyvec"
version = "1.8.0"
@ -2978,6 +3031,8 @@ dependencies = [
"bytes",
"futures-core",
"futures-sink",
"futures-util",
"hashbrown 0.14.5",
"pin-project-lite",
"slab",
"tokio",
@ -3084,6 +3139,18 @@ dependencies = [
"tracing-core",
]
[[package]]
name = "tracing-appender"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf"
dependencies = [
"crossbeam-channel",
"thiserror",
"time",
"tracing-subscriber",
]
[[package]]
name = "tracing-attributes"
version = "0.1.27"

View file

@ -122,6 +122,7 @@ tokio-stream = { version = "0.1", default-features = false }
tokio = { version = "1", default-features = false }
tower = { git = "https://github.com/Cuprate/tower.git", rev = "6c7faf0", default-features = false } # <https://github.com/tower-rs/tower/pull/796>
toml = { version = "0.8", default-features = false }
tracing-appender = { version = "0.2", default-features = false }
tracing-subscriber = { version = "0.3", default-features = false }
tracing = { version = "0.1", default-features = false }

View file

@ -10,7 +10,7 @@
network = "Mainnet"
## Tracing config.
[tracing]
[tracing.stdout]
## The minimum level for log events to be displayed.
level = "info"

View file

@ -68,11 +68,12 @@ serde_json = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }
thread_local = { workspace = true }
tokio-util = { workspace = true }
tokio-util = { workspace = true, features = ["rt"] }
tokio-stream = { workspace = true }
tokio = { workspace = true }
toml = { workspace = true, features = ["parse", "display"]}
tower = { workspace = true }
tracing-appender = { workspace = true }
tracing-subscriber = { workspace = true, features = ["std", "fmt", "default"] }
tracing = { workspace = true, features = ["default"] }

View file

@ -3,6 +3,7 @@ use std::{collections::HashMap, sync::Arc};
use futures::StreamExt;
use monero_serai::block::Block;
use tokio::sync::{mpsc, oneshot, Notify};
use tokio_util::sync::CancellationToken;
use tower::{Service, ServiceExt};
use tracing::error;

View file

@ -9,7 +9,7 @@ use rayon::prelude::*;
use std::ops::ControlFlow;
use std::{collections::HashMap, sync::Arc};
use tower::{Service, ServiceExt};
use tracing::info;
use tracing::{info, instrument};
use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle};
use cuprate_consensus::{
@ -120,6 +120,7 @@ impl super::BlockchainManager {
///
/// This function will panic if the batch is empty or if any internal service returns an unexpected
/// error that we cannot recover from or if the incoming batch contains no blocks.
#[instrument(name = "incoming_block_batch" skip_all, level = "info", fields(start_height = batch.blocks.first().unwrap().0.number().unwrap(), len = batch.blocks.len()))]
pub async fn handle_incoming_block_batch(&mut self, batch: BlockBatch) {
let (first_block, _) = batch
.blocks
@ -146,10 +147,7 @@ impl super::BlockchainManager {
/// This function will panic if any internal service returns an unexpected error that we cannot
/// recover from or if the incoming batch contains no blocks.
async fn handle_incoming_block_batch_main_chain(&mut self, batch: BlockBatch) {
info!(
"Handling batch to main chain height: {}",
batch.blocks.first().unwrap().0.number().unwrap()
);
let start_height = batch.blocks.first().unwrap().0.number().unwrap();
let batch_prep_res = self
.block_verifier_service
@ -192,6 +190,7 @@ impl super::BlockchainManager {
self.add_valid_block_to_main_chain(verified_block).await;
}
info!("Successfully added block batch");
}
/// Handles an incoming [`BlockBatch`] that does not follow the main-chain.

View file

@ -80,7 +80,7 @@ pub struct Config {
/// The storage config.
storage: StorageConfig,
fs: FileSystemConfig,
pub fs: FileSystemConfig,
}
impl Config {

View file

@ -2,15 +2,22 @@ use serde::{Deserialize, Serialize};
use tracing::level_filters::LevelFilter;
/// [`tracing`] config.
#[derive(Deserialize, Serialize)]
#[derive(Default, Deserialize, Serialize)]
#[serde(deny_unknown_fields, default)]
pub struct TracingConfig {
pub stdout: StdoutTracingConfig,
pub file: FileTracingConfig,
}
#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields, default)]
pub struct StdoutTracingConfig {
/// The default minimum log level.
#[serde(with = "level_filter_serde")]
pub level: LevelFilter,
}
impl Default for TracingConfig {
impl Default for StdoutTracingConfig {
fn default() -> Self {
Self {
level: LevelFilter::INFO,
@ -18,6 +25,25 @@ impl Default for TracingConfig {
}
}
#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields, default)]
pub struct FileTracingConfig {
/// The default minimum log level.
#[serde(with = "level_filter_serde")]
pub level: LevelFilter,
pub max_log_files: usize,
}
impl Default for FileTracingConfig {
fn default() -> Self {
Self {
level: LevelFilter::DEBUG,
max_log_files: 7,
}
}
}
mod level_filter_serde {
use std::str::FromStr;

View file

@ -0,0 +1,105 @@
use crate::config::Config;
use cuprate_helper::fs::logs_path;
use std::mem::forget;
use std::sync::OnceLock;
use tracing::instrument::WithSubscriber;
use tracing::level_filters::LevelFilter;
use tracing::subscriber::Interest;
use tracing::Metadata;
use tracing_appender::non_blocking::NonBlocking;
use tracing_appender::rolling::Rotation;
use tracing_subscriber::filter::Filtered;
use tracing_subscriber::fmt::format::{DefaultFields, Format};
use tracing_subscriber::layer::{Context, Layered, SubscriberExt};
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{
fmt::Layer as FmtLayer,
layer::Filter,
reload::{Handle, Layer as ReloadLayer},
Layer,
};
use tracing_subscriber::{reload, Registry};
static FILE_WRITER_FILTER_HANDLE: OnceLock<Handle<CupratedTracingFilter, Registry>> =
OnceLock::new();
static STDOUT_FILTER_HANDLE: OnceLock<
Handle<
CupratedTracingFilter,
Layered<
Filtered<
FmtLayer<Registry, DefaultFields, Format, NonBlocking>,
ReloadLayer<CupratedTracingFilter, Registry>,
Registry,
>,
Registry,
Registry,
>,
>,
> = OnceLock::new();
pub struct CupratedTracingFilter {
pub level: LevelFilter,
}
impl<S> Filter<S> for CupratedTracingFilter {
fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
Filter::<S>::enabled(&self.level, meta, cx)
}
fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
Filter::<S>::callsite_enabled(&self.level, meta)
}
fn max_level_hint(&self) -> Option<LevelFilter> {
Some(self.level)
}
}
pub fn init_logging(config: &Config) {
use tracing_subscriber::{fmt, Layer};
let (stdout_filter, stdout_handle) = reload::Layer::new(CupratedTracingFilter {
level: config.tracing.stdout.level,
});
drop(STDOUT_FILTER_HANDLE.set(stdout_handle));
let stdout_layer = fmt::Layer::default()
.with_target(false)
.with_filter(stdout_filter);
let appender_config = &config.tracing.file;
let (appender, guard) = tracing_appender::non_blocking(
tracing_appender::rolling::Builder::new()
.rotation(Rotation::DAILY)
.max_log_files(appender_config.max_log_files)
.build(logs_path(&config.fs.data_directory, config.network()))
.unwrap(),
);
forget(guard);
let (appender_filter, appender_handle) = reload::Layer::new(CupratedTracingFilter {
level: appender_config.level,
});
drop(FILE_WRITER_FILTER_HANDLE.set(appender_handle));
let appender_layer = fmt::layer()
.with_target(false)
.with_ansi(false)
.with_writer(appender)
.with_filter(appender_filter);
tracing_subscriber::registry()
.with(appender_layer)
.with(stdout_layer)
.init();
}
pub fn modify_stdout_output(f: impl FnOnce(&mut CupratedTracingFilter)) {
STDOUT_FILTER_HANDLE.get().unwrap().modify(f).unwrap();
}
pub fn modify_file_output(f: impl FnOnce(&mut CupratedTracingFilter)) {
FILE_WRITER_FILTER_HANDLE.get().unwrap().modify(f).unwrap();
}

View file

@ -30,6 +30,7 @@ mod blockchain;
mod commands;
mod config;
mod constants;
mod logging;
mod p2p;
mod rpc;
mod signals;
@ -42,7 +43,7 @@ fn main() {
let config = config::read_config_and_args();
let log_level_handle = init_logging(&config);
logging::init_logging(&config);
let rt = init_tokio_rt();
@ -98,21 +99,10 @@ fn main() {
let (command_tx, command_rx) = mpsc::channel(1);
std::thread::spawn(|| commands::command_listener(command_tx));
io_loop(command_rx, log_level_handle).await;
io_loop(command_rx).await;
});
}
fn init_logging(config: &Config) -> Handle<LevelFilter, Registry> {
let (filter, handle) = tracing_subscriber::reload::Layer::new(config.tracing.level);
tracing_subscriber::registry()
.with(filter)
.with(tracing_subscriber::fmt::Layer::default().with_target(false))
.init();
handle
}
fn init_tokio_rt() -> tokio::runtime::Runtime {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
@ -120,16 +110,11 @@ fn init_tokio_rt() -> tokio::runtime::Runtime {
.unwrap()
}
async fn io_loop(
mut incoming_commands: mpsc::Receiver<Command>,
tracing_level_handle: Handle<LevelFilter, Registry>,
) -> ! {
async fn io_loop(mut incoming_commands: mpsc::Receiver<Command>) -> ! {
while let Some(command) = incoming_commands.recv().await {
match command {
Command::SetLog { level } => {
tracing_level_handle
.modify(|filter| *filter = level)
.unwrap();
logging::modify_stdout_output(|filter| filter.level = level);
println!("LOG LEVEL CHANGED: {level}");
}

View file

@ -200,6 +200,21 @@ pub fn txpool_path(data_dir: &Path, network: Network) -> PathBuf {
path_with_network(data_dir, network).join("txpool")
}
/// Cuprate's logs directory.
///
/// This is the PATH used for all Cuprate log files.
///
/// ```rust
/// use cuprate_helper::{network::Network, fs::{CUPRATE_DATA_DIR, logs_path}};
///
/// assert_eq!(logs_path(&**CUPRATE_DATA_DIR, Network::Mainnet).as_path(), CUPRATE_DATA_DIR.join("logs"));
/// assert_eq!(logs_path(&**CUPRATE_DATA_DIR, Network::Stagenet).as_path(), CUPRATE_DATA_DIR.join(Network::Stagenet.to_string()).join("logs"));
/// assert_eq!(logs_path(&**CUPRATE_DATA_DIR, Network::Testnet).as_path(), CUPRATE_DATA_DIR.join(Network::Testnet.to_string()).join("logs"));
/// ```
pub fn logs_path(data_dir: &Path, network: Network) -> PathBuf {
path_with_network(data_dir, network).join("logs")
}
/// Cuprate's address-book directory.
///
/// This is the PATH used for any Cuprate address-book files.

View file

@ -42,7 +42,11 @@ pub(crate) fn save_peers_to_disk<Z: BorshNetworkZone>(
let file = cfg
.peer_store_directory
.join(format!("{}_p2p_state", Z::NAME));
spawn_blocking(move || fs::write(&file, &data))
spawn_blocking(move || {
fs::create_dir_all(file.parent().unwrap())?;
fs::write(&file, &data)
})
}
pub(crate) async fn read_peers_from_disk<Z: BorshNetworkZone>(