idiomatic logging in clojure

I'm new to clojure and would like to understand the approaches of logging in a clojure, coming from an imperative background. In a java production-program I would usually LOG (debug/info) in start-end of a method, something like that:

public void foo(){
   logger.debug("starting method to embrace %s", rightIdioms);
   doSomething();
   logger.debug("successfully embraced %s idioms", idioms.length);
}

I'm familiar with the pro's/con's of logging and know the tools available for that in clojure,

I can also find some con's of logging in the approach mentioned above, which deepens the tension I feel when logging in none-imperative:

  1. logging is a side effect and clojure pushes to no-side-effects.
  2. more lines-of-code or 'code-complexity': in java - having big classes is common (getters, setters, constructors), in clojure, expressions return values, logging 'difficults' the process and hardens small functions and namespaces: (one example would be the need to change from if to if-let or if-do to perform a logging):

    (defn foo [x]
      (if (neg? x)
        (inc x)
        x))
    
    (defn foo [x]
      (if (neg? x)
        (let [new-x (inc x)] 
          (logger/debug (format "inc value, now %s" new-x)
          new-x))
        x))
    

I have read logging with clojure/tap or tracing but not sure i fully found it useful.

What are the approaches or the idiomatic way to do logging in clojure?

Logging in Clojure: Making Sense of the Mess, log , which offers an API inspired by Log4j, and Gl�gi offers an idiomatic ClojureScript interface inspired by pedestal.log. Happy logging! More� Stack Exchange network consists of 177 Q&A communities including Stack Overflow, the largest, most trusted online community for developers to learn, share their knowledge, and build their careers.

Few best practices are given in this blog post, it suggestion to log data and not strings could be very useful and fit with clojure-style of logging. a log event could be something like that:

{:service     :user.profile/update
 :level       :debug
 :time        "2020-01-01"
 :description {:before '0
               :after  '1}
 :metric       10ms}

Where metric can be anything, from time the update took, to the number of rows pulled from the db.

Then when you have data, you could do anything with it - analyzing it to gain insights or group-by to search and find. You can always turn the data structure back to a string if needed for console-logging.

tee val to log idiomatically? : Clojure, defining a new fn (using only clojure core fns?) (defn tee [f! g v] (f! v) (g v)). Usage (-> (kvlt/request! ) (p/then (partial tee (comp js/console.log pr-str) :body))) . Re-implement Trident example of log processing with grouping and aggregation using clojure. Trident currently does not have clojure DSL. Implementation is based on clojure gen-class. others. Other small modules contains examples of idiomatic clojure programming, e.g., core.async, graph algorithm, qsort in 5 lines, defmacro, etc.

Logging won't side-effect program data, so the Clojure ethic does not frown on it.

To avoid having to remodel a function to log its inputs and outputs, a quick hack is to abuse pre- and post-conditions:

(defn foo [x]
  {:pre [(do (println "foo" x) 
             true)]
   :post [(do (println "foo" x "==>" %) 
              true)]}
  (if (neg? x)
    (inc x)
    x))

The true makes the condition succeed. Otherwise, the program would stop.

Pre- and post-conditions are documented here: https://clojure.org/reference/special_forms#_fn_name_param_condition_map_expr_2

Here's how the logging-enhanced foo looks in the REPL:

user> (foo -7)
foo -7
foo -7 ==> -6
-6

lambdaisland/glogi: A ClojureScript logging library based , A ClojureScript logging library based on goog.log. Contribute to lambdaisland/ glogi development by creating an account on GitHub. The above solution is idiomatic as clojure has a philosophy of maximal immutability and controlled mutability. An atom is the simplest form of controlled mutability provided by clojure. This solution is ready for use by multiple threads, and is appropriate for use by a single thread, without you having to think about it too much.

circleci/analytics-clj: Idiomatic Clojure wrapper for the , Idiomatic Clojure wrapper for the Segment.io 2.x Java client - circleci/analytics-clj. Log (print [this level format args] (println (str (java.util.Date.) "\t" level "\t"� Idiomatic Clojure: Code Smells Posted on June 6, 2020. We all make mistakes. We have all written bad pieces of code at some point of our lives. They might have been

How do you personally do logging? - Watercooler, So, Clojure/tools.logging is built in, but requires some arcane outside knowledge to Providing idiomatic access to MDC functionality with support for capturing� Learning languages is easy, learning the idioms is less easy “Lisp has no syntax,” or so they say. It does have some, but significantly less than other languages. Clojure has a slightly larger pile of stuff that you could mistake for syntax, but, it’s still compact and simple. The tricky part isn’t the language so much as it is the slang.

some? - clojure.core, Returns the first logical true value of (pred x) for any x in coll, else nil. One common idiom is Added by timgilbert. Log in to add a see-also� Stack Trace Debugging using REPL: Since Clojure is compiled to Java bytecode and runs on the JVM, many times, if an exception is thrown, it will be a Java style exception.

Comments
  • "Logging won't side-effect program data, so the Clojure ethic does not frown on it" Anything that changes the state of the system inside a function is a side-effect. So logging is a side-effect.
  • @m0skit0, in Clojure we're only opposed to side effects that will trip us up later. Clojure has quite a liberal view of functional purity. See for example Clojure's Transient Data Structures - "If a tree falls in the woods, does it make a sound?" - and Clojure's own logging library, clojure.tools.logging.