extern crate libmultilog; #[macro_use] extern crate log; #[cfg(feature = "mysql")] extern crate mysql; #[cfg(feature = "rusqlite")] extern crate rusqlite; extern crate time; use libmultilog::multi::*; use log::{LogLevelFilter, LogRecord}; #[cfg(feature = "mysql")] use mysql::conn::MyOpts; #[cfg(feature = "mysql")] use mysql::conn::pool::MyPool; #[cfg(feature = "rusqlite")] use rusqlite::SqliteConnection; use std::default::Default; use std::env; use std::fs::{self, File}; use std::io::{BufWriter, Write}; #[cfg(feature = "socket")] use std::io::Read; #[cfg(feature = "socket")] use std::net::{TcpListener, TcpStream}; use std::sync::mpsc::{channel, Sender, Receiver}; #[cfg(feature = "socket")] use std::thread; fn stdoutfn(record: &LogRecord) { println!("{}", record.args()); } fn fileoutfn(record: &LogRecord, w: &mut BufWriter) { let now = time::now(); w.write_fmt(format_args!("{} {:5} {:4} -- {}: {}\n", now.rfc3339(), record.level(), record.location().line(), record.location().module_path(), record.args())) .and(w.flush()) .unwrap(); } #[cfg(feature = "mysql")] fn mysqloutfn(record: &LogRecord, pool: &mut MyPool) { let mut stmt = pool.prepare(r"INSERT INTO log (created, level, line, module, message) VALUES (?, ?, ?, ?, ?)") .unwrap(); match stmt.execute((&time::get_time(), &format!("{}", record.level()), &format!("{}", record.location().line()), &record.location().module_path(), &format!("{}", record.args()))) { Ok(_) => {} Err(e) => panic!("Unable to insert log record! {}", e), }; } #[cfg(feature = "socket")] fn socketoutfn(record: &LogRecord, w: &mut BufWriter) { let now = time::now(); w.write_fmt(format_args!("{} {:5} {:4} -- {}: {}\n", now.rfc3339(), record.level(), record.location().line(), record.location().module_path(), record.args())) .and(w.flush()) .unwrap(); } #[cfg(feature = "rusqlite")] fn sqliteoutfn(record: &LogRecord, conn: &mut SqliteConnection) { conn.execute(r"INSERT INTO log (created, level, line, module, message) VALUES ($1, $2, $3, $4, $5)", &[&time::get_time(), &format!("{}", record.level()), &format!("{}", record.location().line()), &record.location().module_path(), &format!("{}", record.args())]) .unwrap(); } #[cfg(feature = "mysql")] fn config_mysql(ml: &mut MultiLogger) -> &mut MultiLogger { ml.enable_mysql(mysqloutfn, MyOpts { user: Some("travis".to_string()), pass: Some("".to_string()), db_name: Some("log_test".to_string()), ..Default::default() }, true); ml } #[cfg(not(feature = "mysql"))] fn config_mysql(ml: &mut MultiLogger) -> &mut MultiLogger { ml } #[cfg(feature = "mysql")] fn test_mysql() { // Read the mysql database row let pool = MyPool::new(MyOpts { user: Some("travis".to_string()), pass: Some("".to_string()), db_name: Some("log_test".to_string()), ..Default::default() }) .unwrap(); let _ = pool.prep_exec("SELECT * FROM log", ()).map(|result| { for row in result { assert_eq!("'TEST'", &row.unwrap()[5].into_str()[..]); } }); } #[cfg(not(feature = "mysql"))] fn test_mysql() {} #[cfg(feature = "socket")] fn config_socket(ml: &mut MultiLogger, tx: Sender<(usize, [u8; 256])>) -> &mut MultiLogger { // Setup a temporary tcp listener for the socket test let listener = TcpListener::bind("127.0.0.1:10663").unwrap(); let mut lbuf = [0u8; 256]; // Accept the connection on another thread. thread::spawn(move || { let (mut stream, _) = listener.accept().unwrap(); let l = stream.read(&mut lbuf).unwrap(); let _ = tx.send((l, lbuf)).unwrap(); }); ml.enable_socket(socketoutfn, "127.0.0.1:10663"); ml } #[cfg(not(feature = "socket"))] fn config_socket(ml: &mut MultiLogger, _: Sender<()>) -> &mut MultiLogger { ml } #[cfg(feature = "socket")] fn test_socket(rx: Receiver<(usize, [u8; 256])>) { // Wait for the socket result let (l, buf) = rx.recv().unwrap(); let s = String::from_utf8_lossy(&buf[..l]); let toks = s.split(' '); let lt = toks.last().unwrap(); assert_eq!("TEST", &(lt.trim())[..]); } #[cfg(not(feature = "socket"))] fn test_socket(_: Receiver<()>) {} #[cfg(feature = "rusqlite")] fn config_sqlite(ml: &mut MultiLogger) -> &mut MultiLogger { let tmp = env::temp_dir(); let tmp_db = tmp.join("log.db"); ml.enable_sqlite(sqliteoutfn, Some(tmp_db), true); ml } #[cfg(not(feature = "rusqlite"))] fn config_sqlite(ml: &mut MultiLogger) -> &mut MultiLogger { ml } #[cfg(feature = "rusqlite")] fn test_sqlite() { // Read the sqlite database row let tmp = env::temp_dir(); let tmp_db = tmp.join("log.db"); let conn = SqliteConnection::open(&tmp_db).unwrap(); let mut stmt = conn.prepare("SELECT * FROM log").unwrap(); for row in stmt.query(&[]).unwrap().map(|row| row.unwrap()) { let msg: String = row.get(5); assert_eq!("TEST", &msg[..]); } let _ = fs::remove_file(tmp_db).unwrap(); } #[cfg(not(feature = "rusqlite"))] fn test_sqlite() {} #[test] fn test_chained_loggers() { // Setup the file and logging db files. let tmp = env::temp_dir(); let tmp_log = tmp.join("log.log"); let (tx, rx) = channel(); // Initialize all the loggers let mut ml: MultiLogger = Default::default(); ml.enable_stdout(stdoutfn); ml.enable_file(fileoutfn, tmp_log); config_mysql(&mut ml); config_socket(&mut ml, tx); config_sqlite(&mut ml); assert!(init_multi_logger(LogLevelFilter::Debug, ml).is_ok()); // Log a message... error!("TEST"); test_mysql(); test_socket(rx); test_sqlite(); // Cleanup let _ = fs::remove_file(tmp.join("log.log")).unwrap(); }