@@ -15,7 +15,6 @@ use crate::db::filename::{generate_filename, FileType};
15
15
use crate :: error:: Result ;
16
16
use crate :: storage:: { File , Storage } ;
17
17
18
-
19
18
use log:: { LevelFilter , Log , Metadata , Record } ;
20
19
use slog:: { o, Drain , Level } ;
21
20
@@ -26,12 +25,11 @@ use std::sync::Mutex;
26
25
///
27
26
/// See `slog` at https://github.com/slog-rs/slog
28
27
/// See `log` at https://github.com/rust-lang/log
29
- ///
28
+ ///
30
29
31
- pub fn create_file < S : Storage > ( storage : & S , db_path : & str , timestamp : i64 ) -> Result < S :: F > {
32
- let new_path = generate_filename ( db_path, FileType :: Log , timestamp as u64 ) ;
33
- storage. create ( new_path)
34
-
30
+ pub fn create_file < S : Storage > ( storage : & S , db_path : & str , timestamp : i64 ) -> Result < S :: F > {
31
+ let log_path = generate_filename ( db_path, FileType :: Log , timestamp as u64 ) ;
32
+ storage. create ( log_path)
35
33
}
36
34
37
35
pub struct Logger {
@@ -46,10 +44,10 @@ impl Logger {
46
44
/// If `inner` is `None`
47
45
/// - In dev mode, use a std output
48
46
/// - In release mode, use a storage specific file with name `LOG`
49
- pub fn new < S : Storage + Clone + ' static > (
47
+ pub fn new < S : Storage + Clone + ' static > (
50
48
inner : Option < slog:: Logger > ,
51
49
level : LevelFilter ,
52
- storage : S ,
50
+ storage : S ,
53
51
db_path : & ' static str ,
54
52
) -> Self {
55
53
let inner = match inner {
@@ -62,14 +60,12 @@ impl Logger {
62
60
slog:: Logger :: root ( drain, o ! ( ) )
63
61
} else {
64
62
// Use a file `Log` to record all logs
65
- // TODO: add file rotation
66
- //db_path 是generate_filename
67
- let file = create_file ( & storage, db_path, Local :: now ( ) . timestamp ( ) ) . unwrap ( ) ;
68
- let file_fn = move |path : String | { create_file ( & storage,
69
- path. as_str ( ) , Local :: now ( ) . timestamp ( ) ) } ;
70
- let drain =FileBasedDrain :: new ( file, db_path,
71
- file_fn)
72
- . add_rotator ( RotatedFileBySize :: new ( 1 ) ) ;
63
+ let file = create_file ( & storage, db_path, Local :: now ( ) . timestamp ( ) ) . unwrap ( ) ;
64
+ let file_fn = move |path : String | {
65
+ create_file ( & storage, path. as_str ( ) , Local :: now ( ) . timestamp ( ) )
66
+ } ;
67
+ let drain = FileBasedDrain :: new ( file, db_path, file_fn)
68
+ . add_rotator ( RotatedFileBySize :: new ( 1 ) ) ;
73
69
let drain = slog_async:: Async :: new ( drain) . build ( ) . fuse ( ) ;
74
70
slog:: Logger :: root ( drain, o ! ( ) )
75
71
}
@@ -130,56 +126,56 @@ fn log_to_slog_level(level: log::Level) -> Level {
130
126
}
131
127
}
132
128
133
- struct FileBasedDrain < F : File > {
129
+ struct FileBasedDrain < F : File > {
134
130
inner : Mutex < F > ,
135
131
rotators : Vec < Box < dyn Rotator > > ,
136
- db_path : String ,
137
- new_file : Box < dyn Send + Fn ( String ) -> Result < F > >
132
+ db_path : String ,
133
+ new_file : Box < dyn Send + Fn ( String ) -> Result < F > > ,
138
134
}
139
135
140
- impl < F : File > FileBasedDrain < F > {
141
- fn new < H > ( f : F , path : & str , new_file : H ) -> Self
142
- where H : ' static +Send +Fn ( String ) ->Result < F >
143
- {
136
+ impl < F : File > FileBasedDrain < F > {
137
+ fn new < H > ( f : F , path : & str , new_file : H ) -> Self
138
+ where
139
+ H : ' static + Send + Fn ( String ) -> Result < F > ,
140
+ {
144
141
FileBasedDrain {
145
142
db_path : path. to_string ( ) ,
146
143
inner : Mutex :: new ( f) ,
147
144
rotators : vec ! [ ] ,
148
- new_file : Box :: new ( new_file)
145
+ new_file : Box :: new ( new_file) ,
149
146
}
150
147
}
151
148
152
-
153
- fn add_rotator < R : ' static +Rotator > ( mut self , rotator : R ) -> Self {
149
+ fn add_rotator < R : ' static + Rotator > ( mut self , rotator : R ) -> Self {
154
150
if rotator. is_enabled ( ) {
155
151
self . rotators . push ( Box :: new ( rotator) ) ;
156
152
}
157
- for rotator in ( & self ) . rotators . iter ( ) {
153
+ for rotator in self . rotators . iter ( ) {
158
154
rotator. prepare ( & * self . inner . lock ( ) . unwrap ( ) ) . unwrap ( ) ;
159
155
}
160
156
self
161
157
}
162
158
163
- fn flush ( & self ) -> Result < ( ) > {
164
- // use crate::storage::file::FileStorage;
165
- // let storage = FileStorage::default();
159
+ fn flush ( & self ) -> Result < ( ) > {
166
160
for rotator in self . rotators . iter ( ) {
167
- if rotator. should_rotate ( ) {
168
- // let _ = storage.rename("log/000000.log","log/000000.log");
161
+ if rotator. should_rotate ( ) {
169
162
let new_file = ( self . new_file ) ( self . db_path . clone ( ) ) . unwrap ( ) ;
163
+
170
164
let mut old_file = self . inner . lock ( ) . unwrap ( ) ;
171
- * old_file =new_file;
172
-
165
+ * old_file = new_file;
166
+
173
167
for rotator in self . rotators . iter ( ) {
174
168
rotator. on_rotate ( ) ;
175
169
}
170
+
176
171
return Ok ( ( ) ) ;
177
- }
178
172
}
173
+ }
174
+
179
175
self . inner . lock ( ) . unwrap ( ) . flush ( )
180
176
}
181
177
}
182
- impl < F : File > Drain for FileBasedDrain < F > {
178
+ impl < F : File > Drain for FileBasedDrain < F > {
183
179
type Ok = ( ) ;
184
180
type Err = slog:: Never ;
185
181
@@ -194,23 +190,20 @@ impl<F:File> Drain for FileBasedDrain<F> {
194
190
record. msg( ) ,
195
191
values
196
192
) ;
197
-
198
193
199
- for rotator in self . rotators . iter ( ) {
200
- rotator. on_write ( by. as_bytes ( ) ) . unwrap ( ) ;
194
+ for rotator in self . rotators . iter ( ) {
195
+ rotator. on_write ( by. as_bytes ( ) ) . unwrap ( ) ;
201
196
}
202
-
203
- let _f = self . flush ( ) . unwrap ( ) ;
197
+
198
+ self . flush ( ) . unwrap ( ) ;
204
199
205
200
//Ignore errors here
206
201
let _ = self . inner . lock ( ) . unwrap ( ) . write ( by. as_bytes ( ) ) ;
207
-
202
+
208
203
Ok ( ( ) )
209
204
}
210
205
}
211
206
212
-
213
-
214
207
trait Rotator : Send {
215
208
/// Check if the option is enabled in configuration.
216
209
/// Return true if the `rotator` is valid.
@@ -224,7 +217,7 @@ trait Rotator: Send {
224
217
225
218
fn on_write ( & self , buf : & [ u8 ] ) -> Result < ( ) > ;
226
219
// Call by operator, update rotators' state while the operator execute a rotation.
227
- fn on_rotate ( & self ) ;
220
+ fn on_rotate ( & self ) ;
228
221
}
229
222
230
223
struct RotatedFileBySize {
@@ -245,10 +238,9 @@ impl Rotator for RotatedFileBySize {
245
238
fn is_enabled ( & self ) -> bool {
246
239
self . rotation_size != 0
247
240
}
248
- fn prepare ( & self , file : & dyn File ) -> Result < ( ) > {
241
+ fn prepare ( & self , file : & dyn File ) -> Result < ( ) > {
249
242
* self . file_size . lock ( ) . unwrap ( ) = file. len ( ) . unwrap ( ) ;
250
243
Ok ( ( ) )
251
-
252
244
}
253
245
254
246
fn should_rotate ( & self ) -> bool {
@@ -259,7 +251,7 @@ impl Rotator for RotatedFileBySize {
259
251
Ok ( ( ) )
260
252
}
261
253
262
- fn on_rotate ( & self ) {
254
+ fn on_rotate ( & self ) {
263
255
* self . file_size . lock ( ) . unwrap ( ) = 0 ;
264
256
}
265
257
}
@@ -268,52 +260,75 @@ impl Rotator for RotatedFileBySize {
268
260
mod tests {
269
261
270
262
use super :: * ;
271
- use crate :: storage:: mem:: MemStorage ;
272
263
use crate :: storage:: file:: FileStorage ;
273
- use slog:: info;
274
- use std:: fs;
275
- use std:: thread;
276
- use std:: time:: Duration ;
264
+ use crate :: storage:: mem:: MemStorage ;
277
265
use std:: path:: Path ;
266
+ use std:: thread;
267
+ use std:: time:: Duration ;
278
268
279
- fn file_exists ( file : impl AsRef < Path > , storage : FileStorage ) -> bool {
269
+ fn file_exists ( file : impl AsRef < Path > , storage : impl Storage ) -> bool {
280
270
storage. exists ( file)
281
271
}
282
- // #[test]
283
- // fn test_default_logger() {
284
- // let s =MemStorage::default();
285
- // // let s = &'static s;
286
- // let db_path = "test";
287
- // let logger = Logger::new(None, LevelFilter::Debug, s, db_path);
288
- // // Ignore the error if the logger have been set
289
- // let _ = log::set_logger(Box::leak(Box::new(logger)));
290
- // log::set_max_level(LevelFilter::Debug);
291
- // self::info!(,"Hello World");
292
- // // Wait for the async logger print the result
293
- // thread::sleep(Duration::from_millis(100));
294
- // }
295
-
272
+
296
273
#[ test]
297
- fn test_rotate_by_size ( ) {
274
+ fn test_default_logger ( ) {
275
+ let s = MemStorage :: default ( ) ;
276
+ // let s = &'static s;
277
+ let db_path = "test" ;
278
+ let logger = Logger :: new ( None , LevelFilter :: Debug , s, db_path) ;
279
+ // Ignore the error if the logger have been set
280
+ let _ = log:: set_logger ( Box :: leak ( Box :: new ( logger) ) ) ;
281
+ log:: set_max_level ( LevelFilter :: Debug ) ;
282
+ log:: info!( "Hello World" ) ;
283
+ // Wait for the async logger print the result
284
+ thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
285
+ }
286
+
287
+ #[ test]
288
+ fn test_rotate_by_size ( ) {
298
289
let db_path = "log" ;
299
-
290
+
300
291
let storage = FileStorage :: default ( ) ;
301
- let _= storage. mkdir_all ( db_path) ;
302
- let storage2 = storage. clone ( ) ;
303
- let file= create_file ( & storage, db_path, 0 ) . unwrap ( ) ;
304
- let new_path = generate_filename ( db_path, FileType :: Log , 1 ) ;
305
-
306
-
307
-
308
- let file_fn = move |path : String | { create_file ( & storage,
309
- path. as_str ( ) , 1 ) } ;
310
-
311
- let drain =FileBasedDrain :: new ( file, db_path, file_fn)
312
- . add_rotator ( RotatedFileBySize :: new ( 1 ) ) ;
313
- let drain = slog_async:: Async :: new ( drain) . build ( ) . fuse ( ) ;
314
- let _log = slog:: Logger :: root ( drain, o ! ( ) ) ;
315
- self :: info!( _log, "Test log file rotated by size" ) ;
316
-
317
- assert ! ( file_exists( new_path, FileStorage :: default ( ) ) ) ;
292
+
293
+ let _ = storage. mkdir_all ( db_path) ;
294
+ let file = create_file ( & storage, db_path, 0 ) . unwrap ( ) ;
295
+ let new_path = generate_filename ( db_path, FileType :: Log , 1 ) ;
296
+
297
+ {
298
+ let file_fn = move |path : String | create_file ( & storage, path. as_str ( ) , 1 ) ;
299
+
300
+ let drain =
301
+ FileBasedDrain :: new ( file, db_path, file_fn) . add_rotator ( RotatedFileBySize :: new ( 1 ) ) ;
302
+ let drain = slog_async:: Async :: new ( drain) . build ( ) . fuse ( ) ;
303
+ let _log = slog:: Logger :: root ( drain, o ! ( ) ) ;
304
+ slog:: info!( _log, "Test log file rotated by size" ) ;
305
+ }
306
+ assert_eq ! ( true , file_exists( new_path, FileStorage :: default ( ) ) ) ;
307
+ }
308
+
309
+ #[ test]
310
+ fn test_not_rotate_by_size ( ) {
311
+ let db_path = "norotate" ;
312
+
313
+ let storage = FileStorage :: default ( ) ;
314
+
315
+ let _ = storage. mkdir_all ( db_path) ;
316
+ let file = create_file ( & storage, db_path, 0 ) . unwrap ( ) ;
317
+ let new_path = generate_filename ( db_path, FileType :: Log , 1 ) ;
318
+
319
+ {
320
+ let file_fn = move |path : String | create_file ( & storage, path. as_str ( ) , 1 ) ;
321
+
322
+ let drain = FileBasedDrain :: new ( file, db_path, file_fn)
323
+ . add_rotator ( RotatedFileBySize :: new ( 100 ) ) ;
324
+ let drain = slog_async:: Async :: new ( drain) . build ( ) . fuse ( ) ;
325
+ let _log = slog:: Logger :: root ( drain, o ! ( ) ) ;
326
+ slog:: info!( _log, "Test log file rotated by size" ) ;
327
+ }
328
+ assert_eq ! (
329
+ true ,
330
+ file_exists( "norotate/000000.log" , FileStorage :: default ( ) )
331
+ ) ;
332
+ assert_eq ! ( false , file_exists( new_path, FileStorage :: default ( ) ) ) ;
318
333
}
319
334
}
0 commit comments