[refactor](decoders): extract decoder logging into trx-decode-log crate
Move DecoderLoggers and DecodeLogsConfig out of trx-server into a dedicated src/decoders/trx-decode-log crate, giving file logging the same standalone crate treatment as the four decoder crates. - src/decoders/trx-decode-log/ (new — DecodeLogsConfig + DecoderLoggers) - trx-server/config.rs: re-exports DecodeLogsConfig from trx-decode-log so ServerConfig field references and all tests compile unchanged - trx-server: drop decode_logs module, use trx_decode_log directly Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
# SPDX-FileCopyrightText: 2026 Stanislaw Grams <stanislawgrams@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
[package]
|
||||
name = "trx-decode-log"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
trx-core = { path = "../../trx-core" }
|
||||
chrono = { version = "0.4", default-features = false, features = ["clock"] }
|
||||
dirs = "6"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
@@ -1,7 +1,12 @@
|
||||
// SPDX-FileCopyrightText: 2025 Stanislaw Grams <stanislawgrams@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2026 Stanislaw Grams <stanislawgrams@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
//! Server-side decoder file logging (APRS / CW / FT8 / WSPR).
|
||||
//!
|
||||
//! Provides [`DecodeLogsConfig`] for TOML configuration and [`DecoderLoggers`]
|
||||
//! for writing JSON-Lines log files with automatic daily rotation.
|
||||
|
||||
use std::fs::{create_dir_all, File, OpenOptions};
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -9,12 +14,62 @@ use std::sync::{Arc, Mutex};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use chrono::Utc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::config::DecodeLogsConfig;
|
||||
use trx_core::decode::{AprsPacket, CwEvent, Ft8Message, WsprMessage};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Configuration
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
fn default_decode_logs_dir() -> String {
|
||||
if let Some(data_dir) = dirs::data_dir() {
|
||||
return data_dir
|
||||
.join("trx-rs")
|
||||
.join("decoders")
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
}
|
||||
"logs/decoders".to_string()
|
||||
}
|
||||
|
||||
/// Server-side decoder file logging configuration.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct DecodeLogsConfig {
|
||||
/// Whether decoder file logging is enabled
|
||||
pub enabled: bool,
|
||||
/// Base directory for log files
|
||||
pub dir: String,
|
||||
/// APRS decoder log filename
|
||||
pub aprs_file: String,
|
||||
/// CW decoder log filename
|
||||
pub cw_file: String,
|
||||
/// FT8 decoder log filename
|
||||
pub ft8_file: String,
|
||||
/// WSPR decoder log filename
|
||||
pub wspr_file: String,
|
||||
}
|
||||
|
||||
impl Default for DecodeLogsConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: false,
|
||||
dir: default_decode_logs_dir(),
|
||||
aprs_file: "TRXRS-APRS-%YYYY%-%MM%-%DD%.log".to_string(),
|
||||
cw_file: "TRXRS-CW-%YYYY%-%MM%-%DD%.log".to_string(),
|
||||
ft8_file: "TRXRS-FT8-%YYYY%-%MM%-%DD%.log".to_string(),
|
||||
wspr_file: "TRXRS-WSPR-%YYYY%-%MM%-%DD%.log".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// File logger (private)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct DecoderFileLogger {
|
||||
base_dir: PathBuf,
|
||||
file_template: String,
|
||||
@@ -64,7 +119,7 @@ impl DecoderFileLogger {
|
||||
})
|
||||
}
|
||||
|
||||
fn write_payload<T: serde::Serialize>(&self, payload: &T) {
|
||||
fn write_payload<T: Serialize>(&self, payload: &T) {
|
||||
let ts_ms = match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||
Ok(d) => d.as_millis() as u64,
|
||||
Err(_) => 0,
|
||||
@@ -106,6 +161,11 @@ impl DecoderFileLogger {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public API
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Aggregate logger for all four server-side decoders.
|
||||
pub struct DecoderLoggers {
|
||||
aprs: DecoderFileLogger,
|
||||
cw: DecoderFileLogger,
|
||||
@@ -114,6 +174,7 @@ pub struct DecoderLoggers {
|
||||
}
|
||||
|
||||
impl DecoderLoggers {
|
||||
/// Create loggers from config, or return `None` when logging is disabled.
|
||||
pub fn from_config(cfg: &DecodeLogsConfig) -> Result<Option<Arc<Self>>, String> {
|
||||
if !cfg.enabled {
|
||||
return Ok(None);
|
||||
@@ -26,6 +26,7 @@ trx-backend = { path = "trx-backend" }
|
||||
trx-core = { path = "../trx-core" }
|
||||
trx-aprs = { path = "../decoders/trx-aprs" }
|
||||
trx-cw = { path = "../decoders/trx-cw" }
|
||||
trx-decode-log = { path = "../decoders/trx-decode-log" }
|
||||
trx-ft8 = { path = "../decoders/trx-ft8" }
|
||||
trx-wspr = { path = "../decoders/trx-wspr" }
|
||||
trx-protocol = { path = "../trx-protocol" }
|
||||
|
||||
@@ -28,7 +28,7 @@ use trx_ft8::Ft8Decoder;
|
||||
use trx_wspr::WsprDecoder;
|
||||
|
||||
use crate::config::AudioConfig;
|
||||
use crate::decode_logs::DecoderLoggers;
|
||||
use trx_decode_log::DecoderLoggers;
|
||||
|
||||
const APRS_HISTORY_RETENTION: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
const FT8_HISTORY_RETENTION: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
|
||||
@@ -16,6 +16,7 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use trx_app::{ConfigError, ConfigFile};
|
||||
pub use trx_decode_log::DecodeLogsConfig;
|
||||
|
||||
use trx_core::rig::state::RigMode;
|
||||
|
||||
@@ -260,48 +261,6 @@ impl Default for AprsFiConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn default_decode_logs_dir() -> String {
|
||||
if let Some(data_dir) = dirs::data_dir() {
|
||||
return data_dir
|
||||
.join("trx-rs")
|
||||
.join("decoders")
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
}
|
||||
"logs/decoders".to_string()
|
||||
}
|
||||
|
||||
/// Server-side decoder file logging configuration.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct DecodeLogsConfig {
|
||||
/// Whether decoder file logging is enabled
|
||||
pub enabled: bool,
|
||||
/// Base directory for log files
|
||||
pub dir: String,
|
||||
/// APRS decoder log filename
|
||||
pub aprs_file: String,
|
||||
/// CW decoder log filename
|
||||
pub cw_file: String,
|
||||
/// FT8 decoder log filename
|
||||
pub ft8_file: String,
|
||||
/// WSPR decoder log filename
|
||||
pub wspr_file: String,
|
||||
}
|
||||
|
||||
impl Default for DecodeLogsConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: false,
|
||||
dir: default_decode_logs_dir(),
|
||||
aprs_file: "TRXRS-APRS-%YYYY%-%MM%-%DD%.log".to_string(),
|
||||
cw_file: "TRXRS-CW-%YYYY%-%MM%-%DD%.log".to_string(),
|
||||
ft8_file: "TRXRS-FT8-%YYYY%-%MM%-%DD%.log".to_string(),
|
||||
wspr_file: "TRXRS-WSPR-%YYYY%-%MM%-%DD%.log".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ServerConfig {
|
||||
pub fn validate(&self) -> Result<(), String> {
|
||||
validate_log_level(self.general.log_level.as_deref())?;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
mod aprsfi;
|
||||
mod audio;
|
||||
mod config;
|
||||
mod decode_logs;
|
||||
mod error;
|
||||
mod listener;
|
||||
mod pskreporter;
|
||||
@@ -34,7 +33,7 @@ use trx_core::rig::state::RigState;
|
||||
use trx_core::DynResult;
|
||||
|
||||
use config::ServerConfig;
|
||||
use decode_logs::DecoderLoggers;
|
||||
use trx_decode_log::DecoderLoggers;
|
||||
|
||||
const PKG_DESCRIPTION: &str = concat!(env!("CARGO_PKG_NAME"), " - rig server daemon");
|
||||
const RIG_TASK_CHANNEL_BUFFER: usize = 32;
|
||||
|
||||
Reference in New Issue
Block a user