Fork me on GitHub

Hi guys! Is there a way to indicate to clojurethat the ~/.m2 is now in ~/.cache/m2?


If you need it outside of projects with deps.edn as well, it will probably work if you set it in ~/.clojure/deps.edn.

👍 1

Thank you @U2FRKM4TW

👍 2
Al Z. Heymer08:05:46

Assuming I have a logging-agent running in my test environment, and I want to check if it outputs a warning when a certain condition is met. How would I capture the log of a function call (as a side-effect)? Neither log-capture! or with-logs are appropriate here. I could use with-out-str , but that would mean I would need to execute the function again, just for the sake of getting the log-message, which I want to avoid. I suppose I could do something like

(let [out (with-out-str (let [result (f ...)] (is ...)))] (is ...))
But that feels odd.


You can add indirection, injecting a logger service in your f . In test env it can be a kind of mock that you can check it has been called.


There is also >tap if you can modify what's inside f

Al Z. Heymer08:05:02

So you suggest to create a new temporary mock-logger, that would execute the test, when it receives a log-API-call?

Al Z. Heymer08:05:55

Do I understand the concept of tap> correctly, in that it is very similar to core.asyncs sub/`pub`?


for the mock, what I'm suggesting is approximately that:

(let [capture (atom nil)
      logger (fn [& args] (reset! capture args))
      result (f arg1 arg2 logger)]
  (is (= "I'm the log that should be logged" @capture)))

Al Z. Heymer11:05:47

Thanks, I will try that 👍 Much appreciated


for the tap> , that's a kind of pub sub (but you subscibe everything), or maybe a very simple visitor pattern (with only one kind of event to visit)


would be something like that:

(defn f [arg1 arg2]
  (let [msg '???]
    (logger/log (tap> msg))))

(let [capture (atom nil)
      capture-fn (fn [x] (reset! capture x))]
  (add-tap capture-fn)
  (try (f arg1 arg2)
       (= "blabla" @capture)
       (finally (remove-tap capture-fn))))

Yogesvara Das09:05:04

I'm struggling to figure out how to configure this logger at runtime. The example shown shows a static leiningen config and I'm not sure where the log4j2 config example is meant to go.


This talks about the "Properties" configuration format. So you'd put it in a file or something like that. And, according to mentioned in that section above: > 1. Log4j will inspect the "log4j2.configurationFile" system property and, if set, will attempt to load the configuration using the ConfigurationFactory that matches the file extension. Note that this is not restricted to a location on the local file system and may contain a URL. >

Yogesvara Das09:05:03

This is still a little unclear to me. If the file path is a system property how can I set it at runtime?


Before addressing the question, I wanna ask the obvious - why would you want to set it at run time?

Yogesvara Das10:05:48

requirement for this project


One approach would be to use System/setProperty. Probably a more appropriate solution would be to learn log4j2 plugin system and write a plugin that provides the right configuration factory.

Yogesvara Das10:05:19

oh nvm I misunderstood the requirements


:) Exactly why I asked that question. Runtime logging configuration does sound suspicious.

Yogesvara Das10:05:00

I've seen more bizarre things that weren't misunderstandings so I didn't question it 💀

😄 1

Hijacking the discussion about logging, I've used [timbre]( in the past, but was under the impression that it's better to use java logging facilities. Although, the whole log4j debacle doesn't inspire confidence. What are the current best practices (if any)?

Geoffrey Gaillard13:05:32

Java logging does not imply log4j. You might find Logback interesting


Not sure if there’s one current best practice tbh. People and projects have different needs. I’ve used timbre with great success in the past, but there are other interesting contenders more focused around data as well. I believe one is called micro as in the mathematical symbol.


memory failed me, it was mulog

👀 1

I’m used to tail and grep, but I guess this could be useful


The Juxt tech radar for 2021 indicated they are moving away from timbre and recommending logback.


One of the more comprehensive writeups of the logging ecosystem in Clojure is


Somewhat related, I've been wondering if anyone uses tap> as a replacement/entry point for all logging in an app? I've never fully truly understood the intended uses of tap>. I get that it enables tooling like rebl/portal/reveal. Is that basically the specific kind of use case it's meant for? A side channel for data on a dev machine, where presumably there's a high signal to noise ratio (because otherwise it will clog up your viewer). Is there more? There's hardly any examples in public code bases.


I haven't seen production use cases, I use it solely for debugging. Usually just as a way to log values to the reveal, but on rare occasions I've found it useful to do something like collecting tapped values into an atom for me to work with at the repl.

Ivar Refsdal14:05:13

I'm/my company is happy with timbre


Yeah. No fuzz and you can use the same API from ClojureScript as well. Would be interesting to see the difference in performance that’s mentioned in Juxt’s radar


Is there any news on the front (? Last time we heard about it was in the July 2021 Deref update. This would be very useful to simplify using the Kafka Streams Java API (which is full of SAM types) from Clojure.

Alex Miller (Clojure team)13:05:48

have done a lot of exploratory work on it but haven't convinced ourselves of a best direction. If you have one or more concrete examples, would be interested in hearing about those


I still have this nagging feeling I don't understand MethodHandles/invokedynamic enough and there is some translation of clojure functions to them that would magically solve these issues


Thanks Alex, will do.

Alex Miller (Clojure team)12:05:00

Thanks, that's very helpful. My main question is - if you had the ability to adapt a stream into a seq and vice versa, wouldn't you prefer to write that using Clojure seq fns instead?

Matt Searle20:05:04

It would be great! - however there are some behaviours Kafka Streams has, a lot around how its data partitioning works, that mean using a kafka stream via the clojure seq et al ends up either hiding problems that bite you later, or rendering some features of Kafka inaccessible 😞 We ( 👋 @U050S183X ) have tried a few things here, especially around transducers which brought some success. The Kafka Streams DSL itself though is very handy, and its there as you weave in and out of the Kafka Streams APIs itself where would really help