clojure.tools.logging

repository·master·Indexed 19 days ago

https://github.com/clojure/tools.logging

A Clojure library providing logging macros that delegate to a specific logging implementation selected at runtime, such as SLF4J, Log4J2, or java.util.logging. It includes features for redirecting System.out and System.err to logs, handling STM transactions, and configuring logger names based on namespaces.

Tokens
1.1K
Snippets
3
Records
7
Agent score
15%

What's inside clojure.tools.logging

  1. How namespacing works for log entries

    master

    By default, clojure.tools.logging uses the current namespace (the value of *ns*) as the "logger name". This allows you to configure different logging levels or formats for specific namespaces within your underlying logging implementation.

    Important: Ensure your underlying logging implementation is configured to display the logger name. If the implementation uses stack-inspection instead of the provided name, log output may be unhelpful.

  2. Install clojure.tools.logging

    master

    You can install clojure.tools.logging using various Clojure dependency management tools. The latest stable release is 1.3.1.

    ;; deps.edn
    {:deps {org.clojure/tools.logging {:mvn/version "1.3.1"}}}
    
    ;; Leiningen
    [org.clojure/tools.logging "1.3.1"]
    <!-- Maven -->
    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>tools.logging</artifactId>
      <version>1.3.1</version>
    </dependency>
  3. Use logging macros in Clojure

    master

    Logging is performed using the log macro or level-specific convenience macros like debug and debugf.

    Performance Note: Message arguments are only evaluated if the specified logging level is enabled. This prevents unnecessary computation when a log level is suppressed.

    STM Note: By default, if you are inside a running STM transaction, the log invocation will occur via an agent to avoid side effects within the transaction.

  4. Select a logging implementation via system property

    master

    To avoid issues caused by multiple logging implementations being present in the classpath (e.g., via transitive dependencies), it is strongly advised to explicitly select your implementation using the clojure.tools.logging.factory system property.

    This property should be set to the fully-qualified name of a no-arg function that returns an instance of clojure.tools.logging.impl/LoggerFactory. You can find available factory functions in the clojure.tools.logging.impl namespace.

    If unset, the library automatically selects the first implementation it successfully loads from this list (in order):

    1. SLF4J
    2. Apache Commons Logging
    3. Log4J 2
    4. Log4J
    5. java.util.logging
    ;; Leiningen example setting the factory to SLF4J
    :jvm-opts ["-Dclojure.tools.logging.factory=clojure.tools.logging.impl/slf4j-factory"]
  5. Troubleshoot missing data maps in ex-info exceptions

    master

    If you are logging an ex-info exception and the data map is missing, it is likely because your logging implementation is only printing the result of Throwable.getMessage().

    To fix this, ensure your logging implementation prints the contents of Throwable.toString() or uses Throwable.printStackTrace(...) instead.

  6. Redirect System.out and System.err to logs

    master

    You can capture standard output and error streams and redirect them into the logging system using two methods. In both cases, you must provide a specific logger name (do not rely on *ns* for these operations).

    1. log-capture!: Redirects all Java writes of System.out and System.err to the log system.
    2. with-logs: Binds *out* and *err* to the log system.
  7. Configure Log4J2 for Clojure exceptions

    master

    When using Log4J2, use the %throwable pattern in your layout to ensure that clojure.lang.ExceptionInfo exceptions are printed with their associated data maps.

    Warning: Do not use %xThrowable (the default) or %rThrowable, as these will omit the data maps from the log output.

    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