1 ! Copyright (C) 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: assocs calendar calendar.format combinators
4 concurrency.messaging continuations debugger destructors init io
5 io.directories io.encodings.utf8 io.files io.pathnames kernel
6 math math.parser ranges namespaces sequences strings threads ;
9 : log-root ( -- string )
10 \ log-root get-global [ "logs" resource-path ] unless* ;
12 : log-path ( service -- path )
13 log-root prepend-path ;
15 : log# ( path n -- path' )
16 number>string ".log" append append-path ;
20 : open-log-stream ( service -- stream )
23 [ 1 log# utf8 <file-appender> ] bi ;
25 : log-stream ( service -- stream )
26 log-files get [ open-log-stream ] cache ;
28 : close-log-streams ( -- )
29 log-files get [ values dispose-each ] [ clear-assoc ] bi ;
31 :: with-log-root ( path quot -- )
32 [ close-log-streams path \ log-root set-global quot call ]
34 [ \ log-root set-global close-log-streams ] curry
37 : timestamp-header. ( -- )
38 "[" write now write-rfc3339 "] " write ;
40 : multiline-header ( -- str ) 20 CHAR: - <string> ; foldable
42 : multiline-header. ( -- )
43 "[" write multiline-header write "] " write ;
45 :: write-message ( msg word-name level -- )
49 [ level write bl word-name write ": " write print ]
53 : (log-message) ( msg -- )
54 ! msg: { msg word-name level service }
55 first4 log-stream [ write-message flush ] with-output-stream* ;
57 : try-dispose ( obj -- )
58 [ dispose ] curry [ error. ] recover ;
60 : close-log ( service -- )
61 log-files get delete-at*
62 [ try-dispose ] [ drop ] if ;
66 [ values [ try-dispose ] each ] [ clear-assoc ] bi ;
68 CONSTANT: keep-logs 10
70 : delete-oldest ( service -- )
71 keep-logs log# ?delete-file ;
73 : ?move-file ( old new -- )
74 over file-exists? [ move-file ] [ 2drop ] if ;
76 : advance-log ( path n -- )
77 [ 1 - log# ] 2keep log# ?move-file ;
79 : rotate-log ( service -- )
84 [ keep-logs 1 [a..b] [ advance-log ] with each ] bi
87 : (rotate-logs) ( -- )
89 log-root directory-files [ rotate-log ] each ;
91 : log-server-loop ( -- )
93 { "log-message" [ (log-message) ] }
94 { "rotate-logs" [ drop (rotate-logs) ] }
95 { "close-logs" [ drop (close-logs) ] }
96 } case log-server-loop ;
102 [ error. (close-logs) ]
105 "Log server" spawn-server
106 "log-server" set-global ;
109 H{ } clone log-files set-global
111 ] "logging" add-startup-hook