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.

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