use super::output;
use super::{Level, LevelFilter, LogSink};
use bytes::{BufMut, Bytes, BytesMut};
use log;
use serde::Serialize;
use std::io;
use std::io::Write;
use std::ops::Drop;
use std::sync::{Arc, Mutex, Weak};
pub use log::SetLoggerError as MakeGlobalError;
pub struct Logger {
pub src: String,
pub level: LevelFilter,
pub sink: Weak<LogSink>,
buffer: Buffer,
}
impl Logger {
pub fn new(sink: &Arc<LogSink>) -> Logger {
let level = sink.default_level;
Logger {
src: String::default(),
sink: Arc::downgrade(&sink),
level,
buffer: Buffer(BytesMut::new()),
}
}
pub fn with_src(&self, src: impl Into<String>) -> Self {
Logger {
src: src.into(),
sink: self.sink.clone(),
level: self.level,
buffer: Buffer(BytesMut::new()),
}
}
pub fn make_global(self) -> Result<(), MakeGlobalError> {
log::set_max_level(self.level);
log::set_boxed_logger(Box::new(Adapter(Mutex::new(self))))
}
pub fn log(&mut self, level: Level, msg: &str) -> ContextWriter {
let mut writer = ContextWriter {
logger: None,
pretty: false,
};
if level <= self.level {
if let Some(sink) = self.sink.upgrade() {
output::begin_entry(&mut self.buffer, sink.format, level, &self.src, msg);
writer.logger = Some(self);
}
}
writer
}
fn send(&mut self) {
if let Some(sink) = self.sink.upgrade() {
sink.send(self.buffer.take_bytes());
}
}
pub fn trace(&mut self, msg: &str) -> ContextWriter {
self.log(Level::Trace, msg)
}
pub fn debug(&mut self, msg: &str) -> ContextWriter {
self.log(Level::Debug, msg)
}
pub fn info(&mut self, msg: &str) -> ContextWriter {
self.log(Level::Info, msg)
}
pub fn warn(&mut self, msg: &str) -> ContextWriter {
self.log(Level::Warn, msg)
}
pub fn error(&mut self, msg: &str) -> ContextWriter {
self.log(Level::Error, msg)
}
}
impl Clone for Logger {
fn clone(&self) -> Self {
Logger {
src: self.src.clone(),
sink: self.sink.clone(),
level: self.level,
buffer: Buffer(BytesMut::new()),
}
}
}
struct Buffer(BytesMut);
impl Buffer {
fn take_bytes(&mut self) -> Bytes {
self.0.take().freeze()
}
}
impl Write for Buffer {
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
let len = src.len();
self.0.reserve(len);
self.0.put_slice(src);
Ok(len)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
pub struct ContextWriter<'a> {
pretty: bool,
logger: Option<&'a mut Logger>,
}
impl<'a> ContextWriter<'a> {
pub fn pretty(&mut self) -> &mut Self {
self.pretty = true;
self
}
pub fn with<V: Serialize>(&mut self, key: &str, value: &V) -> &mut Self {
self.write(key, value)
}
pub fn write<V: Serialize>(&mut self, key: &str, value: &V) -> &mut Self {
if let Some(ref mut logger) = self.logger {
if let Some(sink) = logger.sink.upgrade() {
if self.pretty {
output::context_pretty(&mut logger.buffer, sink.format, key, value);
} else {
output::context(&mut logger.buffer, sink.format, key, value);
}
}
}
self
}
pub fn finish(self) {
}
}
impl<'a> Drop for ContextWriter<'a> {
fn drop(&mut self) {
if let Some(ref mut logger) = self.logger {
if let Some(sink) = logger.sink.upgrade() {
output::end_entry(&mut logger.buffer, sink.format);
logger.send();
}
}
}
}
struct Adapter(Mutex<Logger>);
impl log::Log for Adapter {
fn enabled(&self, metadata: &log::Metadata) -> bool {
let logger = self.0.lock().expect("could not lock logger");
metadata.level() <= logger.level
}
fn log(&self, record: &log::Record) {
let mut logger = self.0.lock().expect("could not lock logger");
if record.level() <= logger.level {
if let Some(sink) = logger.sink.upgrade() {
output::simple_entry(
&mut logger.buffer,
sink.format,
record.level(),
record.target(),
record.args(),
);
logger.send();
}
}
}
fn flush(&self) {}
}