]> gitweb.factorcode.org Git - factor.git/blob - basis/logging/server/server.factor
d13ae616be54bdb1a25f4c59756191f68a29e943
[factor.git] / basis / logging / server / server.factor
1 ! Copyright (C) 2008 Slava Pestov.\r
2 ! See http://factorcode.org/license.txt for BSD license.\r
3 USING: namespaces kernel io calendar sequences io.files\r
4 io.sockets continuations destructors prettyprint assocs\r
5 math.parser words debugger math combinators\r
6 concurrency.messaging threads arrays init math.ranges strings\r
7 calendar.format io.encodings.utf8 ;\r
8 IN: logging.server\r
9 \r
10 : log-root ( -- string )\r
11     \ log-root get "logs" resource-path or ;\r
12 \r
13 : log-path ( service -- path )\r
14     log-root prepend-path ;\r
15 \r
16 : log# ( path n -- path' )\r
17     number>string ".log" append append-path ;\r
18 \r
19 SYMBOL: log-files\r
20 \r
21 : open-log-stream ( service -- stream )\r
22     log-path\r
23     dup make-directories\r
24     1 log# utf8 <file-appender> ;\r
25 \r
26 : log-stream ( service -- stream )\r
27     log-files get [ open-log-stream ] cache ;\r
28 \r
29 : multiline-header 20 CHAR: - <string> ; foldable\r
30 \r
31 : (write-message) ( msg name>> level multi? -- )\r
32     [\r
33         "[" write multiline-header write "] " write\r
34     ] [\r
35         "[" write now (timestamp>rfc3339) "] " write\r
36     ] if\r
37     write bl write ": " write print ;\r
38 \r
39 : write-message ( msg name>> level -- )\r
40     rot harvest {\r
41         { [ dup empty? ] [ 3drop ] }\r
42         { [ dup length 1 = ] [ first -rot f (write-message) ] }\r
43         [\r
44             [ first -rot f (write-message) ] 3keep\r
45             rest -rot [ t (write-message) ] 2curry each\r
46         ]\r
47     } cond ;\r
48 \r
49 : (log-message) ( msg -- )\r
50     #! msg: { msg name>> level service }\r
51     first4 log-stream [ write-message flush ] with-output-stream* ;\r
52 \r
53 : try-dispose ( stream -- )\r
54     [ dispose ] curry [ error. ] recover ;\r
55 \r
56 : close-log ( service -- )\r
57     log-files get delete-at*\r
58     [ try-dispose ] [ drop ] if ;\r
59 \r
60 : (close-logs) ( -- )\r
61     log-files get\r
62     dup values [ try-dispose ] each\r
63     clear-assoc ;\r
64 \r
65 : keep-logs 10 ;\r
66 \r
67 : ?delete-file ( path -- )\r
68     dup exists? [ delete-file ] [ drop ] if ;\r
69 \r
70 : delete-oldest ( service -- ) keep-logs log# ?delete-file ;\r
71 \r
72 : ?move-file ( old new -- )\r
73     over exists? [ move-file ] [ 2drop ] if ;\r
74 \r
75 : advance-log ( path n -- )\r
76     [ 1- log# ] 2keep log# ?move-file ;\r
77 \r
78 : rotate-log ( service -- )\r
79     dup close-log\r
80     log-path\r
81     dup delete-oldest\r
82     keep-logs 1 [a,b] [ advance-log ] with each ;\r
83 \r
84 : (rotate-logs) ( -- )\r
85     (close-logs)\r
86     log-root directory [ drop rotate-log ] assoc-each ;\r
87 \r
88 : log-server-loop ( -- )\r
89     receive unclip {\r
90         { "log-message" [ (log-message) ] }\r
91         { "rotate-logs" [ drop (rotate-logs) ] }\r
92         { "close-logs" [ drop (close-logs) ] }\r
93     } case log-server-loop ;\r
94 \r
95 : log-server ( -- )\r
96     [\r
97         init-namespaces\r
98         [ log-server-loop ]\r
99         [ error. (close-logs) ]\r
100         recover t\r
101     ]\r
102     "Log server" spawn-server\r
103     "log-server" set-global ;\r
104 \r
105 [\r
106     H{ } clone log-files set-global\r
107     log-server\r
108 ] "logging" add-init-hook\r