Skip to content

Commit 0d824c1

Browse files
committed
Refactor logging and improve error handling in CEL execution
1 parent bd72e64 commit 0d824c1

File tree

3 files changed

+27
-37
lines changed

3 files changed

+27
-37
lines changed

Cargo.lock

Lines changed: 12 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ name = "cel"
99
crate-type = ["cdylib"]
1010

1111
[dependencies]
12-
pyo3 = { version = "0.25.1", features = ["chrono", "py-clone"]}
12+
pyo3 = { version = "0.27", features = ["chrono", "py-clone"]}
1313
cel = { version = "0.11.6", features = ["chrono", "json", "regex"] }
1414
log = "0.4.27"
15-
pyo3-log = "0.12.4"
15+
pyo3-log = { git = "https://github.com/a1phyr/pyo3-log.git", branch = "pyo3_0.27" }
1616
chrono = { version = "0.4.42", features = ["serde"] }

src/lib.rs

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ mod context;
22

33
use ::cel::objects::{Key, TryIntoValue};
44
use ::cel::{Context as CelContext, ExecutionError, Program, Value};
5-
use log::debug;
5+
use log::warn;
66
use pyo3::exceptions::{PyRuntimeError, PyTypeError, PyValueError};
77
use pyo3::prelude::*;
88
use pyo3::BoundObject;
@@ -32,10 +32,7 @@ impl<'py> IntoPyObject<'py> for RustyCelType {
3232
RustyCelType(Value::Int(i64)) => i64.into_pyobject(py)?.into_any(),
3333
RustyCelType(Value::UInt(u64)) => u64.into_pyobject(py)?.into_any(),
3434
RustyCelType(Value::Float(f)) => f.into_pyobject(py)?.into_any(),
35-
RustyCelType(Value::Timestamp(ts)) => {
36-
debug!("Converting a fixed offset datetime to python type");
37-
ts.into_pyobject(py)?.into_any()
38-
}
35+
RustyCelType(Value::Timestamp(ts)) => ts.into_pyobject(py)?.into_any(),
3936
RustyCelType(Value::Duration(d)) => d.into_pyobject(py)?.into_any(),
4037
RustyCelType(Value::String(s)) => s.as_ref().to_string().into_pyobject(py)?.into_any(),
4138
RustyCelType(Value::List(val)) => {
@@ -200,19 +197,19 @@ impl TryIntoValue for RustyPyType<'_> {
200197
Ok(Value::Duration(value))
201198
} else if let Ok(value) = pyobject.extract::<String>() {
202199
Ok(Value::String(value.into()))
203-
} else if let Ok(value) = pyobject.downcast::<PyList>() {
200+
} else if let Ok(value) = pyobject.cast::<PyList>() {
204201
let list = value
205202
.iter()
206203
.map(|item| RustyPyType(&item).try_into_value())
207204
.collect::<Result<Vec<Value>, Self::Error>>();
208205
list.map(|v| Value::List(Arc::new(v)))
209-
} else if let Ok(value) = pyobject.downcast::<PyTuple>() {
206+
} else if let Ok(value) = pyobject.cast::<PyTuple>() {
210207
let list = value
211208
.iter()
212209
.map(|item| RustyPyType(&item).try_into_value())
213210
.collect::<Result<Vec<Value>, Self::Error>>();
214211
list.map(|v| Value::List(Arc::new(v)))
215-
} else if let Ok(value) = pyobject.downcast::<PyDict>() {
212+
} else if let Ok(value) = pyobject.cast::<PyDict>() {
216213
let mut map: HashMap<Key, Value> = HashMap::new();
217214
for (key, value) in value.into_iter() {
218215
let key = if key.is_none() {
@@ -407,7 +404,7 @@ fn evaluate(src: String, evaluation_context: Option<&Bound<'_, PyAny>>) -> PyRes
407404
// Clone variables and functions into our local Context
408405
ctx.variables = py_context_ref.variables.clone();
409406
ctx.functions = py_context_ref.functions.clone();
410-
} else if let Ok(py_dict) = evaluation_context.downcast::<PyDict>() {
407+
} else if let Ok(py_dict) = evaluation_context.cast::<PyDict>() {
411408
// User passed in a dict - let's process variables and functions from the dict
412409
ctx.update(py_dict)?;
413410
} else {
@@ -419,12 +416,10 @@ fn evaluate(src: String, evaluation_context: Option<&Bound<'_, PyAny>>) -> PyRes
419416
variables_for_env = ctx.variables.clone();
420417
}
421418

422-
// Strict mode only - preserve original expression without any preprocessing
423-
let processed_src = src.clone();
424-
425419
// Use panic::catch_unwind to handle parser panics gracefully
426-
let program = panic::catch_unwind(|| Program::compile(&processed_src))
420+
let program = panic::catch_unwind(|| Program::compile(&src))
427421
.map_err(|_| {
422+
warn!("CEL parser panic for expression: '{}'", src);
428423
PyValueError::new_err(format!(
429424
"Failed to parse expression '{src}': Invalid syntax or malformed string"
430425
))
@@ -445,7 +440,7 @@ fn evaluate(src: String, evaluation_context: Option<&Bound<'_, PyAny>>) -> PyRes
445440
// Register Python functions
446441
for (function_name, py_function) in ctx.functions.iter() {
447442
// Create a wrapper function
448-
let py_func_clone = Python::with_gil(|py| py_function.clone_ref(py));
443+
let py_func_clone = Python::attach(|py| py_function.clone_ref(py));
449444
let func_name_clone = function_name.clone();
450445

451446
// Register a function that takes Arguments (variadic) and returns a Value
@@ -455,7 +450,7 @@ fn evaluate(src: String, evaluation_context: Option<&Bound<'_, PyAny>>) -> PyRes
455450
let py_func = py_func_clone.clone();
456451
let func_name = func_name_clone.clone();
457452

458-
Python::with_gil(|py| {
453+
Python::attach(|py| {
459454
// Convert CEL arguments to Python objects
460455
let mut py_args = Vec::new();
461456
for cel_value in args.0.iter() {
@@ -479,6 +474,7 @@ fn evaluate(src: String, evaluation_context: Option<&Bound<'_, PyAny>>) -> PyRes
479474

480475
// Call the Python function
481476
let py_result = py_func.call1(py, py_args_tuple).map_err(|e| {
477+
warn!("Python function '{}' failed: {}", func_name, e);
482478
ExecutionError::FunctionError {
483479
function: func_name.clone(),
484480
message: format!("Python function call failed: {e}"),
@@ -508,18 +504,14 @@ fn evaluate(src: String, evaluation_context: Option<&Bound<'_, PyAny>>) -> PyRes
508504
// AssertUnwindSafe is needed because the environment contains function closures
509505
let result =
510506
panic::catch_unwind(AssertUnwindSafe(|| program.execute(&environment))).map_err(|_| {
507+
warn!("CEL execution panic for expression: '{}'", src);
511508
PyValueError::new_err(format!(
512509
"Failed to execute expression '{src}': Internal parser error"
513510
))
514511
})?;
515512

516513
match result {
517-
Err(error) => {
518-
debug!("An error occurred during execution");
519-
debug!("Execution error: {error:?}");
520-
Err(map_execution_error_to_python(&error))
521-
}
522-
514+
Err(error) => Err(map_execution_error_to_python(&error)),
523515
Ok(value) => Ok(RustyCelType(value)),
524516
}
525517
}

0 commit comments

Comments
 (0)