Created
June 1, 2022 11:31
-
-
Save opqdonut/442a52464e76f376e2002567f0dbed29 to your computer and use it in GitHub Desktop.
Clojure structured logging via Log4J2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{:deps {org.apache.logging.log4j/log4j-api {:mvn/version "2.17.2"} | |
org.apache.logging.log4j/log4j-core {:mvn/version "2.17.2"} | |
org.apache.logging.log4j/log4j-layout-template-json {:mvn/version "2.17.2"} | |
org.apache.logging.log4j/log4j-slf4j18-impl {:mvn/version "2.17.2"}}} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns myproj.log | |
"Structured JSON logging via Log4J2. See resources/log4j2.xml for config." | |
(:import [org.apache.logging.log4j LogManager Logger Level] | |
[org.apache.logging.log4j.message MapMessage])) | |
(defn get-level [kw] | |
(case kw | |
:info Level/INFO | |
:warn Level/WARN | |
:error Level/ERROR)) | |
;; We need careful type hinting here to avoid reflection for the .log | |
;; call. Otherwise the source location of the log line is | |
;; clojure.lang.Reflector.invokeMatchingMethod instead of the actual | |
;; calling function. Likewise, we need the info/warn/error defs to be | |
;; macros that expand to actual calls to .log. If we wrap .log in a | |
;; helper function, that function will show up as the source of the | |
;; log line. | |
(defn- log-impl [level message payload throwable] | |
(if throwable | |
`(.log ^Logger (LogManager/getLogger ~(str *ns*)) | |
^Level (get-level ~level) | |
(MapMessage. (assoc ~payload "message" ~message)) | |
^Throwable ~throwable) | |
`(.log ^Logger (LogManager/getLogger ~(str *ns*)) | |
^Level (get-level ~level) | |
(MapMessage. (assoc ~payload "message" ~message))))) | |
(defmacro info [message payload & [throwable]] | |
(log-impl :info message payload throwable)) | |
(defmacro warn [message payload & [throwable]] | |
(log-impl :warn message payload throwable)) | |
(defmacro error [message payload & [throwable]] | |
(log-impl :error message payload throwable)) | |
(defn- logging-demo [] | |
(info "hello!" {:a 1 :foo "boing"}) | |
(info "new customer" {:address {:number 1 :street "Mannerheimintie"} :name "Pekka Pekkarinen"}) | |
(warn "unserializable" {:a (Object.)}) | |
(error "an exception!" {:meta "data"} (Error. "BOOM"))) | |
(comment | |
(logging-demo)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<Configuration status="WARN" monitorInterval="1"> | |
<Appenders> | |
<!-- Separate appenders for other Java logs and our logs. | |
Will allow fine-tuning the format of application logs in the future. --> | |
<Console name="gcp_default" target="SYSTEM_OUT" follow="true"> | |
<JsonTemplateLayout eventTemplateUri="classpath:GcpLayout.json" locationInfoEnabled="true" /> | |
</Console> | |
<Console name="gcp_custom" target="SYSTEM_OUT" follow="true"> | |
<JsonTemplateLayout eventTemplateUri="classpath:GcpLayout.json" locationInfoEnabled="true" > | |
<!-- Log structured MapMessages as JSON directly under the "message" key | |
instead of rendering them as key=value strings --> | |
<EventTemplateAdditionalField key="message" format="JSON" value='{"$resolver":"message"}'/> | |
</JsonTemplateLayout> | |
</Console> | |
</Appenders> | |
<Loggers> | |
<!-- Logging from Java libraries, either directly or via SLF4J --> | |
<Root level="info" includeLocation="true"> | |
<AppenderRef ref="gcp_default"/> | |
</Root> | |
<!-- Grab all log messages from an.* namespaces --> | |
<Logger name="myproj" level="info" additivity="false"> | |
<AppenderRef ref="gcp_custom"/> | |
</Logger> | |
<!-- REPL logging might originate from the user namespace --> | |
<Logger name="user" level="info" additivity="false"> | |
<AppenderRef ref="gcp_custom"/> | |
</Logger> | |
</Loggers> | |
</Configuration> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment