Skip to content

Commit

Permalink
Merge commit '4164b16f2b0d0b7998af69757ac83bcfa013cd11'
Browse files Browse the repository at this point in the history
  • Loading branch information
Tibor Benke committed Jun 3, 2016
2 parents 1e17ad6 + 4164b16 commit 13b69c0
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 2 deletions.
8 changes: 8 additions & 0 deletions python-parser/_test_module/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,11 @@ class ExceptionIsRaisedInInitMethod:
def init(self, options):
raise TypeError("text")
return True

class LoggingIsUsedInInitMethod:
def init(self, options):
info("INFO")
warning("WARNING")
trace("TRACE")
error("ERROR")
debug("DEBUG")
13 changes: 13 additions & 0 deletions python-parser/_test_module/test_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
def info(msg): pass
def trace(msg): pass
def warning(msg): pass
def error(msg): pass
def debug(msg): pass

class LoggingCallbacksAreNotOverriden:
def init(self, options):
info("INFO")
warning("WARNING")
trace("TRACE")
error("ERROR")
debug("DEBUG")
51 changes: 49 additions & 2 deletions python-parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::borrow::Borrow;
use std::marker::PhantomData;

use syslog_ng_common::{LogMessage, Parser, ParserBuilder, OptionError, Pipe, GlobalConfig};
use cpython::{Python, PyDict, NoArgs, PyClone, PyObject, PyResult, PyModule, PyErr, PyString};
use cpython::{Python, PyDict, NoArgs, PyClone, PyObject, PyResult, PyModule, PyErr, PyString, ToPyObject};
use cpython::ObjectProtocol; //for call method
use cpython::exc::TypeError;

Expand Down Expand Up @@ -92,11 +92,58 @@ impl<P: Pipe> PythonParserBuilder<P> {

pub fn load_and_init_class<'p>(py: Python<'p>, module_name: &str, class_name: &str, options: &[(String, String)]) -> PyResult<PyObject> {
let module = try!(Self::load_module(py, module_name));
let mut dict = module.dict(py);

try!(python_register_callbacks(py, &mut dict));

let class = try!(Self::load_class(py, &module, class_name));
Self::initialize_class(py, &class, options)
}
}

fn python_register_callbacks(py: Python, dict: &mut PyDict) -> PyResult<()> {
try!(python_register_callback(py, dict, "error", py_fn!(python_error_callback(error_message: &str))));
try!(python_register_callback(py, dict, "info", py_fn!(python_info_callback(info_message: &str))));
try!(python_register_callback(py, dict, "trace", py_fn!(python_trace_callback(trace_message: &str))));
try!(python_register_callback(py, dict, "warning", py_fn!(python_warning_callback(warning_message: &str))));
try!(python_register_callback(py, dict, "debug", py_fn!(python_debug_callback(debug_message: &str))));
Ok(())
}

fn python_register_callback<F: ToPyObject>(py: Python, dict: &mut PyDict, name: &str, function: F) -> PyResult<()> {
if try!(dict.contains(py, name)) {
warn!("Already implemented {}() function, omitting callback definition.", name);
} else {
try!(dict.set_item(py, name, function));
}
Ok(())
}

fn python_error_callback(_: Python, error_message: &str) -> PyResult<NoArgs> {
error!("{}", error_message);
Ok(NoArgs)
}

fn python_info_callback(_: Python, info_message: &str) -> PyResult<NoArgs> {
info!("{}", info_message);
Ok(NoArgs)
}

fn python_trace_callback(_: Python, trace_message: &str) -> PyResult<NoArgs> {
trace!("{}", trace_message);
Ok(NoArgs)
}

fn python_warning_callback(_: Python, warning_message: &str) -> PyResult<NoArgs> {
warn!("{}", warning_message);
Ok(NoArgs)
}

fn python_debug_callback(_: Python, debug_message: &str) -> PyResult<NoArgs> {
debug!("{}", debug_message);
Ok(NoArgs)
}

