-
Notifications
You must be signed in to change notification settings - Fork 49
/
readable.clj
171 lines (149 loc) · 6.51 KB
/
readable.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
;; Copyright (c) Alex Taggart. All rights reserved. The use
;; and distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns ^{:author "Alex Taggart"
:doc "Logging macros that support printing message (some) arguments as
if wrapped in pr-str, the goal being to preserve their data representation
distinct from the explanatory text. See logp and logf for details regarding
which args are treated in this manner.
Examples:
(require '[clojure.tools.logging :as log]
'[clojure.tools.logging.readable :as logr])
(def x \"bar\")
; Logged as...
(log/debug \"foo\" x \"baz\") ; foo bar baz
(logr/debug \"foo\" x \"baz\") ; foo \"bar\" baz
(log/debugf \"foo %s %s\" x \"baz\") ; foo bar baz
(logr/debugf \"foo %s %s\" x \"baz\") ; foo \"bar\" \"baz\"
"}
clojure.tools.logging.readable
(:require [clojure.tools.logging :as log]
[clojure.tools.logging.impl :as impl]))
(defn- readable-print-args [args]
(for [arg args]
(if (string? arg)
arg
`(pr-str ~arg))))
(defmacro logp
"Logs a message using print style args, where message args that are not
literal strings will be printed readably, as if wrapped in pr-str. Can
optionally take a throwable as its second arg. See level-specific macros,
e.g., debug."
{:arglists '([level message & more] [level throwable message & more])}
[level x & more]
; Why bind `*print-readably*` to true?
; The `pr` functions do not bind `*print-readably*`, which defaults to true;
; instead the `print` functions bind `*print-readably*` to nil, then invoke
; `pr` functions.
; As such, absent explicit binding, if this code happened to be invoked in a
; context where `*print-readably*` was nil, then the non-string message args
; passed to pr-str would still not be printed readably.
(if (or (string? x) (nil? more)) ; optimize for non-exception case
`(log/log ~level (binding [*print-readably* true]
(print-str ~@(readable-print-args (cons x more)))))
`(let [logger# (impl/get-logger log/*logger-factory* ~*ns*)]
(if (impl/enabled? logger# ~level)
(let [x# ~x]
(if (instance? Throwable x#)
(log/log* logger# ~level x#
(binding [*print-readably* true]
(print-str ~@(readable-print-args more))))
(log/log* logger# ~level nil
(binding [*print-readably* true]
(print-str (pr-str x#) ; x is not a literal string, so pr-str x#
~@(readable-print-args more))))))))))
(defn- readable-format-args [args]
(for [arg args]
`(pr-str ~arg)))
(defmacro logf
"Logs a message using a format string and args, where all format args will be
printed readably, as if wrapped in pr-str. Can optionally take a throwable as
its second arg. See level-specific macros, e.g., debugf."
{:arglists '([level fmt & fmt-args] [level throwable fmt & fmt-args])}
[level x & more]
(if (or (instance? String x) (nil? more)) ; optimize for non-exception case
`(log/log ~level (binding [*print-readably* true]
(format ~x ~@(readable-format-args more))))
`(let [logger# (impl/get-logger log/*logger-factory* ~*ns*)]
(if (impl/enabled? logger# ~level)
(let [x# ~x]
(if (instance? Throwable x#) ; type check only when enabled
(log/log* logger# ~level x# (binding [*print-readably* true]
(format ~(first more) ; not applied to the format string
~@(readable-format-args (rest more)))))
(log/log* logger# ~level nil (binding [*print-readably* true]
(format x# ~@(readable-format-args more))))))))))
;; level-specific macros
(defmacro trace
"Trace level logging using print-style args. See logp for details."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :trace ~@args))
(defmacro debug
"Debug level logging using print-style args. See logp for details."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :debug ~@args))
(defmacro info
"Info level logging using print-style args. See logp for details."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :info ~@args))
(defmacro warn
"Warn level logging using print-style args. See logp for details."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :warn ~@args))
(defmacro error
"Error level logging using print-style args. See logp for details."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :error ~@args))
(defmacro fatal
"Fatal level logging using print-style args. See logp for details."
{:arglists '([message & more] [throwable message & more])}
[& args]
`(logp :fatal ~@args))
(defmacro tracef
"Trace level logging using format. See logf for details."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :trace ~@args))
(defmacro debugf
"Debug level logging using format. See logf for details."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :debug ~@args))
(defmacro infof
"Info level logging using format. See logf for details."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :info ~@args))
(defmacro warnf
"Warn level logging using format. See logf for details."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :warn ~@args))
(defmacro errorf
"Error level logging using format. See logf for details."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :error ~@args))
(defmacro fatalf
"Fatal level logging using format. See logf for details."
{:arglists '([fmt & fmt-args] [throwable fmt & fmt-args])}
[& args]
`(logf :fatal ~@args))
(defmacro spyf
"Evaluates expr and may write (logf level fmt result) to the log. Returns the
result of expr. Defaults to :debug log level."
([fmt expr]
`(spyf :debug ~fmt ~expr))
([level fmt expr]
`(let [a# ~expr]
(logf ~level ~fmt a#)
a#)))