ensure_default now seeds a brand-new Default profile (not one that already existed) with a "log_category" counter metric and an "Overview" dashboard containing a line and a pie panel, both querying that metric so each renders both series from a single PromQL query like any user-created panel. The counter classifies every line into exactly "category=error" or "category=other" via two new fixed-label fields on metric declarations: DeclareMetricRequest::matched_labels/unmatched_labels. These apply literal label values instead of parsing captured text, which is what keeps a case-insensitive match (e.g. "ERROR" vs "Error") collapsed into one clean series instead of fragmenting by source casing, and is also the only way to express the "line does NOT match" side at all: plain regex alternation can't do it without lookaround, which the `regex` crate doesn't support (a catch-all alternation branch always wins at the search's leftmost position). Both fields default to None and are backward compatible with existing profiles. Seeded panels are ordinary editable/deletable dashboard state, persisted through the normal profile save path; ensure_default never re-seeds or duplicates them on a later call once the profile exists. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
82 lines
3.1 KiB
Rust
82 lines
3.1 KiB
Rust
use crate::metric_primitive::MetricPrimitive;
|
|
use crate::timestamp::Timestamp;
|
|
use serde::{Deserialize, Serialize};
|
|
use std::collections::BTreeMap;
|
|
|
|
/// A single parsed metric primitive extracted from a regex capture group.
|
|
#[allow(dead_code)]
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct RegexToMetricPrimitiveMatcher {
|
|
pub param_name: String,
|
|
pub capture_group: String,
|
|
pub kind: MetricPrimitiveKind,
|
|
/// Ticket 022: whether this param contributes to the bucket's `labels`
|
|
/// (the default) or is the bucket's per-event captured `value` (at most
|
|
/// one `Value`-role param per metric — `declare_metric` rejects more
|
|
/// than one). `#[serde(default)]` so profile files saved before this
|
|
/// field existed still load, with every param defaulting to `Label` —
|
|
/// i.e. unchanged behavior (the fixed occurrence-count-of-1 value).
|
|
#[serde(default)]
|
|
pub role: ParamRole,
|
|
}
|
|
|
|
/// See [`RegexToMetricPrimitiveMatcher::role`].
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum ParamRole {
|
|
#[default]
|
|
Label,
|
|
Value,
|
|
}
|
|
|
|
/// `rename_all = "lowercase"` matches every other `kind`-style enum exposed
|
|
/// over the API/settings JSON (`ColorScheme`, `CssEntryKind`,
|
|
/// `ProfileMetricPrimitiveKind`), so `POST /api/params`/`POST /api/metrics`
|
|
/// bodies use `"string"`/`"number"`/`"timestamp"`.
|
|
#[allow(dead_code)]
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum MetricPrimitiveKind {
|
|
String,
|
|
Number,
|
|
Timestamp,
|
|
/// Ticket 023: milliseconds. On a metric's `Value`-role param, this
|
|
/// doesn't parse the captured text at all — the value is instead derived
|
|
/// as the elapsed time since the previous counter event with the same
|
|
/// label set (see `crate::engine::apply_metric_to_log`). On any other
|
|
/// param (a `Label`-role metric param, or a standalone `ParamDeclaration`),
|
|
/// it parses the captured text as a literal `i64` millisecond count.
|
|
Duration,
|
|
}
|
|
|
|
/// Value type paired with [`crate::index_key::IndexKey`] in the engine's primary index.
|
|
#[allow(dead_code)]
|
|
#[derive(Debug, Clone, Serialize)]
|
|
pub enum DataValue {
|
|
/// Paired with `IndexKey::IngestedLog`.
|
|
LogLiteral { text: String },
|
|
/// Paired with `IndexKey::ParamDeclaration`.
|
|
ParamDeclaration {
|
|
message_match_regex: String,
|
|
capture_group: String,
|
|
kind: MetricPrimitiveKind,
|
|
},
|
|
/// Paired with `IndexKey::MetricDeclaration`.
|
|
MetricDeclaration {
|
|
message_match_regex: String,
|
|
params: Vec<RegexToMetricPrimitiveMatcher>,
|
|
/// See `crate::engine::DeclareMetricRequest::matched_labels` (ticket 025).
|
|
matched_labels: Option<BTreeMap<String, String>>,
|
|
/// See `crate::engine::DeclareMetricRequest::unmatched_labels` (ticket 025).
|
|
unmatched_labels: Option<BTreeMap<String, String>>,
|
|
},
|
|
/// Paired with `IndexKey::Bucket`.
|
|
BucketValue {
|
|
values: Vec<(u64, Timestamp, MetricPrimitive)>,
|
|
},
|
|
/// Paired with `IndexKey::LastMetricEvent` (ticket 023).
|
|
LastEventTimestamp {
|
|
timestamp: Timestamp,
|
|
},
|
|
}
|