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<File>) {
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<TcpStream>) {
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() {
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 {
let listener = TcpListener::bind("127.0.0.1:10663").unwrap();
let mut lbuf = [0u8; 256];
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])>) {
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() {
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() {
let tmp = env::temp_dir();
let tmp_log = tmp.join("log.log");
let (tx, rx) = channel();
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());
error!("TEST");
test_mysql();
test_socket(rx);
test_sqlite();
let _ = fs::remove_file(tmp.join("log.log")).unwrap();
}