feat: HassLogger
This commit is contained in:
180
src/home_assistant/logger.rs
Normal file
180
src/home_assistant/logger.rs
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
use pyo3::{prelude::*, types::PyTuple};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
arbitrary::{arbitrary::Arbitrary, map::Map},
|
||||||
|
python_utils::{detach, validate_type_by_name},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HassLogger(Py<PyAny>);
|
||||||
|
|
||||||
|
impl<'source> FromPyObject<'source> for HassLogger {
|
||||||
|
fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult<Self> {
|
||||||
|
// region: Validation
|
||||||
|
validate_type_by_name(ob, "HassLogger")?;
|
||||||
|
// endregion: Validation
|
||||||
|
|
||||||
|
Ok(Self(detach(ob)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, IntoPyObject)]
|
||||||
|
pub struct LogData<ExcInfo> {
|
||||||
|
/// If exc_info does not evaluate as false, it causes exception information to be added to the logging message.
|
||||||
|
/// If an exception tuple (in the format returned by sys.exc_info()) or an exception instance is provided, it is used;
|
||||||
|
/// otherwise, sys.exc_info() is called to get the exception information.
|
||||||
|
exc_info: Option<ExcInfo>,
|
||||||
|
|
||||||
|
/// If true, stack information is added to the logging message, including the actual logging call.
|
||||||
|
/// Note that this is not the same stack information as that displayed through specifying exc_info:
|
||||||
|
/// The former is stack frames from the bottom of the stack up to the logging call in the current thread,
|
||||||
|
/// whereas the latter is information about stack frames which have been unwound,
|
||||||
|
/// following an exception, while searching for exception handlers.
|
||||||
|
///
|
||||||
|
/// You can specify stack_info independently of exc_info,
|
||||||
|
/// e.g. to just show how you got to a certain point in your code, even when no exceptions were raised.
|
||||||
|
/// The stack frames are printed following a header line which says:
|
||||||
|
///
|
||||||
|
/// Stack (most recent call last):
|
||||||
|
///
|
||||||
|
/// This mimics the `Traceback (most recent call last):` which is used when displaying exception frames.
|
||||||
|
stack_info: bool,
|
||||||
|
|
||||||
|
/// If greater than 1, the corresponding number of stack frames are skipped
|
||||||
|
/// when computing the line number and function name set in the LogRecord created for the logging event.
|
||||||
|
/// This can be used in logging helpers so that the function name, filename and line number recorded
|
||||||
|
/// are not the information for the helper function/method, but rather its caller.
|
||||||
|
stacklevel: u16,
|
||||||
|
|
||||||
|
/// This can be used to pass a dictionary which is used to populate the __dict__ of the LogRecord
|
||||||
|
/// created for the logging event with user-defined attributes.
|
||||||
|
/// These custom attributes can then be used as you like.
|
||||||
|
/// For example, they could be incorporated into logged messages.
|
||||||
|
extra: Map,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HassLogger {
|
||||||
|
pub fn new(py: Python<'_>, name: &str) -> PyResult<Self> {
|
||||||
|
let logging = py.import("logging")?;
|
||||||
|
let logger = logging.call_method1("getLogger", (name,))?;
|
||||||
|
|
||||||
|
Ok(logger.extract()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn debug<'py, ExcInfo: IntoPyObject<'py>>(
|
||||||
|
&self,
|
||||||
|
py: Python<'py>,
|
||||||
|
msg: &str,
|
||||||
|
args: Vec<Arbitrary>,
|
||||||
|
log_data: Option<LogData<ExcInfo>>,
|
||||||
|
) -> PyResult<()> {
|
||||||
|
let mut all_args = vec![msg.into_pyobject(py)?.into_any()];
|
||||||
|
for arg in args {
|
||||||
|
let arg = arg.into_pyobject(py)?;
|
||||||
|
all_args.push(arg);
|
||||||
|
}
|
||||||
|
let all_args = PyTuple::new(py, all_args)?;
|
||||||
|
|
||||||
|
let kwargs = log_data
|
||||||
|
.map(|log_data| log_data.into_pyobject(py))
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
self.0.call_method(py, "debug", all_args, kwargs.as_ref())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn info<'py, ExcInfo: IntoPyObject<'py>>(
|
||||||
|
&self,
|
||||||
|
py: Python<'py>,
|
||||||
|
msg: &str,
|
||||||
|
args: Vec<Arbitrary>,
|
||||||
|
log_data: Option<LogData<ExcInfo>>,
|
||||||
|
) -> PyResult<()> {
|
||||||
|
let mut all_args = vec![msg.into_pyobject(py)?.into_any()];
|
||||||
|
for arg in args {
|
||||||
|
let arg = arg.into_pyobject(py)?;
|
||||||
|
all_args.push(arg);
|
||||||
|
}
|
||||||
|
let all_args = PyTuple::new(py, all_args)?;
|
||||||
|
|
||||||
|
let kwargs = log_data
|
||||||
|
.map(|log_data| log_data.into_pyobject(py))
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
self.0.call_method(py, "info", all_args, kwargs.as_ref())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn warning<'py, ExcInfo: IntoPyObject<'py>>(
|
||||||
|
&self,
|
||||||
|
py: Python<'py>,
|
||||||
|
msg: &str,
|
||||||
|
args: Vec<Arbitrary>,
|
||||||
|
log_data: Option<LogData<ExcInfo>>,
|
||||||
|
) -> PyResult<()> {
|
||||||
|
let mut all_args = vec![msg.into_pyobject(py)?.into_any()];
|
||||||
|
for arg in args {
|
||||||
|
let arg = arg.into_pyobject(py)?;
|
||||||
|
all_args.push(arg);
|
||||||
|
}
|
||||||
|
let all_args = PyTuple::new(py, all_args)?;
|
||||||
|
|
||||||
|
let kwargs = log_data
|
||||||
|
.map(|log_data| log_data.into_pyobject(py))
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.call_method(py, "warning", all_args, kwargs.as_ref())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error<'py, ExcInfo: IntoPyObject<'py>>(
|
||||||
|
&self,
|
||||||
|
py: Python<'py>,
|
||||||
|
msg: &str,
|
||||||
|
args: Vec<Arbitrary>,
|
||||||
|
log_data: Option<LogData<ExcInfo>>,
|
||||||
|
) -> PyResult<()> {
|
||||||
|
let mut all_args = vec![msg.into_pyobject(py)?.into_any()];
|
||||||
|
for arg in args {
|
||||||
|
let arg = arg.into_pyobject(py)?;
|
||||||
|
all_args.push(arg);
|
||||||
|
}
|
||||||
|
let all_args = PyTuple::new(py, all_args)?;
|
||||||
|
|
||||||
|
let kwargs = log_data
|
||||||
|
.map(|log_data| log_data.into_pyobject(py))
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
self.0.call_method(py, "error", all_args, kwargs.as_ref())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn critical<'py, ExcInfo: IntoPyObject<'py>>(
|
||||||
|
&self,
|
||||||
|
py: Python<'py>,
|
||||||
|
msg: &str,
|
||||||
|
args: Vec<Arbitrary>,
|
||||||
|
log_data: Option<LogData<ExcInfo>>,
|
||||||
|
) -> PyResult<()> {
|
||||||
|
let mut all_args = vec![msg.into_pyobject(py)?.into_any()];
|
||||||
|
for arg in args {
|
||||||
|
let arg = arg.into_pyobject(py)?;
|
||||||
|
all_args.push(arg);
|
||||||
|
}
|
||||||
|
let all_args = PyTuple::new(py, all_args)?;
|
||||||
|
|
||||||
|
let kwargs = log_data
|
||||||
|
.map(|log_data| log_data.into_pyobject(py))
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.call_method(py, "critical", all_args, kwargs.as_ref())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@@ -2,6 +2,7 @@ pub mod domain;
|
|||||||
pub mod entity_id;
|
pub mod entity_id;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
pub mod home_assistant;
|
pub mod home_assistant;
|
||||||
|
pub mod logger;
|
||||||
pub mod object_id;
|
pub mod object_id;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod state_machine;
|
pub mod state_machine;
|
||||||
|
Reference in New Issue
Block a user