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:
co-authored by
Claude Sonnet 5
parent
2cc8ac8138
commit
c3108677ce
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user