impl<P: Pipe> ParserBuilder<P> for PythonParserBuilder<P> {
type Parser = PythonParser<P>;
fn new(_: GlobalConfig) -> Self {
Expand Down Expand Up @@ -126,7 +173,7 @@ impl<P: Pipe> ParserBuilder<P> for PythonParserBuilder<P> {
Ok(PythonParser {parser: parser_instance, _marker: PhantomData})
},
Err(error) => {
error!("Failed to create Python parser, class='{}'", class_name);
error!("Failed to create Python parser, class='{}', error='{:?}'", class_name, error);
Err(OptionError::verbatim_error(format!("{:?}", error)))
}
}
Expand Down
117 changes: 117 additions & 0 deletions python-parser/tests/logging.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
extern crate python_parser;
extern crate syslog_ng_common;
extern crate cpython;
extern crate log;

use std::env;
use python_parser::{options, PythonParserBuilder};
use syslog_ng_common::{ParserBuilder, SYSLOG_NG_INITIALIZED, syslog_ng_global_init, GlobalConfig};
use syslog_ng_common::mock::MockPipe;
use log::{LogRecord, LogLevel, LogMetadata};

use std::sync::Arc;
use std::sync::Mutex;

#[derive(Eq, PartialEq, Debug)]
struct SimplifiedLogRecord {
level: LogLevel,
formatted_message: String
}

impl SimplifiedLogRecord {
pub fn new<S: Into<String>>(level: LogLevel, msg: S) -> SimplifiedLogRecord {
SimplifiedLogRecord {
level: level,
formatted_message: msg.into()
}
}
}

struct MockLogger {
pub messages: Arc<Mutex<Vec<SimplifiedLogRecord>>>
}

impl MockLogger {
pub fn new() -> MockLogger {
MockLogger {
messages: Arc::new(Mutex::new(Vec::new()))
}
}
}

impl log::Log for MockLogger {
fn enabled(&self, metadata: &LogMetadata) -> bool {
metadata.level() <= LogLevel::Trace
}

fn log(&self, record: &LogRecord) {
if self.enabled(record.metadata()) {
let mut lock = self.messages.lock().unwrap();
let record = SimplifiedLogRecord::new(record.level(), format!("{}", record.args()));
lock.push(record);
}
}
}

fn init_logging(logger: MockLogger) -> Result<(), log::SetLoggerError> {
log::set_logger(|max_log_level| {
max_log_level.set(log::LogLevelFilter::Trace);
Box::new(logger)
})
}

fn logging_callbacks_can_be_used_from_init_method(messages: Arc<Mutex<Vec<SimplifiedLogRecord>>>) {
let expected = [
SimplifiedLogRecord::new(LogLevel::Info, "INFO"),
SimplifiedLogRecord::new(LogLevel::Warn, "WARNING"),
SimplifiedLogRecord::new(LogLevel::Trace, "TRACE"),
SimplifiedLogRecord::new(LogLevel::Error, "ERROR"),
SimplifiedLogRecord::new(LogLevel::Debug, "DEBUG"),
];
let cfg = GlobalConfig::new(0x0308);
let mut builder = PythonParserBuilder::<MockPipe>::new(cfg);
builder.option(options::MODULE.to_owned(), "_test_module".to_owned());
builder.option(options::CLASS.to_owned(), "LoggingIsUsedInInitMethod".to_owned());
let _ = builder.build();
let lock = messages.lock().unwrap();
for i in &expected {
assert!((*lock).contains(i), "This item wasn't found in the expected messages: {:?}", i);
}
}

fn logging_callbacks_are_not_overriden_if_they_are_already_defined(messages: Arc<Mutex<Vec<SimplifiedLogRecord>>>) {
let expected = [
SimplifiedLogRecord::new(LogLevel::Warn, "Already implemented info() function, omitting callback definition."),
SimplifiedLogRecord::new(LogLevel::Warn, "Already implemented warning() function, omitting callback definition."),
SimplifiedLogRecord::new(LogLevel::Warn, "Already implemented trace() function, omitting callback definition."),
SimplifiedLogRecord::new(LogLevel::Warn, "Already implemented error() function, omitting callback definition."),
SimplifiedLogRecord::new(LogLevel::Warn, "Already implemented debug() function, omitting callback definition."),
];
let cfg = GlobalConfig::new(0x0308);
let mut builder = PythonParserBuilder::<MockPipe>::new(cfg);
builder.option(options::MODULE.to_owned(), "_test_module.test_logging".to_owned());
builder.option(options::CLASS.to_owned(), "LoggingCallbacksAreNotOverriden".to_owned());
let _ = builder.build();
let lock = messages.lock().unwrap();
for i in &expected {
assert!((*lock).contains(i), "This item wasn't found in the expected messages: {:?}", i);
}
}

fn set_up() -> Arc<Mutex<Vec<SimplifiedLogRecord>>> {
let logger = MockLogger::new();
let messages = logger.messages.clone();
let _ = init_logging(logger);
SYSLOG_NG_INITIALIZED.call_once(|| {
unsafe { syslog_ng_global_init(); }
});
env::set_var("PYTHONPATH", env::current_dir().unwrap());
messages
}

#[test]
fn test_run_tests() {
let messages = set_up();
logging_callbacks_can_be_used_from_init_method(messages.clone());
logging_callbacks_are_not_overriden_if_they_are_already_defined(messages);
}

0 comments on commit 13b69c0

Please sign in to comment.