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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use error_chain::ChainedError;
use failure;
use std::collections::HashMap;
use std::convert::From;
#[derive(Serialize)]
pub struct Notice<'req> {
pub api_key: &'req str,
pub notifier: Notifier,
pub error: Error,
pub request: Request<'req>,
pub server: Server<'req>,
}
#[derive(Serialize)]
pub struct Error {
pub class: String,
pub message: Option<String>,
pub causes: Option<Vec<Error>>,
}
impl From<failure::Error> for Error {
fn from(error: failure::Error) -> Error {
Error {
class: format!("{}", error),
message: Some(format!("{:?}", error)),
causes: Some(
error
.iter_causes()
.map(|cause| Error {
class: format!("{}", cause),
message: Some(format!("{:?}", cause)),
causes: None,
})
.collect(),
),
}
}
}
impl From<&failure::Error> for Error {
fn from(error: &failure::Error) -> Error {
Error {
class: format!("{}", error),
message: Some(format!("{:?}", error)),
causes: Some(
error
.iter_causes()
.map(|cause| Error {
class: format!("{}", cause),
message: Some(format!("{:?}", cause)),
causes: None,
})
.collect(),
),
}
}
}
impl From<Box<std::error::Error>> for Error {
fn from(error: Box<std::error::Error>) -> Error {
Error {
class: format!("{}", error),
message: Some(format!("{:?}", error)),
causes: None,
}
}
}
impl Error {
pub fn new<E>(error: &E) -> Error
where
E: ChainedError,
{
Error {
class: error.description().to_string(),
message: Some(error.display_chain().to_string()),
causes: Some(error.iter().map(|cause| Error::std_err(cause)).collect()),
}
}
fn std_err(error: &::std::error::Error) -> Error {
Error {
class: error.description().to_string(),
message: None,
causes: error.cause().map(|cause| vec![Error::std_err(cause)]),
}
}
}
#[derive(Serialize)]
pub struct Notifier {
pub name: &'static str,
pub url: &'static str,
pub version: &'static str,
}
#[derive(Serialize)]
pub struct Request<'req> {
pub context: Option<HashMap<&'req str, &'req str>>,
pub cgi_data: HashMap<String, String>,
}
#[derive(Serialize)]
pub struct Server<'req> {
pub project_root: &'req str,
pub environment_name: &'req str,
pub hostname: &'req str,
pub time: u64,
pub pid: u32,
}
#[cfg(test)]
mod tests {
use errors::*;
use failure;
use notice;
#[test]
fn test_chained_err() {
let error : Result<()> = Err(ErrorKind::RedirectionError.into());
let chain = error.chain_err(|| ErrorKind::RateExceededError);
let notice = ::notice::Error::new(&chain.unwrap_err());
assert_eq!("Honeybadger rate limit exceeded", notice.class);
if let Some(causes) = notice.causes {
assert_eq!(2, causes.len());
} else {
assert_eq!("", "Missing causes in ::notice::Error");
}
}
#[test]
fn test_failure_err() {
let error : failure::Error = failure::err_msg("test_error_message");
let notice : notice::Error = notice::From::from(error);
assert_eq!("test_error_message", notice.class);
}
}