argmin/core/observers/
slog_logger.rs1use crate::core::{ArgminKV, ArgminOp, Error, IterState, Observe};
11use slog;
12use slog::{info, o, Drain, Record, Serializer, KV};
13use slog_async;
14use slog_async::OverflowStrategy;
15use slog_json;
16use slog_term;
17use std::fs::OpenOptions;
18use std::sync::Mutex;
19
20#[derive(Clone)]
22pub struct ArgminSlogLogger {
23 logger: slog::Logger,
25}
26
27impl ArgminSlogLogger {
28 pub fn term() -> Self {
30 ArgminSlogLogger::term_internal(OverflowStrategy::Block)
31 }
32
33 pub fn term_noblock() -> Self {
35 ArgminSlogLogger::term_internal(OverflowStrategy::Drop)
36 }
37
38 fn term_internal(overflow_strategy: OverflowStrategy) -> Self {
40 let decorator = slog_term::TermDecorator::new().build();
41 let drain = slog_term::FullFormat::new(decorator)
42 .use_original_order()
43 .build()
44 .fuse();
45 let drain = slog_async::Async::new(drain)
46 .overflow_strategy(overflow_strategy)
47 .build()
48 .fuse();
49 ArgminSlogLogger {
50 logger: slog::Logger::root(drain, o!()),
51 }
52 }
53
54 pub fn file(file: &str, truncate: bool) -> Result<Self, Error> {
59 ArgminSlogLogger::file_internal(file, OverflowStrategy::Block, truncate)
60 }
61
62 pub fn file_noblock(file: &str, truncate: bool) -> Result<Self, Error> {
67 ArgminSlogLogger::file_internal(file, OverflowStrategy::Drop, truncate)
68 }
69
70 fn file_internal(
72 file: &str,
73 overflow_strategy: OverflowStrategy,
74 truncate: bool,
75 ) -> Result<Self, Error> {
76 let file = OpenOptions::new()
78 .create(true)
79 .write(true)
80 .truncate(truncate)
81 .open(file)?;
82 let drain = Mutex::new(slog_json::Json::new(file).build()).map(slog::Fuse);
83 let drain = slog_async::Async::new(drain)
84 .overflow_strategy(overflow_strategy)
85 .build()
86 .fuse();
87 Ok(ArgminSlogLogger {
88 logger: slog::Logger::root(drain, o!()),
89 })
90 }
91}
92
93pub struct ArgminSlogKV {
95 pub kv: Vec<(&'static str, String)>,
97}
98
99impl KV for ArgminSlogKV {
100 fn serialize(&self, _record: &Record, serializer: &mut dyn Serializer) -> slog::Result {
101 for idx in self.kv.clone().iter().rev() {
102 serializer.emit_str(idx.0, &idx.1.to_string())?;
103 }
104 Ok(())
105 }
106}
107
108impl<O: ArgminOp> KV for IterState<O> {
109 fn serialize(&self, _record: &Record, serializer: &mut dyn Serializer) -> slog::Result {
110 serializer.emit_str(
111 "modify_func_count",
112 &self.get_modify_func_count().to_string(),
113 )?;
114 serializer.emit_str(
115 "hessian_func_count",
116 &self.get_hessian_func_count().to_string(),
117 )?;
118 serializer.emit_str(
119 "jacobian_func_count",
120 &self.get_jacobian_func_count().to_string(),
121 )?;
122 serializer.emit_str("grad_func_count", &self.get_grad_func_count().to_string())?;
123 serializer.emit_str("cost_func_count", &self.get_cost_func_count().to_string())?;
124 serializer.emit_str("best_cost", &self.get_best_cost().to_string())?;
125 serializer.emit_str("cost", &self.get_cost().to_string())?;
126 serializer.emit_str("iter", &self.get_iter().to_string())?;
127 Ok(())
128 }
129}
130
131impl<'a> From<&'a ArgminKV> for ArgminSlogKV {
132 fn from(i: &'a ArgminKV) -> ArgminSlogKV {
133 ArgminSlogKV { kv: i.kv.clone() }
134 }
135}
136
137impl<O: ArgminOp> Observe<O> for ArgminSlogLogger {
138 fn observe_init(&self, msg: &str, kv: &ArgminKV) -> Result<(), Error> {
140 info!(self.logger, "{}", msg; ArgminSlogKV::from(kv));
141 Ok(())
142 }
143
144 fn observe_iter(&mut self, state: &IterState<O>, kv: &ArgminKV) -> Result<(), Error> {
147 info!(self.logger, ""; state, ArgminSlogKV::from(kv));
148 Ok(())
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 send_sync_test!(argmin_slog_loggerv, ArgminSlogLogger);
157}