1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
extern crate log;
extern crate log4rs;
extern crate sentry;

use log::{Level, Record};
use log4rs::{
	append::Append,
	encode::{
		Encode,
		writer::simple::SimpleWriter
	}
};
use sentry::{
	protocol::value::{Number, Value},
	Level as SentryLevel
};

#[derive(Debug)]
pub struct SentryAppender
{
	encoder : Box<Encode>
}

impl SentryAppender
{
	pub fn new(encoder : Box<Encode>) -> Self
	{
		SentryAppender { encoder }
	}
}

impl Append for SentryAppender
{
	fn append(&self, record: &Record) -> Result<(), Box<std::error::Error + Sync + Send>>
	{
		let level = match record.level() {
			Level::Error => SentryLevel::Error,
			Level::Warn => SentryLevel::Warning,
			_ => return Ok(()) // don't send messages < warn to sentry
		};
		
		let mut buf : Vec<u8> = Vec::new();
		self.encoder.encode(&mut SimpleWriter(&mut buf), record)?;
		let msg = match String::from_utf8(buf) {
			Ok(msg) => msg,
			Err(e) => return Err(Box::new(e))
		};
		
		let mut event = sentry::protocol::Event::new();
		event.level = level;
		event.message = Some(msg);
		event.logger = Some(record.metadata().target().to_owned());
		
		if let Some(file) = record.file()
		{
			event.extra.insert("file".to_owned(), Value::String(file.to_owned()));
		}
		
		if let Some(line) = record.line()
		{
			event.extra.insert("line".to_owned(), Value::Number(Number::from(line)));
		}
		
		if let Some(module_path) = record.module_path()
		{
			event.tags.insert("module_path".to_owned(), module_path.to_owned());
		}
		
		sentry::capture_event(event);
		Ok(())
	}

	fn flush(&self) {}
}