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
use linked_hash_map::LinkedHashMap;
use log::LogRecord;
use log4rs::append::Append;
use std::error::Error;
use std::fmt;
use std::sync::Arc;
use std::time::{Duration, Instant};
#[cfg(feature = "file")]
use log4rs::file::Deserializable;
use {CacheInner, AppenderInner};
#[cfg(feature = "pattern-router")]
pub mod pattern;
struct TrackedAppender {
appender: Appender,
used: Instant,
}
pub struct Cache {
map: LinkedHashMap<String, TrackedAppender>,
ttl: Duration,
}
impl CacheInner for Cache {
fn new(ttl: Duration) -> Cache {
Cache {
map: LinkedHashMap::new(),
ttl: ttl,
}
}
}
impl Cache {
pub fn entry<'a>(&'a mut self, key: String) -> Entry<'a> {
let now = Instant::now();
self.purge(now);
let entry = match self.map.get_refresh(&key) {
Some(entry) => {
entry.used = now;
Some(Appender(entry.appender.0.clone()))
}
None => None,
};
match entry {
Some(appender) => Entry::Occupied(OccupiedEntry(self, appender)),
None => {
Entry::Vacant(VacantEntry {
cache: self,
key: key,
time: now,
})
}
}
}
fn purge(&mut self, now: Instant) {
let timeout = now - self.ttl;
loop {
match self.map.front() {
Some((_, v)) if v.used <= timeout => {}
_ => break,
}
self.map.pop_front();
}
}
}
pub enum Entry<'a> {
Occupied(OccupiedEntry<'a>),
Vacant(VacantEntry<'a>),
}
impl<'a> Entry<'a> {
pub fn or_insert_with<F>(self, f: F) -> Appender
where F: FnOnce() -> Box<Append>
{
match self {
Entry::Occupied(e) => e.into_value(),
Entry::Vacant(e) => e.insert(f()),
}
}
}
pub struct OccupiedEntry<'a>(&'a mut Cache, Appender);
impl<'a> OccupiedEntry<'a> {
pub fn into_value(self) -> Appender {
self.1
}
}
pub struct VacantEntry<'a> {
cache: &'a mut Cache,
key: String,
time: Instant,
}
impl<'a> VacantEntry<'a> {
pub fn insert(self, value: Box<Append>) -> Appender {
let appender = Arc::new(value);
let tracked = TrackedAppender {
appender: Appender(appender.clone()),
used: self.time,
};
self.cache.map.insert(self.key, tracked);
Appender(appender)
}
}
pub struct Appender(Arc<Box<Append>>);
impl AppenderInner for Appender {
fn appender(&self) -> &Append {
&**self.0
}
}
pub trait Route: fmt::Debug + 'static + Sync + Send {
fn route(&self, record: &LogRecord, cache: &mut Cache) -> Result<Appender, Box<Error + Sync + Send>>;
}
#[cfg(feature = "file")]
impl Deserializable for Route {
fn name() -> &'static str {
"router"
}
}