use super::*;
use crate::v2_operator::{V2OperatorTrace, operator};
#[allow(clippy::too_many_arguments)]
pub(super) fn eval_v2_step_traced<'a>(
step: &V2Step,
pipe_value: V2EvalValue,
record: &'a JsonValue,
context: Option<&'a JsonValue>,
out: &'a JsonValue,
step_path: &str,
ctx: &V2EvalContext<'a>,
collector: &mut TraceCollector,
) -> Result<(V2EvalValue, V2EvalContext<'a>), TransformError> {
match step {
V2Step::Op(op) => {
collector
.start_span(TraceEventKind::OpStart, TracePhase::Start)
.rule_path(step_path)
.operator(&op.op)
.input_v2_eval_value(&pipe_value, collector.options(), None)
.attr_count("arg_count", op.args.len())
.finish(collector);
let operator_metadata = operator(&op.op);
let trace = operator_metadata
.map(|metadata| metadata.trace)
.unwrap_or(V2OperatorTrace::EagerArgs);
let result = match trace {
V2OperatorTrace::ItemLevelCollection => eval_v2_collection_op_traced(
op,
pipe_value.clone(),
record,
context,
out,
step_path,
ctx,
collector,
),
V2OperatorTrace::EagerArgs => eval_v2_eager_op_traced(
op,
pipe_value.clone(),
record,
context,
out,
step_path,
ctx,
operator_metadata,
collector,
),
V2OperatorTrace::LazyShortCircuit => eval_v2_lazy_op_traced(
op,
pipe_value.clone(),
record,
context,
out,
step_path,
ctx,
collector,
),
V2OperatorTrace::Delegated => {
eval_v2_op_step(op, pipe_value.clone(), record, context, out, step_path, ctx)
}
};
let output = match result {
Ok(output) => output,
Err(error) => {
collector
.error_span(TraceEventKind::OpError, "OP_ERROR", "operator failed")
.rule_path(step_path)
.operator(&op.op)
.input_v2_eval_value(&pipe_value, collector.options(), None)
.finish(collector);
return Err(error);
}
};
collector
.end_span(TraceEventKind::OpEnd, TracePhase::End)
.rule_path(step_path)
.operator(&op.op)
.input_v2_eval_value(&pipe_value, collector.options(), None)
.finish_with_v2_eval_output(collector, &output, None);
Ok((output, ctx.clone()))
}
V2Step::Map(map) => eval_v2_map_step_traced(
map, pipe_value, record, context, out, step_path, ctx, collector,
),
V2Step::Let(let_step) => {
let new_ctx = eval_v2_let_step(
let_step,
pipe_value.clone(),
record,
context,
out,
step_path,
ctx,
)?;
collector
.emit(TraceEventKind::ChainStep, TracePhase::Instant)
.rule_path(step_path)
.input_v2_eval_value(&pipe_value, collector.options(), None)
.finish(collector);
let output = new_ctx.get_pipe_value().cloned().unwrap_or(pipe_value);
Ok((output, new_ctx))
}
V2Step::If(if_step) => {
let cond_ctx = ctx.clone().with_pipe_value(pipe_value.clone());
let cond_path = format!("{}.cond", step_path);
let cond = eval_v2_condition_traced(
&if_step.cond,
record,
context,
out,
&cond_path,
&cond_ctx,
collector,
)?;
collector
.emit(TraceEventKind::BranchEval, TracePhase::Instant)
.rule_path(&cond_path)
.finish_with_output(collector, &JsonValue::Bool(cond), None);
if cond {
collector
.start_span(TraceEventKind::BranchTaken, TracePhase::Start)
.rule_path(step_path)
.attr_enum("selected_branch", "then")
.finish(collector);
let result = eval_v2_pipe_traced(
&if_step.then_branch,
record,
context,
out,
&format!("{}.then", step_path),
&cond_ctx,
collector,
)?;
collector
.end_span(TraceEventKind::BranchTaken, TracePhase::End)
.rule_path(step_path)
.finish_with_v2_eval_output(collector, &result, None);
Ok((result, ctx.clone()))
} else if let Some(else_branch) = &if_step.else_branch {
collector
.start_span(TraceEventKind::BranchTaken, TracePhase::Start)
.rule_path(step_path)
.attr_enum("selected_branch", "else")
.finish(collector);
let result = eval_v2_pipe_traced(
else_branch,
record,
context,
out,
&format!("{}.else", step_path),
&cond_ctx,
collector,
)?;
collector
.end_span(TraceEventKind::BranchTaken, TracePhase::End)
.rule_path(step_path)
.finish_with_v2_eval_output(collector, &result, None);
Ok((result, ctx.clone()))
} else {
Ok((pipe_value, ctx.clone()))
}
}
V2Step::Ref(v2_ref) => {
let result = eval_v2_ref(v2_ref, record, context, out, step_path, ctx)?;
let mut event = collector
.emit(TraceEventKind::RefRead, TracePhase::Instant)
.rule_path(step_path);
if let Some(path) = canonical_v2_ref_path(v2_ref) {
event = event.input_path(path);
}
event.finish_with_v2_eval_output(collector, &result, None);
Ok((result, ctx.clone()))
}
}
}