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.

490 lines
15KB

  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::{BTreeMap, VecDeque};
  7. use std::fmt::{self, 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 as InfluentValue};
  12. use slog::{self, OwnedKVList, Drain, Key, KV};
  13. use super::{nanos, file_logger};
  14. use influx;
  15. const N_WARNINGS: usize = 150;
  16. #[macro_export]
  17. macro_rules! confirmed {
  18. ($warnings:ident, $($args:tt)*) => (
  19. {
  20. $warnings.send(Warning::Confirmed( ( format!($($args)*) ) ) ).unwrap();
  21. }
  22. )
  23. }
  24. /// logs a `Warning::Awesome` message to the `WarningsManager`
  25. #[macro_export]
  26. macro_rules! awesome {
  27. ($warnings:ident, $($args:tt)*) => (
  28. {
  29. $warnings.send(Warning::Awesome( ( format!($($args)*) ) ) ).unwrap();
  30. }
  31. )
  32. }
  33. #[macro_export]
  34. macro_rules! critical {
  35. ($warnings:ident, $($args:tt)*) => (
  36. {
  37. $warnings.send(Warning::Critical( ( format!($($args)*) ) ) ).unwrap();
  38. }
  39. )
  40. }
  41. #[macro_export]
  42. macro_rules! notice {
  43. ($warnings:ident, $($args:tt)*) => (
  44. {
  45. $warnings.send(Warning::Notice( ( format!($($args)*) ) ) ).unwrap();
  46. }
  47. )
  48. }
  49. #[macro_export]
  50. macro_rules! error {
  51. ($warnings:ident, $($args:tt)*) => (
  52. {
  53. $warnings.send(Warning::Error( ( format!($($args)*) ) ) ).unwrap();
  54. }
  55. )
  56. }
  57. /// represents a non-fatal error somewhere in
  58. /// the system to report either to the program interface
  59. /// or in logs.
  60. ///
  61. #[derive(Debug, Clone, PartialEq)]
  62. pub enum Warning {
  63. Notice(String),
  64. Error(String),
  65. DegradedService(String),
  66. Critical(String),
  67. Confirmed(String),
  68. Awesome(String),
  69. Debug {
  70. msg: String,
  71. kv: MeasurementRecord,
  72. },
  73. Terminate
  74. }
  75. impl Warning {
  76. pub fn msg(&self) -> String {
  77. match *self {
  78. Warning::Notice(ref s) | Warning::Error(ref s) |
  79. Warning::DegradedService(ref s) | Warning::Critical(ref s) |
  80. Warning::Awesome(ref s) | Warning::Confirmed(ref s) |
  81. Warning::Debug { msg: ref s, .. } =>
  82. s.clone(),
  83. Warning::Terminate => "".to_owned()
  84. }
  85. }
  86. pub fn msg_str(&self) -> &str {
  87. match *self {
  88. Warning::Notice(ref s) | Warning::Error(ref s) |
  89. Warning::DegradedService(ref s) | Warning::Critical(ref s) |
  90. Warning::Awesome(ref s) | Warning::Confirmed(ref s) |
  91. Warning::Debug { msg: ref s, .. } =>
  92. s.as_ref(),
  93. Warning::Terminate => "Terminate"
  94. }
  95. }
  96. pub fn category_str(&self) -> &str {
  97. match self {
  98. &Warning::Notice(_) => "notice",
  99. &Warning::Error(_) => "error",
  100. &Warning::Critical(_) => "critical",
  101. &Warning::DegradedService(_) => "degraded_service",
  102. &Warning::Confirmed(_) => "confirmed",
  103. &Warning::Awesome(_) => "awesome",
  104. &Warning::Debug { .. } => "debug",
  105. &Warning::Terminate => "terminate",
  106. }
  107. }
  108. pub fn category(&self, f: &mut Formatter) {
  109. match self {
  110. &Warning::Notice(_) => {
  111. write!(f, "[ Notice ]");
  112. }
  113. &Warning::Error(_) => {
  114. write!(f, "{yellow}[{title}]{reset}",
  115. yellow = Fg(color::LightYellow),
  116. title = " Error--",
  117. reset = Fg(color::Reset));
  118. }
  119. &Warning::Critical(_) => {
  120. write!(f, "{bg}{fg}{title}{resetbg}{resetfg}",
  121. bg = Bg(color::Red),
  122. fg = Fg(color::White),
  123. title = " CRITICAL ",
  124. resetbg = Bg(color::Reset),
  125. resetfg = Fg(color::Reset));
  126. }
  127. &Warning::Awesome(_) => {
  128. write!(f, "{color}[{title}]{reset}",
  129. color = Fg(color::Green),
  130. title = "Awesome!",
  131. reset = Fg(color::Reset));
  132. }
  133. &Warning::DegradedService(_) => {
  134. write!(f, "{color}[{title}] {reset}",
  135. color = Fg(color::Blue),
  136. title = "Degraded Service ",
  137. reset = Fg(color::Reset));
  138. }
  139. &Warning::Confirmed(_) => {
  140. write!(f, "{bg}{fg}{title}{resetbg}{resetfg}",
  141. bg = Bg(color::Blue),
  142. fg = Fg(color::White),
  143. title = "Confirmed ",
  144. resetbg = Bg(color::Reset),
  145. resetfg = Fg(color::Reset));
  146. }
  147. _ => {}
  148. }
  149. }
  150. }
  151. impl Display for Warning {
  152. fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
  153. self.category(f);
  154. write!(f, " {}", self.msg())
  155. }
  156. }
  157. // impl Message for Warning {
  158. // fn kill_switch() -> Self {
  159. // Warning::Terminate
  160. // }
  161. // }
  162. #[derive(Debug, Clone)]
  163. pub struct Record {
  164. pub time: DateTime<Utc>,
  165. pub msg: Warning
  166. }
  167. impl Record {
  168. pub fn new(msg: Warning) -> Self {
  169. let time = Utc::now();
  170. Record { time, msg }
  171. }
  172. pub fn to_measurement(&self, name: &'static str) -> Measurement {
  173. let cat = self.msg.category_str();
  174. let body = self.msg.msg_str();
  175. let mut m = Measurement::new(name);
  176. m.add_tag("category", cat);
  177. m.add_field("msg", InfluentValue::String(body));
  178. m.set_timestamp(nanos(self.time) as i64);
  179. m
  180. }
  181. }
  182. impl Display for Record {
  183. fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
  184. write!(f, "{} | {}", self.time.format("%H:%M:%S"), self.msg)
  185. }
  186. }
  187. pub type SlogResult = Result<(), slog::Error>;
  188. #[derive(Debug, Clone, PartialEq)]
  189. pub enum Value {
  190. String(String),
  191. Float(f64),
  192. Integer(i64),
  193. Boolean(bool)
  194. }
  195. impl Value {
  196. pub fn to_influent<'a>(&'a self) -> InfluentValue<'a> {
  197. match self {
  198. &Value::String(ref s) => InfluentValue::String(s),
  199. &Value::Float(n) => InfluentValue::Float(n),
  200. &Value::Integer(i) => InfluentValue::Integer(i),
  201. &Value::Boolean(b) => InfluentValue::Boolean(b),
  202. }
  203. }
  204. }
  205. #[derive(Debug, Clone, PartialEq)]
  206. pub struct MeasurementRecord {
  207. fields: Vec<(Key, Value)>,
  208. //measurement: &'a mut Measurement<'a>,
  209. tags: Vec<(Key, String)>,
  210. }
  211. impl MeasurementRecord {
  212. pub fn new() -> Self {
  213. MeasurementRecord {
  214. fields: Vec::new(),
  215. tags: Vec::new(),
  216. }
  217. }
  218. pub fn add_field(&mut self, key: Key, val: Value) -> SlogResult {
  219. self.fields.push((key, val));
  220. Ok(())
  221. }
  222. pub fn add_tag(&mut self, key: Key, val: String) -> SlogResult {
  223. self.tags.push((key, val));
  224. Ok(())
  225. }
  226. pub fn serialize_values(&mut self, record: &slog::Record, values: &OwnedKVList) {
  227. let mut builder = TagBuilder { mrec: self };
  228. values.serialize(record, &mut builder);
  229. }
  230. pub fn to_measurement<'a>(&'a self, name: &'a str) -> Measurement<'a> {
  231. let fields: BTreeMap<&'a str, InfluentValue<'a>> =
  232. self.fields.iter()
  233. .map(|&(k, ref v)| {
  234. (k, v.to_influent())
  235. }).collect();
  236. let tags: BTreeMap<&'a str, &'a str> =
  237. self.tags.iter()
  238. .map(|&(k, ref v)| {
  239. (k, v.as_ref())
  240. }).collect();
  241. Measurement {
  242. key: name,
  243. timestamp: Some(nanos(Utc::now()) as i64),
  244. fields,
  245. tags,
  246. }
  247. }
  248. }
  249. impl slog::Serializer for MeasurementRecord {
  250. fn emit_usize(&mut self, key: Key, val: usize) -> SlogResult { self.add_field(key, Value::Integer(val as i64)) }
  251. fn emit_isize(&mut self, key: Key, val: isize) -> SlogResult { self.add_field(key, Value::Integer(val as i64)) }
  252. fn emit_bool(&mut self, key: Key, val: bool) -> SlogResult { self.add_field(key, Value::Boolean(val)); Ok(()) }
  253. fn emit_u8(&mut self, key: Key, val: u8) -> SlogResult { self.add_field(key, Value::Integer(val as i64)) }
  254. fn emit_i8(&mut self, key: Key, val: i8) -> SlogResult { self.add_field(key, Value::Integer(val as i64)) }
  255. fn emit_u16(&mut self, key: Key, val: u16) -> SlogResult { self.add_field(key, Value::Integer(val as i64)) }
  256. fn emit_i16(&mut self, key: Key, val: i16) -> SlogResult { self.add_field(key, Value::Integer(val as i64)) }
  257. fn emit_u32(&mut self, key: Key, val: u32) -> SlogResult { self.add_field(key, Value::Integer(val as i64)) }
  258. fn emit_i32(&mut self, key: Key, val: i32) -> SlogResult { self.add_field(key, Value::Integer(val as i64)) }
  259. fn emit_f32(&mut self, key: Key, val: f32) -> SlogResult { self.add_field(key, Value::Float(val as f64)) }
  260. fn emit_u64(&mut self, key: Key, val: u64) -> SlogResult { self.add_field(key, Value::Integer(val as i64)) }
  261. fn emit_i64(&mut self, key: Key, val: i64) -> SlogResult { self.add_field(key, Value::Integer(val)) }
  262. fn emit_f64(&mut self, key: Key, val: f64) -> SlogResult { self.add_field(key, Value::Float(val)) }
  263. fn emit_str(&mut self, key: Key, val: &str) -> SlogResult { self.add_field(key, Value::String(val.to_string())) }
  264. fn emit_unit(&mut self, key: Key) -> SlogResult { self.add_field(key, Value::Boolean(true)) }
  265. fn emit_none(&mut self, key: Key) -> SlogResult { Ok(()) } //self.add_field(key, Value::String("none".into())) }
  266. fn emit_arguments(&mut self, key: Key, val: &fmt::Arguments) -> SlogResult { self.add_field(key, Value::String(val.to_string())) }
  267. }
  268. pub struct TagBuilder<'a> {
  269. mrec: &'a mut MeasurementRecord
  270. }
  271. impl<'a> slog::Serializer for TagBuilder<'a> {
  272. fn emit_str(&mut self, key: Key, val: &str) -> SlogResult {
  273. self.mrec.add_tag(key, val.to_string())
  274. }
  275. fn emit_arguments(&mut self, key: Key, val: &fmt::Arguments) -> SlogResult {
  276. self.mrec.add_tag(key, val.to_string())
  277. }
  278. }
  279. pub struct WarningsDrain<D: Drain> {
  280. tx: Arc<Mutex<Sender<Warning>>>,
  281. drain: D
  282. }
  283. impl WarningsDrain<slog::Discard> {
  284. pub fn new(tx: Sender<Warning>) -> Self {
  285. let tx = Arc::new(Mutex::new(tx));
  286. let drain = slog::Discard;
  287. WarningsDrain { tx, drain }
  288. }
  289. }
  290. impl<D: Drain> Drain for WarningsDrain<D> {
  291. type Ok = ();
  292. type Err = D::Err;
  293. fn log(&self, record: &slog::Record, values: &OwnedKVList) -> Result<Self::Ok, Self::Err> {
  294. //let mut meas = Measurement::new("warnings");
  295. //println!("{:?}", values);
  296. let mut ser = MeasurementRecord::new();
  297. ser.serialize_values(record, values);
  298. //values.serialize(record, &mut ser);
  299. record.kv().serialize(record, &mut ser);
  300. //println!("{:?}", ser);
  301. let msg = record.msg().to_string();
  302. if let Ok(lock) = self.tx.lock() {
  303. lock.send(Warning::Debug { msg, kv: ser });
  304. }
  305. Ok(())
  306. }
  307. }
  308. #[derive(Debug)]
  309. pub struct WarningsManager {
  310. pub tx: Sender<Warning>,
  311. pub warnings: Arc<RwLock<VecDeque<Record>>>,
  312. thread: Option<JoinHandle<()>>
  313. }
  314. impl WarningsManager {
  315. /// `measurement_name` is the name of the influxdb measurement
  316. /// we will save log entries to.
  317. ///
  318. pub fn new(measurement_name: &'static str) -> Self {
  319. let warnings = Arc::new(RwLock::new(VecDeque::new()));
  320. let warnings_copy = warnings.clone();
  321. let (tx, rx) = channel();
  322. let mut buf = String::with_capacity(4096);
  323. let ctx = zmq::Context::new();
  324. let socket = influx::push(&ctx).unwrap();
  325. let thread = thread::spawn(move || {
  326. let path = format!("var/log/warnings-manager-{}.log", measurement_name);
  327. let logger = file_logger(&path);
  328. info!(logger, "entering loop");
  329. loop {
  330. if let Ok(msg) = rx.recv() {
  331. match msg {
  332. Warning::Terminate => {
  333. crit!(logger, "terminating");
  334. break;
  335. }
  336. Warning::Debug { msg, kv } => {
  337. debug!(logger, "new Warning::Debug arrived";
  338. "msg" => &msg);
  339. let mut meas = kv.to_measurement(measurement_name);
  340. meas.add_field("msg", InfluentValue::String(msg.as_ref()));
  341. meas.add_tag("category", "debug");
  342. influx::serialize(&meas, &mut buf);
  343. socket.send_str(&buf, 0);
  344. buf.clear();
  345. // and don't push to warnings
  346. // bc it's debug
  347. }
  348. other => {
  349. debug!(logger, "new {} arrived", other.category_str();
  350. "msg" => other.category_str());
  351. let rec = Record::new(other);
  352. {
  353. let m = rec.to_measurement(measurement_name);
  354. influx::serialize(&m, &mut buf);
  355. socket.send_str(&buf, 0);
  356. buf.clear();
  357. }
  358. if let Ok(mut lock) = warnings.write() {
  359. lock.push_front(rec);
  360. lock.truncate(N_WARNINGS);
  361. }
  362. }
  363. }
  364. }
  365. }
  366. });
  367. WarningsManager {
  368. warnings: warnings_copy,
  369. thread: Some(thread),
  370. tx
  371. }
  372. }
  373. }
  374. impl Drop for WarningsManager {
  375. fn drop(&mut self) {
  376. self.tx.send(Warning::Terminate);
  377. if let Some(thread) = self.thread.take() {
  378. thread.join();
  379. }
  380. }
  381. }
  382. #[cfg(test)]
  383. mod tests {
  384. use super::*;
  385. use test::{black_box, Bencher};
  386. #[test]
  387. fn it_creates_a_logger() {
  388. let wm = WarningsManager::new();
  389. let im = influx::writer(wm.tx.clone());
  390. let drain = WarningsDrain { tx: Arc::new(Mutex::new(wm.tx.clone())), drain: slog::Discard };
  391. let logger = slog::Logger::root(drain, o!());
  392. //for _ in 0..60 {
  393. // debug!(logger, "test 123"; "exchange" => "plnx");
  394. //}
  395. }
  396. #[bench]
  397. fn it_sends_integers_with_a_sender_behind_a_mutex(b: &mut Bencher) {
  398. let (tx, rx) = channel();
  399. enum Msg {
  400. Val(usize),
  401. Terminate
  402. }
  403. let worker = thread::spawn(move || {
  404. let mut xs = Vec::new();
  405. loop {
  406. match rx.recv().unwrap() {
  407. Msg::Val(x) => { xs.push(x); }
  408. Msg::Terminate => break,
  409. }
  410. }
  411. xs.len()
  412. });
  413. let tx = Arc::new(Mutex::new(tx));
  414. b.iter(|| {
  415. let lock = tx.lock().unwrap();
  416. lock.send(Msg::Val(1));
  417. });
  418. tx.lock().unwrap().send(Msg::Terminate);
  419. let len = worker.join().unwrap();
  420. println!("{}", len);
  421. }
  422. }