### Log4j2 Configuration Example Source: https://github.com/clojure/tools.logging/blob/master/README.md A basic Log4j2 configuration file. Ensure the pattern layout includes %throwable to print data maps for exceptions. ```properties status = warn monitorInterval = 5 appender.console.type = Console appender.console.name = STDOUT appender.console.layout.type = PatternLayout appender.console.layout.pattern = %date %level %logger %message%n%throwable rootLogger.level = info rootLogger.appenderRef.stdout.ref = STDOUT ``` -------------------------------- ### `log-capture!` / `log-uncapture!` — Redirect System.out and System.err to Log Source: https://context7.com/clojure/tools.logging/llms.txt These functions allow you to redirect Java's `System.out` and `System.err` streams to the logging system. `log-capture!` starts the redirection for a given logger namespace, and `log-uncapture!` restores the original streams. ```APIDOC ## `log-capture!` / `log-uncapture!` — Redirect System.out and System.err to Log Captures Java's `System.out` and `System.err` streams, routing all output to the log under a given logger namespace. ### Usage ```clojure (require '[clojure.tools.logging :as log]) ;; Capture with defaults (:info for stdout, :error for stderr) (log/log-capture! 'myapp.stdout) ;; All System.out/System.err writes now go to the log (println "This goes to :info log under myapp.stdout") (.println System/err "This goes to :error log under myapp.stdout") ;; Restore originals (log/log-uncapture!) ;; Capture with custom levels (log/log-capture! 'myapp.legacy :debug :warn) ;; stdout => :debug, stderr => :warn ``` ``` -------------------------------- ### Configure SLF4J Backend via deps.edn Source: https://context7.com/clojure/tools.logging/llms.txt Set the `clojure.tools.logging.factory` JVM system property within a `:jvm-opts` alias in your `deps.edn` file to force the SLF4J backend. ```clojure {:aliases {:dev {:jvm-opts ["-Dclojure.tools.logging.factory=clojure.tools.logging.impl/slf4j-factory"]}}} ``` -------------------------------- ### Maven Dependency Source: https://github.com/clojure/tools.logging/blob/master/README.md Add this to your pom.xml file to include the tools.logging library. ```xml org.clojure tools.logging 1.3.1 ``` -------------------------------- ### Leiningen Dependency Source: https://github.com/clojure/tools.logging/blob/master/README.md Add this to your project.clj file to include the tools.logging library. ```clojure [org.clojure/tools.logging "1.3.1"] ``` -------------------------------- ### Clojure CLI/deps.edn Dependency Source: https://github.com/clojure/tools.logging/blob/master/README.md Add this to your deps.edn file to include the tools.logging library. ```clojure org.clojure/tools.logging {:mvn/version "1.3.1"} ``` -------------------------------- ### Level-Specific Format Macros Source: https://context7.com/clojure/tools.logging/llms.txt Utilize format-string variants like `infof`, `warnf`, `errorf` for structured logging, similar to `clojure.core/format`. An optional Throwable can be included. ```clojure (require '[clojure.tools.logging :as log]) ;; Format string with args (log/infof "User %s logged in from %s" "alice" "192.168.1.1") ;; => logs: "User alice logged in from 192.168.1.1" ``` ```clojure ;; With exception (try (parse-int "not-a-number") (catch Exception e (log/warnf e "Failed to parse value: %s" "not-a-number"))) ;; => logs warning with exception attached ``` ```clojure ;; Useful for structured numeric formatting (log/debugf "Processed %d records in %.2f ms" 1500 42.7) ;; => logs: "Processed 1500 records in 42.70 ms" ``` -------------------------------- ### Format-String Logging Macro (`logf`) Source: https://context7.com/clojure/tools.logging/llms.txt Use `logf` for low-level format-string logging with an explicit level. It serves as the base for other formatted logging functions. It supports logging with an optional throwable. ```clojure (require '[clojure.tools.logging :as log]) (log/logf :warn "Retry %d/%d for host %s" 2 5 "db-primary") ;; => logs: "Retry 2/5 for host db-primary" ;; With throwable (log/logf :error (ex-info "Timeout" {:host "db-primary"}) "Connection failed to %s after %d ms" "db-primary" 5000) ``` -------------------------------- ### Add clojure.tools.logging Dependency Source: https://context7.com/clojure/tools.logging/llms.txt Specify clojure.tools.logging as a dependency in your build tool configuration. ```clojure ;; deps.edn {:deps {org.clojure/tools.logging {:mvn/version "1.3.1"}}} ``` ```clojure ;; Leiningen project.clj [org.clojure/tools.logging "1.3.1"] ``` ```xml org.clojure tools.logging 1.3.1 ``` -------------------------------- ### Force SLF4J Backend in project.clj Source: https://context7.com/clojure/tools.logging/llms.txt Configure your project to use the SLF4J backend by setting the `clojure.tools.logging.factory` JVM system property in `project.clj`. ```clojure ;; project.clj — force SLF4J backend :jvm-opts ["-Dclojure.tools.logging.factory=clojure.tools.logging.impl/slf4j-factory"] ``` -------------------------------- ### General Logging Macro `log` Source: https://context7.com/clojure/tools.logging/llms.txt The foundational `log` macro allows specifying the log level, logger namespace, and factory overrides. It supports messages and optional Throwables. ```clojure (require '[clojure.tools.logging :as log]) ;; Basic form: (log level message) (log/log :info "Application initialized") ``` ```clojure ;; With throwable: (log level throwable message) (log/log :error (ex-info "Bad input" {:input nil}) "Validation failed") ``` ```clojure ;; With explicit namespace: (log logger-ns level throwable message) (log/log 'myapp.subsystem :warn nil "Subsystem degraded") ``` ```clojure ;; With explicit factory: (log logger-factory logger-ns level throwable message) (log/log log/*logger-factory* *ns* :debug nil "Custom factory logging") ``` -------------------------------- ### Level-Specific Print-Style Logging Macros Source: https://context7.com/clojure/tools.logging/llms.txt Use convenience macros like `info`, `error`, `debug`, `fatal` for logging messages with optional Throwables. Message arguments are evaluated lazily. ```clojure (require '[clojure.tools.logging :as log]) ;; Simple message (log/info "Server started on port" 8080) ;; => logs: "Server started on port 8080" ``` ```clojure ;; With a Throwable as first arg (try (/ 1 0) (catch Exception e (log/error e "Unhandled error during request processing"))) ;; => logs: "Unhandled error during request processing" with stack trace ``` ```clojure ;; Multiple args are joined with spaces (log/debug "Request" {:method :GET :path "/api/users"} "from" "127.0.0.1") ;; => logs: "Request {:method :GET, :path \"/api/users\"} from 127.0.0.1" ``` ```clojure ;; Fatal level — used for unrecoverable states (log/fatal "Database connection pool exhausted — shutting down") ``` -------------------------------- ### `clojure.tools.logging.readable` — Readable Print Variants Source: https://context7.com/clojure/tools.logging/llms.txt This namespace provides drop-in replacements for the standard logging macros. Its key feature is that non-string arguments are printed using `pr-str`, which preserves their Clojure data representation in the log output. ```APIDOC ## `clojure.tools.logging.readable` — Readable Print Variants A drop-in namespace providing variants of all logging macros where non-string arguments are printed via `pr-str`, preserving their Clojure data representation in log output. ### Usage ```clojure (require '[clojure.tools.logging :as log] '[clojure.tools.logging.readable :as logr]) (def user {:name "alice" :roles #{:admin :user}}) ;; Standard logging — values printed with print-str (no quotes on strings) (log/info "User:" user) ;; => logs: "User: {:name alice, :roles #{:admin :user}}" ;; Readable logging — values printed with pr-str (preserves data types) (logr/info "User:" user) ;; => logs: "User: {:name \"alice\", :roles #{:admin :user}}" ;; Readable format — all format args are pr-str'd (log/debugf "Value: %s" "hello") ;; => "Value: hello" (logr/debugf "Value: %s" "hello") ;; => "Value: \"hello\"" ;; With throwable (logr/error (ex-info "Failed" {:code 404}) "Response was:" {:status 404 :body "Not Found"}) ;; => logs with exception and readable map representation ``` ``` -------------------------------- ### Testing Log Output with clojure.tools.logging.test Source: https://context7.com/clojure/tools.logging/llms.txt Use `with-log`, `logged?`, `matches`, and `the-log` for asserting log messages in unit tests. `logged?` supports exact message, regex, and exception type matching. `matches` returns matching entries, and `the-log` inspects all captured entries. ```clojure (require '[clojure.tools.logging :as log] '[clojure.tools.logging.test :refer [logged? matches the-log with-log]] '[clojure.test :refer [deftest is]]) (deftest test-logging-behavior (with-log ;; Execute code under test (log/info "Hello World!") (log/error (Exception. "Something went wrong") "Error occurred") (log/debug "Detail" {:key "value"}) ;; logged? — boolean assertion (is (logged? 'user :info #"Hello")) ; regex match on message (is (logged? 'user :info "Hello World!")) ; exact message match (is (logged? 'user :error ; match exception type + message pattern [Exception #"went wrong"] #"Error")) (is (not (logged? 'user :debug "Detail"))) ; default: all levels enabled, so this IS logged ;; matches — returns matching entries or nil (is (seq (matches 'user :info #"Hello"))) ;; the-log — inspect all captured entries (let [entries (the-log)] (is (= 3 (count entries))) (is (= :info (:level (first entries))))))) ;; Test with namespace predicate (with-log (log/info "msg") (logged? #(= (str %) "user") :info "msg")) ; fn predicate for namespace ``` -------------------------------- ### Log and Return an Expression (`spy`) Source: https://context7.com/clojure/tools.logging/llms.txt Use `spy` to evaluate an expression, log its form and result at a specified level (defaults to :debug), and return the result. It's ideal for inline debugging. ```clojure (require '[clojure.tools.logging :as log]) ;; Default :debug level — logs form and result, returns value (def result (log/spy (+ 1 2))) ;; => logs: "(+ 1 2)\n=> 3" ;; result => 3 ;; Explicit level (defn process [items] (->> items (log/spy :info (filter odd? items)) (map inc))) ;; Inline in threading pipelines (-> {:user "alice" :role :admin} (log/spy :debug) (assoc :logged-at (java.time.Instant/now))) ``` -------------------------------- ### Print-Style Logging Macro `logp` Source: https://context7.com/clojure/tools.logging/llms.txt The low-level `logp` macro takes an explicit level as the first argument, followed by messages and an optional exception. It forms the basis for other print-style macros. ```clojure (require '[clojure.tools.logging :as log]) ;; Level as first arg (log/logp :info "Processing batch" 42 "of" 100) ;; => logs: "Processing batch 42 of 100" ``` ```clojure ;; With exception as second arg (log/logp :error (RuntimeException. "Timeout") "Request timed out after" 30 "seconds") ``` ```clojure ;; Dynamic level selection (doseq [[level msg] [[:debug "Starting"] [:info "Running"] [:warn "Slow"]]] (log/logp level msg)) ``` -------------------------------- ### `logf` — Format-String Logging Macro Source: https://context7.com/clojure/tools.logging/llms.txt A low-level macro for formatted logging that accepts an explicit log level. It serves as the base for other formatted logging functions like `debugf`, `infof`, etc. ```APIDOC ## `logf` — Format-String Logging Macro Low-level format macro with an explicit level argument. The foundation for `debugf`, `infof`, etc. ### Usage ```clojure (require '[clojure.tools.logging :as log]) ;; Basic usage with arguments (log/logf :warn "Retry %d/%d for host %s" 2 5 "db-primary") ;; => logs: "Retry 2/5 for host db-primary" ;; Usage with a throwable (log/logf :error (ex-info "Timeout" {:host "db-primary"}) "Connection failed to %s after %d ms" "db-primary" 5000) ``` ``` -------------------------------- ### Minimal log4j2.properties Console Configuration Source: https://context7.com/clojure/tools.logging/llms.txt A basic `log4j2.properties` file to configure console logging. It sets the status level, console appender, and a pattern layout that includes the date, level, logger, message, and throwable information. ```properties # log4j2.properties — minimal console configuration status = warn monitorInterval = 5 appender.console.type = Console appender.console.name = STDOUT appender.console.layout.type = PatternLayout # Use %throwable (not %xThrowable) to print ex-info data maps appender.console.layout.pattern = %date %level %logger %message%n%throwable rootLogger.level = info rootLogger.appenderRef.stdout.ref = STDOUT ``` -------------------------------- ### Log Expression Result With a Format String (`spyf`) Source: https://context7.com/clojure/tools.logging/llms.txt Use `spyf` for logging an expression's result using a format string, similar to `spy` but with formatted output. It logs at a specified level (defaults to :debug). ```clojure (require '[clojure.tools.logging :as log]) ;; Default :debug level (log/spyf "List size: %d" (count my-list)) ;; => logs: "List size: 7", returns the count value ;; Explicit level (log/spyf :info "User count: %d" (count (db/all-users))) ``` -------------------------------- ### `with-logs` — Redirect `*out*` and `*err*` to Log Within a Scope Source: https://context7.com/clojure/tools.logging/llms.txt This macro evaluates its body forms within a context where Clojure's `*out*` and `*err*` are dynamically bound to log-backed writers. This is a scoped operation and does not affect the global `System.out` or `System.err`. ```APIDOC ## `with-logs` — Redirect `*out*` and `*err*` to Log Within a Scope Evaluates body forms in a context where Clojure's `*out*` and `*err*` are bound to log-backed writers. Unlike `log-capture!`, this is scoped and does not affect `System.out`/`System.err`. ### Usage ```clojure (require '[clojure.tools.logging :as log]) ;; Basic usage — *out* => :info, *err* => :error (log/with-logs 'myapp.legacy-lib (run-legacy-code-that-uses-println)) ;; Custom levels via vector syntax (log/with-logs ['myapp.shell :debug :warn] (clojure.java.shell/sh "some-script.sh")) ;; Capturing output of a third-party function (log/with-logs 'myapp.vendor (vendor/initialize!) (vendor/run-job {:id 42})) ``` ``` -------------------------------- ### Logger and LoggerFactory Protocols Source: https://context7.com/clojure/tools.logging/llms.txt The `impl` namespace defines `Logger` and `LoggerFactory` protocols for custom backend integration. You can check the auto-selected factory or programmatically switch factories. ```clojure (require '[clojure.tools.logging.impl :as impl]) ;; Check which factory was auto-selected (impl/name log/*logger-factory*) ;; => "org.slf4j" (or whichever backend was found) ;; Explicitly select a factory via system property (JVM startup flag): ;; -Dclojure.tools.logging.factory=clojure.tools.logging.impl/slf4j-factory ;; Programmatically switch factory at runtime (alter-var-root #'log/*logger-factory* (constantly (impl/log4j2-factory))) ;; Use disabled factory to suppress all logging (e.g., in tests) (binding [log/*logger-factory* impl/disabled-logger-factory] (log/info "This will not be logged")) ;; Implement a custom LoggerFactory (defn my-factory [] (reify impl/LoggerFactory (name [_] "my-custom-logger") (get-logger [_ logger-ns] (reify impl/Logger (enabled? [_ level] (contains? #{:warn :error :fatal} level)) (write! [_ level throwable message] (println (str "[" level "] " message)) (when throwable (.printStackTrace throwable))))))) (binding [log/*logger-factory* (my-factory ())] (log/warn "This will print") (log/debug "This will be suppressed")) ``` -------------------------------- ### Set JVM Option for Logging Factory Source: https://github.com/clojure/tools.logging/blob/master/README.md Configure Leiningen to set a JVM option that specifies the logging implementation factory. ```clojure :jvm-opts ["-Dclojure.tools.logging.factory=clojure.tools.logging.impl/slf4j-factory"] ``` -------------------------------- ### Readable Print Variants (`clojure.tools.logging.readable`) Source: https://context7.com/clojure/tools.logging/llms.txt Use the `clojure.tools.logging.readable` namespace for logging variants that print non-string arguments using `pr-str`, preserving their Clojure data representation. This is useful for debugging complex data structures. ```clojure (require '[clojure.tools.logging :as log] '[clojure.tools.logging.readable :as logr]) (def user {:name "alice" :roles #{:admin :user}}) ;; Standard logging — values printed with print-str (no quotes on strings) (log/info "User:" user) ;; => logs: "User: {:name alice, :roles #{:admin :user}}" ;; Readable logging — values printed with pr-str (preserves data types) (logr/info "User:" user) ;; => logs: "User: {:name \"alice\", :roles #{:admin :user}}" ;; Readable format — all format args are pr-str'd (log/debugf "Value: %s" "hello") ;; => "Value: hello" (logr/debugf "Value: %s" "hello") ;; => "Value: \"hello\"" ;; With throwable (logr/error (ex-info "Failed" {:code 404}) "Response was:" {:status 404 :body "Not Found"}) ;; => logs with exception and readable map representation ``` -------------------------------- ### `spyf` — Log Expression Result With a Format String Source: https://context7.com/clojure/tools.logging/llms.txt Similar to `spy`, this macro evaluates an expression, but it logs the result using a specified format string. It returns the evaluated result unchanged. ```APIDOC ## `spyf` — Log Expression Result With a Format String Like `spy`, but logs using a format string applied to the expression's result. ### Usage ```clojure (require '[clojure.tools.logging :as log]) ;; Default :debug level (log/spyf "List size: %d" (count my-list)) ;; => logs: "List size: 7", returns the count value ;; Explicit level (log/spyf :info "User count: %d" (count (db/all-users))) ``` ``` -------------------------------- ### Redirect `*out*`/`*err*` Within a Scope (`with-logs`) Source: https://context7.com/clojure/tools.logging/llms.txt Use `with-logs` to temporarily redirect Clojure's `*out*` and `*err*` streams to log-backed writers within a specific scope. This is useful for capturing output from functions that use `println` or `print` without affecting `System.out`/`System.err` globally. ```clojure (require '[clojure.tools.logging :as log]) ;; Basic usage — *out* => :info, *err* => :error (log/with-logs 'myapp.legacy-lib (run-legacy-code-that-uses-println)) ;; Custom levels via vector syntax (log/with-logs ['myapp.shell :debug :warn] (clojure.java.shell/sh "some-script.sh")) ;; Capturing output of a third-party function (log/with-logs 'myapp.vendor (vendor/initialize!) (vendor/run-job {:id 42})) ``` -------------------------------- ### Redirect System.out/err to Log (`log-capture!`) Source: https://context7.com/clojure/tools.logging/llms.txt Use `log-capture!` to redirect Java's `System.out` and `System.err` streams to a specified logger namespace. This is useful for capturing output from libraries that write directly to stdout/stderr. Remember to call `log-uncapture!` to restore the original streams. ```clojure (require '[clojure.tools.logging :as log]) ;; Capture with defaults (:info for stdout, :error for stderr) (log/log-capture! 'myapp.stdout) ;; All System.out/System.err writes now go to the log (println "This goes to :info log under myapp.stdout") (.println System/err "This goes to :error log under myapp.stdout") ;; Restore originals (log/log-uncapture!) ;; Capture with custom levels (log/log-capture! 'myapp.legacy :debug :warn) ;; stdout => :debug, stderr => :warn ``` -------------------------------- ### Check If a Level Is Enabled (`enabled?`) Source: https://context7.com/clojure/tools.logging/llms.txt Use `enabled?` to check if a log level is active for the current or a specified namespace. This is useful for conditionally executing expensive operations that are only needed for debugging. ```clojure (require '[clojure.tools.logging :as log]) ;; Check current namespace (when (log/enabled? :debug) (log/debug "Expensive debug payload:" (compute-diagnostic-report))) ;; Check a specific namespace (when (log/enabled? :trace 'myapp.db) (log/log 'myapp.db :trace nil (str "SQL: " (render-query query)))) ``` -------------------------------- ### `enabled?` — Check If a Level Is Enabled Source: https://context7.com/clojure/tools.logging/llms.txt Determines if a given log level is currently enabled for the current or a specified namespace. This is useful for conditionally executing code that is expensive to compute, only when logging is active. ```APIDOC ## `enabled?` — Check If a Level Is Enabled Returns `true` if the given log level is currently enabled for the current (or specified) namespace. Use only when you need to gate non-logging work, not just message construction. ### Usage ```clojure (require '[clojure.tools.logging :as log]) ;; Check current namespace (when (log/enabled? :debug) (log/debug "Expensive debug payload:" (compute-diagnostic-report))) ;; Check a specific namespace (when (log/enabled? :trace 'myapp.db) (log/log 'myapp.db :trace nil (str "SQL: " (render-query query)))) ``` ``` -------------------------------- ### `spy` — Log and Return an Expression Source: https://context7.com/clojure/tools.logging/llms.txt Evaluates an expression, logs the expression itself and its result at the `:debug` level (or a specified level), and then returns the result unchanged. This is ideal for inline debugging. ```APIDOC ## `spy` — Log and Return an Expression Evaluates an expression, logs the expression form and its result at `:debug` level (or a specified level), and returns the result unchanged. Ideal for inline debugging without restructuring code. ### Usage ```clojure (require '[clojure.tools.logging :as log]) ;; Default :debug level — logs form and result, returns value (def result (log/spy (+ 1 2))) ;; => logs: "(+ 1 2)\n=> 3" ;; result => 3 ;; Explicit level (defn process [items] (->> items (log/spy :info (filter odd? items)) (map inc))) ;; Inline in threading pipelines (-> {:user "alice" :role :admin} (log/spy :debug) (assoc :logged-at (java.time.Instant/now))) ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.