forked from aws/aws-lambda-rust-runtime
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy patherror.rs
More file actions
199 lines (179 loc) · 6.08 KB
/
error.rs
File metadata and controls
199 lines (179 loc) · 6.08 KB
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//! The error module defines the error types that can be returned
//! by custom handlers as well as the runtime itself.
use std::{cmp, env, error::Error, fmt};
use backtrace;
use lambda_runtime_client::error;
use serde_json;
/// The `RuntimeError` object is returned by the custom runtime as it polls
/// for new events and tries to execute the handler function. The error
/// is primarily used by other methods within this crate and should not be relevant
/// to developers building Lambda functions. Handlers are expected to return
/// the `HandlerError` defined in this module.
#[derive(Debug, Clone)]
pub struct RuntimeError {
msg: String,
stack_trace: Option<backtrace::Backtrace>,
/// The request id that generated this error
pub(crate) request_id: Option<String>,
/// Whether the error is recoverable or not.
pub(crate) recoverable: bool,
}
impl RuntimeError {
/// Creates a new `RuntimeError` that is unrecoverable and it will cause the
/// runtime to panic in order to force a restart of the execution environment.
/// When a new `RuntimeError` is created the stack trace for the error is collected
/// automatically using the `backtrace` crate.
///
/// # Arguments
///
/// * `msg` The error message to be attached to the error.
///
/// # Returns
/// A new `RuntimeError` instance with the `recoverable` property set to `false`.
pub(crate) fn unrecoverable(msg: &str) -> RuntimeError {
let mut new_error = RuntimeError::new(msg);
new_error.recoverable = false;
new_error
}
/// Creates a new `RuntimeError` with the given properties. The stack trace for the
/// error is collected automatically using the `backtrace` crate.
///
/// # Arguments
///
/// * `msg` The error message
///
/// # Returns
/// A new `RuntimeError` instance.
pub(crate) fn new(msg: &str) -> RuntimeError {
let mut trace: Option<backtrace::Backtrace> = None;
let is_backtrace = env::var("RUST_BACKTRACE");
if is_backtrace.is_ok() && is_backtrace.unwrap() == "1" {
trace!("Begin backtrace collection");
trace = Option::from(backtrace::Backtrace::new());
trace!("Completed backtrace collection");
}
RuntimeError {
msg: String::from(msg),
stack_trace: trace,
recoverable: true,
request_id: None,
}
}
}
impl error::RuntimeApiError for RuntimeError {
fn to_response(&self) -> error::ErrorResponse {
let backtrace = format!("{:?}", self.stack_trace);
error::ErrorResponse {
error_message: String::from(self.description()),
error_type: String::from(error::ERROR_TYPE_HANDLED),
stack_trace: Option::from(backtrace.lines().map(|s| s.to_string()).collect::<Vec<String>>()),
}
}
}
impl fmt::Display for RuntimeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.msg)
}
}
// This is important for other errors to wrap this one.
impl Error for RuntimeError {
fn description(&self) -> &str {
&self.msg
}
fn cause(&self) -> Option<&Error> {
// Generic error, underlying cause isn't tracked.
None
}
}
impl From<env::VarError> for RuntimeError {
fn from(e: env::VarError) -> Self {
RuntimeError::unrecoverable(e.description())
}
}
impl From<serde_json::Error> for RuntimeError {
fn from(e: serde_json::Error) -> Self {
RuntimeError::unrecoverable(e.description())
}
}
impl From<error::ApiError> for RuntimeError {
fn from(e: error::ApiError) -> Self {
let mut err = RuntimeError::new(e.description());
err.recoverable = e.recoverable;
err.stack_trace = e.backtrace;
err
}
}
/// The error type for functions that are used as the `Handler` type. New errors
/// should be instantiated using the `new_error()` method of the `runtime::Context`
/// object passed to the handler function.
///
/// An implementation of `PartialEq` is provided and based it's comparison on the `msg`
/// field.
#[derive(Debug, Clone)]
pub struct HandlerError {
msg: String,
backtrace: Option<backtrace::Backtrace>,
}
impl cmp::PartialEq for HandlerError {
fn eq(&self, other: &HandlerError) -> bool {
self.msg == other.msg
}
}
impl fmt::Display for HandlerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.msg)
}
}
// This is important for other errors to wrap this one.
impl Error for HandlerError {
fn description(&self) -> &str {
&self.msg
}
fn cause(&self) -> Option<&Error> {
// Generic error, underlying cause isn't tracked.
None
}
}
impl HandlerError {
/// Creates a new handler error. This method is used by the `new_error()` method
/// of the `runtime::Context` object.
///
/// # Arguments
///
/// * `msg` The error message for the new error
/// * `trace` A `Backtrace` object to generate the stack trace for the error
/// response. This is provided by the `Context` object.
pub(crate) fn new(msg: &str, trace: Option<backtrace::Backtrace>) -> HandlerError {
HandlerError {
msg: msg.to_string(),
backtrace: trace,
}
}
}
impl error::RuntimeApiError for HandlerError {
fn to_response(&self) -> error::ErrorResponse {
let backtrace = format!("{:?}", self.backtrace);
error::ErrorResponse {
error_message: String::from(self.description()),
error_type: String::from(error::ERROR_TYPE_HANDLED),
stack_trace: Option::from(backtrace.lines().map(|s| s.to_string()).collect::<Vec<String>>()),
}
}
}
#[cfg(test)]
mod tests {
use super::HandlerError;
#[test]
fn handler_error_impls_partialeq() {
assert_eq!(
HandlerError {
msg: "test".into(),
backtrace: Default::default()
},
HandlerError {
msg: "test".into(),
backtrace: Some(Default::default())
}
)
}
}