Adopt rustfmt and clean up clippy warnings

Formats the whole backend to rustfmt defaults and fixes all 23
outstanding clippy warnings (collapsible ifs, clone-to-slice-ref,
type-complexity, single-arm match, unnecessary is_none check), then
wires cargo fmt --check and -D warnings into make lint so both stay
enforced going forward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TeyhRfMYjMditek6geDRoQ
This commit is contained in:
Hugh Kaznowski
2026-09-07 12:21:38 +01:00
co-authored by Claude Sonnet 5
parent 2cc8ac8138
commit c3108677ce
28 changed files with 4721 additions and 2851 deletions
+45 -11
View File
@@ -12,11 +12,24 @@ use std::collections::HashSet;
pub(super) enum CompiledFilter {
Regex(Regex),
Sequence { op: CompareOp, target: f64 },
Timestamp { op: CompareOp, target_ms: i64 },
Fmt { op: CompareOp, target: String },
Sequence {
op: CompareOp,
target: f64,
},
Timestamp {
op: CompareOp,
target_ms: i64,
},
Fmt {
op: CompareOp,
target: String,
},
MetricMatch(HashSet<u64>),
Json { field: String, op: CompareOp, value: FilterValue },
Json {
field: String,
op: CompareOp,
value: FilterValue,
},
And(Box<CompiledFilter>, Box<CompiledFilter>),
Or(Box<CompiledFilter>, Box<CompiledFilter>),
}
@@ -32,7 +45,11 @@ impl CompiledFilter {
Ok(CompiledFilter::Sequence { op, target })
}
pub(super) fn from_ts_comparison(op: CompareOp, value: &FilterValue, now: Timestamp) -> Result<Self, String> {
pub(super) fn from_ts_comparison(
op: CompareOp,
value: &FilterValue,
now: Timestamp,
) -> Result<Self, String> {
let target_ms = match value {
FilterValue::Number(n) => *n as i64,
FilterValue::Raw(raw) => filter_datetime::parse_datetime(raw, now)
@@ -52,7 +69,12 @@ impl CompiledFilter {
}
impl MetricPrimitive {
pub(super) fn compare(&self, op: CompareOp, value: &FilterValue, now: Timestamp) -> Result<bool, String> {
pub(super) fn compare(
&self,
op: CompareOp,
value: &FilterValue,
now: Timestamp,
) -> Result<bool, String> {
let ordering = match (self, value) {
(MetricPrimitive::Number(n), FilterValue::Number(v)) => n.as_f64().partial_cmp(v),
(MetricPrimitive::Number(n), FilterValue::Raw(raw)) => {
@@ -65,10 +87,13 @@ impl MetricPrimitive {
ts.as_millis().partial_cmp(&(*v as i64))
}
(MetricPrimitive::Timestamp(ts), FilterValue::Raw(raw)) => {
let target = filter_datetime::parse_datetime(raw, now).map_err(|err| err.to_string())?;
let target =
filter_datetime::parse_datetime(raw, now).map_err(|err| err.to_string())?;
ts.as_millis().partial_cmp(&target.as_millis())
}
(MetricPrimitive::String(s), FilterValue::Raw(raw)) => s.as_str().partial_cmp(raw.as_str()),
(MetricPrimitive::String(s), FilterValue::Raw(raw)) => {
s.as_str().partial_cmp(raw.as_str())
}
(MetricPrimitive::String(s), FilterValue::Number(n)) => {
s.as_str().partial_cmp(n.to_string().as_str())
}
@@ -91,7 +116,12 @@ impl MetricPrimitive {
}
}
pub(crate) fn eval_json_comparison(text: &str, field: &str, op: CompareOp, value: &FilterValue) -> bool {
pub(crate) fn eval_json_comparison(
text: &str,
field: &str,
op: CompareOp,
value: &FilterValue,
) -> bool {
let Ok(parsed) = serde_json::from_str::<serde_json::Value>(text) else {
return false;
};
@@ -136,7 +166,9 @@ fn compare_json_value(field_value: &serde_json::Value, op: CompareOp, value: &Fi
Err(_) => false,
}
}
serde_json::Value::Null | serde_json::Value::Array(_) | serde_json::Value::Object(_) => false,
serde_json::Value::Null | serde_json::Value::Array(_) | serde_json::Value::Object(_) => {
false
}
}
}
@@ -167,7 +199,9 @@ impl CompiledFilter {
op.matches(crate::engine::logfmt::detect_format(text).cmp(target.as_str()))
}
CompiledFilter::MetricMatch(sequences) => sequences.contains(&sequence),
CompiledFilter::Json { field, op, value } => eval_json_comparison(text, field, *op, value),
CompiledFilter::Json { field, op, value } => {
eval_json_comparison(text, field, *op, value)
}
CompiledFilter::And(lhs, rhs) => {
lhs.eval(sequence, timestamp, text) && rhs.eval(sequence, timestamp, text)
}
+4 -2
View File
@@ -6,7 +6,10 @@ use crate::engine::data_value::MetricPrimitiveKind;
use crate::engine::metric_primitive::{MetricPrimitive, Number};
use crate::engine::timestamp::Timestamp;
pub(super) fn parse_metric_primitive(raw: &str, kind: MetricPrimitiveKind) -> Option<MetricPrimitive> {
pub(super) fn parse_metric_primitive(
raw: &str,
kind: MetricPrimitiveKind,
) -> Option<MetricPrimitive> {
match kind {
MetricPrimitiveKind::String => Some(MetricPrimitive::String(raw.to_string())),
MetricPrimitiveKind::Number => raw
@@ -24,4 +27,3 @@ pub(super) fn parse_metric_primitive(raw: &str, kind: MetricPrimitiveKind) -> Op
MetricPrimitiveKind::Boolean => raw.parse::<bool>().ok().map(MetricPrimitive::Boolean),
}
}
+413 -199
View File
File diff suppressed because it is too large Load Diff
+20 -7
View File
@@ -1,23 +1,34 @@
//! Param declaration: validating and storing explicit declarations, and the auto-detection
//! logic that derives declarations from logfmt/json/log-stream-shaped lines as they're ingested.
#[cfg(test)]
use crate::engine::DeclareParamRequest;
use crate::engine::data_value::MetricPrimitiveKind;
#[cfg(test)]
use crate::engine::snapshot::EngineSnapshot;
#[cfg(test)]
use crate::engine::DeclareParamRequest;
use regex::Regex;
#[cfg(test)]
pub(crate) fn declare_param(snapshot: &mut EngineSnapshot, request: DeclareParamRequest) -> Result<(), String> {
pub(crate) fn declare_param(
snapshot: &mut EngineSnapshot,
request: DeclareParamRequest,
) -> Result<(), String> {
snapshot.validate_param_declaration(&request)?;
snapshot.insert_param_declaration(request);
Ok(())
}
pub(crate) fn sanitize_group_name(key: &str) -> String {
let mut group: String =
key.chars().map(|c| if c.is_ascii_alphanumeric() || c == '_' { c } else { '_' }).collect();
let mut group: String = key
.chars()
.map(|c| {
if c.is_ascii_alphanumeric() || c == '_' {
c
} else {
'_'
}
})
.collect();
if group.chars().next().is_none_or(|c| c.is_ascii_digit()) {
group.insert(0, '_');
}
@@ -41,7 +52,6 @@ pub(crate) fn build_auto_param_pattern(key: &str, group: &str, quoted: bool) ->
}
}
pub(crate) struct AutoParamCandidate {
pub(crate) name: String,
pub(crate) value: String,
@@ -94,6 +104,9 @@ pub(crate) fn extract_param_raw(
}
match json_field_path.filter(|path| !path.is_empty()) {
Some(field_path) => crate::engine::data_value::extract_json_field(text, field_path),
None => regex.captures(text)?.name(capture_group).map(|m| m.as_str().to_string()),
None => regex
.captures(text)?
.name(capture_group)
.map(|m| m.as_str().to_string()),
}
}
+121 -59
View File
@@ -2,8 +2,8 @@
//! stats, declaration listing, bucket-value listing, and PromQL evaluation.
use crate::api::dto::{
BucketValueDto, LogEntryDto, MetricDeclarationDto, ParamDeclarationDto,
StatsDto, TimelineBucketDto,
BucketValueDto, LogEntryDto, MetricDeclarationDto, ParamDeclarationDto, StatsDto,
TimelineBucketDto,
};
use crate::consts::{DEFAULT_TIMELINE_BUCKET_MS, MERGE_WINDOW_MS};
use crate::engine::data_value::DataValue;
@@ -12,17 +12,17 @@ use crate::engine::message::{EngineQuery, EngineResponse};
use crate::engine::metric_primitive::{MetricPrimitive, Number};
use crate::engine::promql::{LabelMatcher, PromqlQuery};
use crate::engine::rate;
use crate::engine::snapshot::EngineSnapshot;
use crate::engine::snapshot::filter::CompiledFilter;
#[cfg(test)]
use crate::engine::snapshot::sort::SortHelperIndexEntry;
use crate::engine::snapshot::sort::{
log_entry_params, CompiledParamDeclaration, SortHelperAccess, SortHelperKey,
CompiledParamDeclaration, SortHelperAccess, SortHelperKey, log_entry_params,
};
use crate::engine::snapshot::EngineSnapshot;
use crate::engine::timestamp::Timestamp;
use std::collections::BTreeMap;
#[cfg(test)]
use std::collections::HashMap;
use std::collections::BTreeMap;
#[cfg(test)]
pub(crate) fn handle_query(
@@ -30,7 +30,11 @@ pub(crate) fn handle_query(
query: EngineQuery,
sort_helper_indexes: &mut HashMap<String, SortHelperIndexEntry>,
) -> EngineResponse {
handle_query_inner(snapshot, query, SortHelperAccess::Mutable(sort_helper_indexes))
handle_query_inner(
snapshot,
query,
SortHelperAccess::Mutable(sort_helper_indexes),
)
}
/// Compiles `filter` against `snapshot`, or returns `Ok(None)` when there's no filter string
@@ -41,7 +45,9 @@ fn compile_optional_filter(
filter: Option<&str>,
now: Timestamp,
) -> Result<Option<CompiledFilter>, String> {
filter.map(|filter| snapshot.compile_filter_query(filter, now)).transpose()
filter
.map(|filter| snapshot.compile_filter_query(filter, now))
.transpose()
}
/// Walks the sort-helper index for `sort_by` — rather than `snapshot.logs_range()`, which is
@@ -67,7 +73,9 @@ fn logs_sorted_by_param(
let index = &snapshot.index;
static EMPTY_HELPER: std::sync::LazyLock<BTreeMap<SortHelperKey, Timestamp>> =
std::sync::LazyLock::new(BTreeMap::new);
let helper_index = sort_helper_access.resolve(index, sort_by).unwrap_or(&EMPTY_HELPER);
let helper_index = sort_helper_access
.resolve(index, sort_by)
.unwrap_or(&EMPTY_HELPER);
let mut entries = Vec::new();
for (helper_key, timestamp) in helper_index.iter() {
@@ -86,9 +94,10 @@ fn logs_sorted_by_param(
{
continue;
}
let Some(DataValue::LogLiteral { text }) =
index.get(&IndexKey::IngestedLog { sequence, timestamp: *timestamp })
else {
let Some(DataValue::LogLiteral { text }) = index.get(&IndexKey::IngestedLog {
sequence,
timestamp: *timestamp,
}) else {
continue;
};
if !compiled_filter.is_none_or(|filter| filter.eval(sequence, *timestamp, text)) {
@@ -117,14 +126,17 @@ pub(super) fn handle_query_inner(
match query {
EngineQuery::Logs(params) => {
let compiled_filter =
match compile_optional_filter(snapshot, params.filter.as_deref(), Timestamp::now()) {
match compile_optional_filter(snapshot, params.filter.as_deref(), Timestamp::now())
{
Ok(compiled) => compiled,
Err(err) => return EngineResponse::Error(err),
};
if let Some(sort_by) = params.sort_by.as_deref() {
if !snapshot.param_declarations_range().any(|(name, ..)| name == sort_by) {
return EngineResponse::Error(format!("unknown param '{sort_by}' for sort_by"));
}
if let Some(sort_by) = params.sort_by.as_deref()
&& !snapshot
.param_declarations_range()
.any(|(name, ..)| name == sort_by)
{
return EngineResponse::Error(format!("unknown param '{sort_by}' for sort_by"));
}
let limit = params.limit.unwrap_or(500).min(10_000);
let compiled_params = snapshot.compiled_param_declarations();
@@ -135,7 +147,9 @@ pub(super) fn handle_query_inner(
let filtered = snapshot
.logs_in_sequence_range((since_bound, std::ops::Bound::Unbounded))
.filter(|(_, timestamp, _)| {
params.start_ms.is_none_or(|start| timestamp.as_millis() >= start)
params
.start_ms
.is_none_or(|start| timestamp.as_millis() >= start)
&& params.end_ms.is_none_or(|end| timestamp.as_millis() <= end)
})
.filter(|(sequence, timestamp, text)| {
@@ -172,14 +186,20 @@ pub(super) fn handle_query_inner(
}
EngineQuery::Timeline(params) => {
let compiled_filter =
match compile_optional_filter(snapshot, params.filter.as_deref(), Timestamp::now()) {
match compile_optional_filter(snapshot, params.filter.as_deref(), Timestamp::now())
{
Ok(compiled) => compiled,
Err(err) => return EngineResponse::Error(err),
};
let bucket_ms = params.bucket_ms.unwrap_or(DEFAULT_TIMELINE_BUCKET_MS).max(1);
let bucket_ms = params
.bucket_ms
.unwrap_or(DEFAULT_TIMELINE_BUCKET_MS)
.max(1);
let mut buckets: BTreeMap<i64, u64> = BTreeMap::new();
for (sequence, timestamp, text) in snapshot.logs_range().filter(|(_, timestamp, _)| {
params.start_ms.is_none_or(|start| timestamp.as_millis() >= start)
params
.start_ms
.is_none_or(|start| timestamp.as_millis() >= start)
&& params.end_ms.is_none_or(|end| timestamp.as_millis() <= end)
}) {
if compiled_filter
@@ -221,34 +241,56 @@ pub(super) fn handle_query_inner(
})
}
EngineQuery::ParamDeclarations => {
let declarations = snapshot.param_declarations_range()
.map(|(name, message_match_regex, capture_group, json_field_path, kind, elapsed_since_last, auto_derived, _)| {
ParamDeclarationDto {
name: name.to_string(),
message_match_regex: message_match_regex.to_string(),
capture_group: capture_group.to_string(),
json_field_path: json_field_path.map(|path| path.to_string()),
let declarations = snapshot
.param_declarations_range()
.map(
|(
name,
message_match_regex,
capture_group,
json_field_path,
kind,
elapsed_since_last,
auto_derived,
reserved: false,
}
})
_,
)| {
ParamDeclarationDto {
name: name.to_string(),
message_match_regex: message_match_regex.to_string(),
capture_group: capture_group.to_string(),
json_field_path: json_field_path.map(|path| path.to_string()),
kind,
elapsed_since_last,
auto_derived,
reserved: false,
}
},
)
.collect();
EngineResponse::ParamDeclarations(declarations)
}
EngineQuery::MetricDeclarations => {
let declarations = snapshot.metric_declarations_range()
.map(|(name, message_match_regex, label_params, value_param, matched_labels, unmatched_labels)| {
MetricDeclarationDto {
name: name.to_string(),
message_match_regex: message_match_regex.to_string(),
label_params: label_params.to_vec(),
value_param: value_param.map(|s| s.to_string()),
matched_labels: matched_labels.cloned(),
unmatched_labels: unmatched_labels.cloned(),
}
})
let declarations = snapshot
.metric_declarations_range()
.map(
|(
name,
message_match_regex,
label_params,
value_param,
matched_labels,
unmatched_labels,
)| {
MetricDeclarationDto {
name: name.to_string(),
message_match_regex: message_match_regex.to_string(),
label_params: label_params.to_vec(),
value_param: value_param.map(|s| s.to_string()),
matched_labels: matched_labels.cloned(),
unmatched_labels: unmatched_labels.cloned(),
}
},
)
.collect();
EngineResponse::MetricDeclarations(declarations)
}
@@ -261,7 +303,8 @@ pub(super) fn handle_query_inner(
limit,
} => {
let limit = limit.unwrap_or(500).min(10_000);
let values: Vec<BucketValueDto> = snapshot.bucket_values(&metric_name, None)
let values: Vec<BucketValueDto> = snapshot
.bucket_values(&metric_name, None)
.filter(|(labels, _)| {
labels_filter.as_ref().is_none_or(|filter| {
filter.iter().all(|(name, expected)| {
@@ -286,7 +329,11 @@ pub(super) fn handle_query_inner(
.collect();
EngineResponse::BucketValues(values)
}
EngineQuery::Promql { query, start_ms, end_ms } => {
EngineQuery::Promql {
query,
start_ms,
end_ms,
} => {
let response = PromqlQuery::parse(&query)
.and_then(|parsed| snapshot.evaluate_promql(&parsed, start_ms, end_ms));
EngineResponse::Promql(response)
@@ -318,7 +365,9 @@ pub(crate) fn matches_label_matchers(
matchers: &[LabelMatcher],
) -> bool {
matchers.iter().all(|matcher| {
labels.get(&matcher.name).is_some_and(|value| value.to_string() == matcher.value)
labels
.get(&matcher.name)
.is_some_and(|value| value.to_string() == matcher.value)
})
}
@@ -338,29 +387,34 @@ pub(crate) fn windowed_rate_series(
start_ms: Option<i64>,
end_ms: Option<i64>,
) -> Vec<(i64, f64)> {
let ts_points: Vec<(Timestamp, f64)> =
points.iter().map(|(ms, value)| (Timestamp::from_millis(*ms), *value)).collect();
let ts_points: Vec<(Timestamp, f64)> = points
.iter()
.map(|(ms, value)| (Timestamp::from_millis(*ms), *value))
.collect();
let mut series: Vec<(i64, f64)> = rate::windowed_rate_series(&ts_points, range_ms)
.into_iter()
.map(|(ts, value)| (ts.as_millis(), value))
.collect();
if let Some(end) = end_ms {
if series.last().is_none_or(|(ts, _)| *ts < end) {
let value = rate::rate_at(&ts_points, Timestamp::from_millis(end), range_ms);
series.push((end, value));
}
if let Some(end) = end_ms
&& series.last().is_none_or(|(ts, _)| *ts < end)
{
let value = rate::rate_at(&ts_points, Timestamp::from_millis(end), range_ms);
series.push((end, value));
}
if let Some(start) = start_ms {
if series.first().is_none_or(|(ts, _)| *ts > start) {
let value = rate::rate_at(&ts_points, Timestamp::from_millis(start), range_ms);
series.insert(0, (start, value));
}
if let Some(start) = start_ms
&& series.first().is_none_or(|(ts, _)| *ts > start)
{
let value = rate::rate_at(&ts_points, Timestamp::from_millis(start), range_ms);
series.insert(0, (start, value));
}
series
}
pub(crate) fn merge_series_windowed(sub_series: &[Vec<(i64, f64)>], is_avg: bool) -> Vec<(i64, f64)> {
pub(crate) fn merge_series_windowed(
sub_series: &[Vec<(i64, f64)>],
is_avg: bool,
) -> Vec<(i64, f64)> {
if sub_series.len() <= 1 {
return sub_series.first().cloned().unwrap_or_default();
}
@@ -375,7 +429,11 @@ pub(crate) fn merge_series_windowed(sub_series: &[Vec<(i64, f64)>], is_avg: bool
.into_iter()
.map(|(timestamp_ms, values)| {
let sum: f64 = values.iter().sum();
let value = if is_avg { sum / values.len() as f64 } else { sum };
let value = if is_avg {
sum / values.len() as f64
} else {
sum
};
(timestamp_ms, value)
})
.collect()
@@ -398,7 +456,11 @@ pub(crate) fn merge_series_locf(sub_series: &[Vec<(i64, f64)>], is_avg: bool) ->
}
}
let sum: f64 = last_values.iter().sum();
let value = if is_avg { sum / last_values.len() as f64 } else { sum };
let value = if is_avg {
sum / last_values.len() as f64
} else {
sum
};
(ts, value)
})
.collect()
+37 -13
View File
@@ -4,12 +4,12 @@
//! kept incrementally up to date on ingest, rather than rebuilt per query.
use crate::engine::data_value::DataValue;
use crate::engine::index_key::IndexKey;
use crate::engine::data_value::MetricPrimitiveKind;
use crate::engine::index_key::IndexKey;
use crate::engine::metric_primitive::MetricPrimitive;
use crate::engine::snapshot::metrics::parse_metric_primitive;
#[cfg(test)]
use crate::engine::snapshot::EngineSnapshot;
use crate::engine::snapshot::metrics::parse_metric_primitive;
use crate::engine::timestamp::Timestamp;
use regex::Regex;
use std::collections::{BTreeMap, HashMap};
@@ -26,7 +26,14 @@ pub(crate) struct SortHelperIndexEntry {
pub(crate) last_accessed: std::time::Instant,
}
pub(super) type CompiledParamDeclaration = (String, Regex, String, Option<String>, MetricPrimitiveKind, bool);
pub(super) type CompiledParamDeclaration = (
String,
Regex,
String,
Option<String>,
MetricPrimitiveKind,
bool,
);
pub(crate) fn derive_single_param(
text: &str,
@@ -49,7 +56,10 @@ pub(crate) fn derive_single_param(
parse_metric_primitive(&raw, *kind)
}
pub(crate) fn derive_log_params(text: &str, declarations: &[CompiledParamDeclaration]) -> BTreeMap<String, MetricPrimitive> {
pub(crate) fn derive_log_params(
text: &str,
declarations: &[CompiledParamDeclaration],
) -> BTreeMap<String, MetricPrimitive> {
let mut params = BTreeMap::new();
for (name, regex, capture_group, json_field_path, kind, log_stream_gated) in declarations {
if *log_stream_gated && !crate::engine::logfmt::is_log_stream_line(text) {
@@ -63,10 +73,12 @@ pub(crate) fn derive_log_params(text: &str, declarations: &[CompiledParamDeclara
continue;
};
let raw: String = match json_field_path.as_deref().filter(|path| !path.is_empty()) {
Some(field_path) => match crate::engine::data_value::extract_json_field(text, field_path) {
Some(value) => value,
None => continue,
},
Some(field_path) => {
match crate::engine::data_value::extract_json_field(text, field_path) {
Some(value) => value,
None => continue,
}
}
None => match captures.name(capture_group) {
Some(m) => m.as_str().to_string(),
None => continue,
@@ -80,9 +92,15 @@ pub(crate) fn derive_log_params(text: &str, declarations: &[CompiledParamDeclara
params
}
pub(super) fn log_entry_params(text: &str, declarations: &[CompiledParamDeclaration]) -> BTreeMap<String, MetricPrimitive> {
pub(super) fn log_entry_params(
text: &str,
declarations: &[CompiledParamDeclaration],
) -> BTreeMap<String, MetricPrimitive> {
let mut params = derive_log_params(text, declarations);
params.insert("ottyl_fmt".to_string(), MetricPrimitive::String(crate::engine::logfmt::detect_format(text).to_string()));
params.insert(
"ottyl_fmt".to_string(),
MetricPrimitive::String(crate::engine::logfmt::detect_format(text).to_string()),
);
params
}
@@ -103,13 +121,19 @@ impl<'a> SortHelperAccess<'a> {
#[cfg(test)]
SortHelperAccess::Mutable(map) => {
if !map.contains_key(sort_by) {
let built = EngineSnapshot::from_index(index.clone()).build_sort_helper_index(sort_by);
let built =
EngineSnapshot::from_index(index.clone()).build_sort_helper_index(sort_by);
map.insert(
sort_by.to_string(),
SortHelperIndexEntry { index: built, last_accessed: std::time::Instant::now() },
SortHelperIndexEntry {
index: built,
last_accessed: std::time::Instant::now(),
},
);
}
let entry = map.get_mut(sort_by).expect("just inserted above if missing");
let entry = map
.get_mut(sort_by)
.expect("just inserted above if missing");
entry.last_accessed = std::time::Instant::now();
map.get(sort_by).map(|entry| &entry.index)
}