use crate::engine::error::Result;
use crate::engine::message::{Change, Message};
use datalogic_rs::{CompiledLogic, DataLogic};
use log::{debug, error, info, trace, warn};
use serde::Deserialize;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum LogLevel {
Trace,
Debug,
#[default]
Info,
Warn,
Error,
}
#[derive(Debug, Clone, Deserialize)]
pub struct LogConfig {
#[serde(default)]
pub level: LogLevel,
pub message: Value,
#[serde(default)]
pub fields: HashMap<String, Value>,
#[serde(skip)]
pub message_index: Option<usize>,
#[serde(skip)]
pub field_indices: Vec<(String, Option<usize>)>,
}
impl LogConfig {
pub fn execute(
&self,
message: &mut Message,
datalogic: &Arc<DataLogic>,
logic_cache: &[Arc<CompiledLogic>],
) -> Result<(usize, Vec<Change>)> {
let context_arc = message.get_context_arc();
let log_message = match self.message_index {
Some(idx) if idx < logic_cache.len() => {
match datalogic.evaluate(&logic_cache[idx], Arc::clone(&context_arc)) {
Ok(Value::String(s)) => s,
Ok(other) => other.to_string(),
Err(e) => {
error!("Log: Failed to evaluate message expression: {:?}", e);
"<message eval error>".to_string()
}
}
}
_ => "<uncompiled message>".to_string(),
};
let mut field_parts = Vec::new();
for (key, idx_opt) in &self.field_indices {
let val = match idx_opt {
Some(idx) if *idx < logic_cache.len() => {
match datalogic.evaluate(&logic_cache[*idx], Arc::clone(&context_arc)) {
Ok(Value::String(s)) => s,
Ok(v) => v.to_string(),
Err(_) => "<eval error>".to_string(),
}
}
_ => "<uncompiled>".to_string(),
};
field_parts.push(format!("{}={}", key, val));
}
let full_message = if field_parts.is_empty() {
log_message
} else {
format!("{} [{}]", log_message, field_parts.join(", "))
};
match self.level {
LogLevel::Trace => trace!(target: "dataflow::log", "{}", full_message),
LogLevel::Debug => debug!(target: "dataflow::log", "{}", full_message),
LogLevel::Info => info!(target: "dataflow::log", "{}", full_message),
LogLevel::Warn => warn!(target: "dataflow::log", "{}", full_message),
LogLevel::Error => error!(target: "dataflow::log", "{}", full_message),
}
Ok((200, vec![]))
}
}