forked from riemann/riemann
-
Notifications
You must be signed in to change notification settings - Fork 0
/
logging.clj
221 lines (196 loc) · 8.18 KB
/
logging.clj
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
(ns riemann.logging
(:import (org.slf4j
LoggerFactory)
(ch.qos.logback.classic
Level
Logger)
(ch.qos.logback.core
ConsoleAppender
FileAppender)
(ch.qos.logback.core.util
FileSize)
(ch.qos.logback.core.encoder
LayoutWrappingEncoder)
(ch.qos.logback.core.rolling
RollingFileAppender
TimeBasedRollingPolicy
FixedWindowRollingPolicy
SizeBasedTriggeringPolicy)
(ch.qos.logback.classic.encoder
PatternLayoutEncoder)
(java.net URL)
(ch.qos.logback.classic.joran JoranConfigurator))
(:require wall.hack))
(defn get-logger
([]
(LoggerFactory/getLogger Logger/ROOT_LOGGER_NAME))
([logger]
(LoggerFactory/getLogger logger)))
(defn- get-context
[]
(LoggerFactory/getILoggerFactory))
(defmulti encoder identity)
(defmethod encoder :riemann
[type]
(doto (PatternLayoutEncoder.)
(.setPattern "%p [%d] %t - %c - %m%n%throwable")))
(defmethod encoder :default
[type]
(binding [*out* *err*]
(println "invalid logging layout specified: " type))
(encoder :riemann))
(defn set-level
"Set the level for the given logger, by string name.
Example:
(set-level Level/INFO)
or
(set-level \"riemann.client\", Level/DEBUG)"
([level]
(. (get-logger)
(setLevel level)))
([logger level]
(. (get-logger logger)
(setLevel level))))
(defmacro suppress
"Turns off logging for the evaluation of body."
[loggers & body]
(let [[logger & more] (flatten [loggers])]
(if logger
`(let [old-level# (.getLevel (get-logger ~logger))]
(try
(set-level ~logger Level/ERROR)
(suppress ~more ~@body)
(finally
(set-level ~logger old-level#))))
`(do ~@body))))
(defn configure-from-file
"Configure logging from a configuration file"
[context config-file]
(doto (JoranConfigurator.)
(.setContext context)
(.doConfigure (URL. config-file))))
(defn configure-from-opts
"Configure logging from opts"
[logger context opts]
(let [{:keys [console?
console-layout
file
file-layout
files
rotate-count
logsize-rotate]
:or {console? true
console-layout :riemann
file-layout :riemann}} opts]
(do
(when console?
(let [encoder (doto (encoder console-layout)
(.setContext context)
(.start))
console-appender (doto (ConsoleAppender.)
(.setContext context)
(.setEncoder encoder)
(.start))]
(.addAppender logger console-appender)))
(doseq [{:keys [file file-layout]}
(conj files {:file file :file-layout file-layout})
:when file]
(if logsize-rotate
(let [encoder (doto (encoder file-layout)
(.setContext context)
(.start))
log-appender (doto (RollingFileAppender.)
(.setFile file)
(.setContext context)
(.setEncoder encoder))
rolling-policy (doto (FixedWindowRollingPolicy.)
(.setMinIndex 1)
(.setMaxIndex (or rotate-count 10))
(.setFileNamePattern
(str file ".%i"))
(.setParent log-appender)
(.setContext context)
(.start))
triggering-policy (doto (SizeBasedTriggeringPolicy.)
(.setMaxFileSize (FileSize. logsize-rotate))
(.setContext context)
(.start))
log-appender (doto log-appender
(.setRollingPolicy rolling-policy)
(.setTriggeringPolicy triggering-policy)
(.start))]
(.addAppender logger log-appender))
(let [encoder (doto (encoder file-layout)
(.setContext context)
(.start))
log-appender (doto (RollingFileAppender.)
(.setFile file)
(.setContext context)
(.setEncoder encoder))
rolling-policy (doto (TimeBasedRollingPolicy.)
(.setMaxHistory (or rotate-count 10))
(.setFileNamePattern
(str file ".%d{yyyy-MM-dd}"))
(.setParent log-appender)
(.setContext context)
(.start))
log-appender (doto log-appender
(.setRollingPolicy rolling-policy)
(.start))]
(.addAppender logger log-appender))))
(set-level Level/INFO)
(set-level "riemann.client" Level/DEBUG)
(set-level "riemann.server" Level/DEBUG)
(set-level "riemann.streams" Level/DEBUG)
(set-level "riemann.graphite" Level/DEBUG))))
(defn init
"Initialize logging. You will probably call this from the config file. You can
call init more than once; its changes are destructive. Options:
- :console? Determine if logging should happen on the console.
- :console-layout Specifying console layout.
- :file The file to log to. If omitted, log to console only.
- :file-layout Specifying file layout.
- :files A list of files to log to. If provided, a seq or vector is
expected containing maps with a :file and an :file-layout
- :logsize-rotate If size (in bytes) is specified use size based rotation
otherwise use default time based rotation.
- :rotate-count Specifying the number of rotated files to keep. If omitted,
keep last 10 rotated files.
Layout can be :riemann or :json. If layout is omitted, the default layout
:riemann will be used.
For example:
```clojure
; Basic console logging
(init)
; Also log to a file
(init {:file \"/var/log/riemann.log\"})
; With rotation
(init {:console? false :file \"/var/log/riemann.log\" :rotate-count 10})
; Rotate at a certain size
(init {:console? false
:file \"/var/log/riemann.log\"
:logsize-rotate 1000000000})
; Multiple files in different formats
(init {:console? false
:files [{:file \"/var/log/riemann.log\"},
{:file \"/var/log/riemann.json.log\" :file-layout :json}]
:logsize-rotate 100
:rotate-count 5})
```"
([] (init {}))
([opts]
(let [logger (get-logger)
context (get-context)]
(.detachAndStopAllAppenders logger)
(if-let [config-file (System/getProperty "logback.configurationFile")]
(configure-from-file context config-file)
(configure-from-opts logger context opts)))))
(defn nice-syntax-error
"Rewrites clojure.lang.LispReader$ReaderException to have error messages that
might actually help someone."
([e] (nice-syntax-error e "(no file)"))
([e file]
; Lord help me.
(let [line (wall.hack/field (class e) :line e)
msg (.getMessage (or (.getCause e) e))]
(RuntimeException. (str "Syntax error (" file ":" line ") " msg)))))