You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

270 lines
7.2KB

  1. //! An object to handle everyone's errors
  2. //!
  3. use std::thread::{self, JoinHandle};
  4. use std::sync::{Arc, Mutex, RwLock};
  5. use std::sync::mpsc::{self, Sender, Receiver, channel};
  6. use std::collections::VecDeque;
  7. use std::fmt::{Display, Error as FmtError, Formatter};
  8. use zmq;
  9. use chrono::{DateTime, Utc, TimeZone};
  10. use termion::color::{self, Fg, Bg};
  11. use influent::measurement::{Measurement, Value};
  12. use super::nanos;
  13. use influx;
  14. const N_WARNINGS: usize = 150;
  15. #[macro_export]
  16. macro_rules! confirmed {
  17. ($warnings:ident, $($args:tt)*) => (
  18. {
  19. $warnings.send(Warning::Confirmed( ( format!($($args)*) ) ) ).unwrap();
  20. }
  21. )
  22. }
  23. /// logs a `Warning::Awesome` message to the `WarningsManager`
  24. #[macro_export]
  25. macro_rules! awesome {
  26. ($warnings:ident, $($args:tt)*) => (
  27. {
  28. $warnings.send(Warning::Awesome( ( format!($($args)*) ) ) ).unwrap();
  29. }
  30. )
  31. }
  32. #[macro_export]
  33. macro_rules! critical {
  34. ($warnings:ident, $($args:tt)*) => (
  35. {
  36. $warnings.send(Warning::Critical( ( format!($($args)*) ) ) ).unwrap();
  37. }
  38. )
  39. }
  40. #[macro_export]
  41. macro_rules! notice {
  42. ($warnings:ident, $($args:tt)*) => (
  43. {
  44. $warnings.send(Warning::Notice( ( format!($($args)*) ) ) ).unwrap();
  45. }
  46. )
  47. }
  48. #[macro_export]
  49. macro_rules! error {
  50. ($warnings:ident, $($args:tt)*) => (
  51. {
  52. $warnings.send(Warning::Error( ( format!($($args)*) ) ) ).unwrap();
  53. }
  54. )
  55. }
  56. /// represents a non-fatal error somewhere in
  57. /// the system to report either to the program interface
  58. /// or in logs.
  59. ///
  60. #[derive(Debug, Clone, PartialEq)]
  61. pub enum Warning {
  62. Notice(String),
  63. Error(String),
  64. DegradedService(String),
  65. Critical(String),
  66. Confirmed(String),
  67. Awesome(String),
  68. Terminate
  69. }
  70. impl Warning {
  71. pub fn msg(&self) -> String {
  72. match *self {
  73. Warning::Notice(ref s) | Warning::Error(ref s) |
  74. Warning::DegradedService(ref s) | Warning::Critical(ref s) |
  75. Warning::Awesome(ref s) | Warning::Confirmed(ref s) =>
  76. s.clone(),
  77. Warning::Terminate => "".to_owned()
  78. }
  79. }
  80. pub fn msg_str(&self) -> &str {
  81. match *self {
  82. Warning::Notice(ref s) | Warning::Error(ref s) |
  83. Warning::DegradedService(ref s) | Warning::Critical(ref s) |
  84. Warning::Awesome(ref s) | Warning::Confirmed(ref s) =>
  85. s.as_ref(),
  86. Warning::Terminate => "Terminate"
  87. }
  88. }
  89. pub fn category_str(&self) -> &str {
  90. match self {
  91. &Warning::Notice(_) => "notice",
  92. &Warning::Error(_) => "error",
  93. &Warning::Critical(_) => "critical",
  94. &Warning::DegradedService(_) => "degraded_service",
  95. &Warning::Confirmed(_) => "confirmed",
  96. &Warning::Awesome(_) => "awesome",
  97. &Warning::Terminate => "terminate",
  98. }
  99. }
  100. pub fn category(&self, f: &mut Formatter) {
  101. match self {
  102. &Warning::Notice(_) => {
  103. write!(f, "[ Notice ]");
  104. }
  105. &Warning::Error(_) => {
  106. write!(f, "{yellow}[{title}]{reset}",
  107. yellow = Fg(color::LightYellow),
  108. title = " Error--",
  109. reset = Fg(color::Reset));
  110. }
  111. &Warning::Critical(_) => {
  112. write!(f, "{bg}{fg}{title}{resetbg}{resetfg}",
  113. bg = Bg(color::Red),
  114. fg = Fg(color::White),
  115. title = " CRITICAL ",
  116. resetbg = Bg(color::Reset),
  117. resetfg = Fg(color::Reset));
  118. }
  119. &Warning::Awesome(_) => {
  120. write!(f, "{color}[{title}]{reset}",
  121. color = Fg(color::Green),
  122. title = "Awesome!",
  123. reset = Fg(color::Reset));
  124. }
  125. &Warning::DegradedService(_) => {
  126. write!(f, "{color}[{title}] {reset}",
  127. color = Fg(color::Blue),
  128. title = "Degraded Service ",
  129. reset = Fg(color::Reset));
  130. }
  131. &Warning::Confirmed(_) => {
  132. write!(f, "{bg}{fg}{title}{resetbg}{resetfg}",
  133. bg = Bg(color::Blue),
  134. fg = Fg(color::White),
  135. title = "Confirmed ",
  136. resetbg = Bg(color::Reset),
  137. resetfg = Fg(color::Reset));
  138. }
  139. _ => {}
  140. }
  141. }
  142. }
  143. impl Display for Warning {
  144. fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
  145. self.category(f);
  146. write!(f, " {}", self.msg())
  147. }
  148. }
  149. // impl Message for Warning {
  150. // fn kill_switch() -> Self {
  151. // Warning::Terminate
  152. // }
  153. // }
  154. #[derive(Debug, Clone)]
  155. pub struct Record {
  156. pub time: DateTime<Utc>,
  157. pub msg: Warning
  158. }
  159. impl Record {
  160. pub fn new(msg: Warning) -> Self {
  161. let time = Utc::now();
  162. Record { time, msg }
  163. }
  164. pub fn to_measurement(&self) -> Measurement {
  165. let cat = self.msg.category_str();
  166. let body = self.msg.msg_str();
  167. let mut m = Measurement::new("warnings");
  168. m.add_tag("category", cat);
  169. m.add_field("msg", Value::String(body));
  170. m.set_timestamp(nanos(self.time) as i64);
  171. m
  172. }
  173. }
  174. impl Display for Record {
  175. fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
  176. write!(f, "{} | {}", self.time.format("%H:%M:%S"), self.msg)
  177. }
  178. }
  179. #[derive(Debug)]
  180. pub struct WarningsManager {
  181. pub tx: Sender<Warning>,
  182. pub warnings: Arc<RwLock<VecDeque<Record>>>,
  183. thread: Option<JoinHandle<()>>
  184. }
  185. impl WarningsManager {
  186. pub fn new() -> Self {
  187. let warnings = Arc::new(RwLock::new(VecDeque::new()));
  188. let warnings_copy = warnings.clone();
  189. let (tx, rx) = channel();
  190. let mut buf = String::with_capacity(4096);
  191. let ctx = zmq::Context::new();
  192. let socket = influx::push(&ctx).unwrap();
  193. let thread = thread::spawn(move || { loop {
  194. if let Ok(msg) = rx.recv() {
  195. match msg {
  196. Warning::Terminate => {
  197. println!("warnings manager terminating");
  198. break;
  199. }
  200. other => {
  201. let rec = Record::new(other);
  202. {
  203. let m = rec.to_measurement();
  204. influx::serialize(&m, &mut buf);
  205. socket.send_str(&buf, 0);
  206. buf.clear();
  207. }
  208. if let Ok(mut lock) = warnings.write() {
  209. lock.push_front(rec);
  210. lock.truncate(N_WARNINGS);
  211. }
  212. }
  213. }
  214. }
  215. } });
  216. WarningsManager {
  217. warnings: warnings_copy,
  218. thread: Some(thread),
  219. tx
  220. }
  221. }
  222. }
  223. impl Drop for WarningsManager {
  224. fn drop(&mut self) {
  225. self.tx.send(Warning::Terminate);
  226. if let Some(thread) = self.thread.take() {
  227. thread.join();
  228. }
  229. }
  230. }