Add profile (preset) CRUD and startup replay (ticket 009)
Introduces `src/profile.rs`: a `Profile` bundles param/metric declarations plus a placeholder dashboards field, and `ProfileStore` persists all profiles as a single profiles.json file, resolved relative to the settings file's directory (same convention as ticket 010's CSS storage). Adds CRUD (create/list/get/delete/set_active) that keeps Settings.profiles.names and active_profile in sync, plus record_param_declaration/record_metric_declaration hooks that ticket 004's HTTP API will call to persist newly-declared params/metrics into the active profile. Wires main.rs to replay the active profile's declarations into the engine before spawning the ingest task, so backfill/live-derivation semantics apply uniformly to every ingested line. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
f259bdc49b
commit
4c8918ec8c
+34
@@ -7,6 +7,7 @@ mod filter_parser;
|
||||
mod index_key;
|
||||
mod ingest;
|
||||
mod metric_primitive;
|
||||
mod profile;
|
||||
mod settings;
|
||||
mod timestamp;
|
||||
|
||||
@@ -17,6 +18,7 @@ use clap::Parser;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use profile::ProfileStore;
|
||||
use settings::Settings;
|
||||
|
||||
/// Observability dashboard from terminal output.
|
||||
@@ -48,6 +50,38 @@ async fn main() {
|
||||
|
||||
let (engine_tx, engine_rx) = mpsc::channel(1024);
|
||||
tokio::spawn(engine::run(engine_rx));
|
||||
|
||||
// Ticket 009: reload the active profile's param/metric declarations into the
|
||||
// engine BEFORE starting ingest below. Ordering matters: declarations must be
|
||||
// in place before any line is ingested so that backfill/live-derivation
|
||||
// semantics (ticket 003) apply uniformly to every line, including ones that
|
||||
// arrive immediately once ingest starts (there's no "declare after the fact
|
||||
// and go back to reprocess early lines" step, so doing it after ingest starts
|
||||
// could silently miss lines that raced ahead of the declarations).
|
||||
{
|
||||
let (active_profile_name, profiles_dir) = {
|
||||
let settings_guard = settings.lock().unwrap();
|
||||
(
|
||||
settings_guard.profiles.active_profile.clone(),
|
||||
profile::resolve_profiles_dir(&settings_guard, &settings_path),
|
||||
)
|
||||
};
|
||||
if let Some(profile_name) = active_profile_name {
|
||||
let store = ProfileStore::load(&profile::profiles_store_path(&profiles_dir));
|
||||
match store.get(&profile_name) {
|
||||
Some(active_profile) => {
|
||||
profile::load_into_engine(&engine_tx, active_profile).await;
|
||||
}
|
||||
None => {
|
||||
eprintln!(
|
||||
"warning: active profile '{profile_name}' not found under {}; skipping",
|
||||
profiles_dir.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tokio::spawn(ingest::run(engine_tx.clone()));
|
||||
|
||||
let app = api::router(engine_tx, &args.static_dir, settings, settings_path);
|
||||
|
||||
Reference in New Issue
Block a user