This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-04-06
Channels
- # announcements (14)
- # babashka (14)
- # beginners (22)
- # calva (56)
- # cider (20)
- # clerk (8)
- # clj-commons (10)
- # clj-kondo (18)
- # cljs-dev (11)
- # clojure (87)
- # clojure-conj (3)
- # clojure-europe (29)
- # clojure-nl (1)
- # clojure-poland (5)
- # clojure-portugal (1)
- # clojurescript (100)
- # data-science (3)
- # datahike (1)
- # datomic (13)
- # events (2)
- # fulcro (10)
- # funcool (2)
- # helix (19)
- # hoplon (6)
- # humbleui (2)
- # hyperfiddle (40)
- # leiningen (5)
- # lsp (22)
- # malli (26)
- # nrepl (2)
- # off-topic (19)
- # reagent (32)
- # releases (1)
- # shadow-cljs (266)
- # spacemacs (6)
- # tools-build (9)
- # vim (1)
Hi I need to write a program that is constantly reading a log file line by line and react on certain events. I can't come up with a way to continuously read the file without having to start over when the entire file has been read. What would be a good way to solve this?
Can you share the code that reads from file?
I have only tried something like this but then I would have to do a new line-seq on the reader and read the entire file again.
(with-open [rdr (io/reader "file.log")]
(doseq [line (line-seq rdr)]
(line-handler line)))
I'd search online for something like "tail -f" in java
.
Or, if your program is intended to be running on *nix, I'd simply pipe the output of tail -f
into it - no need to reinvent the wheel.
(require '[ :as io])
(import '[ BufferedReader])
(with-open [^BufferedReader rdr (io/reader (io/file "/tmp/log.txt"))]
(loop []
(let [line (.readLine rdr)]
(case line
;; Nothing is ready to read yet, wait a second and continue
nil (do (Thread/sleep 1000)
(recur))
;; Handle any stop reading condition
"stop" (prn line)
;; Overwise, handle line and continue the loop
(do (prn line)
(recur))))))
not very nice solution, because to wait it is calling Thread/sleep. But it is possible to adjust to specific usecaseThere is also https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/input/Tailer.html which is exact what @U2FRKM4TW suggested: "tail -f" implementation in java
Yes, this solves the issue that I had. Thanks for the suggestions.
There is no way to make RegexReader
-like things but with macros, is there?
Trying to pre-compile xpaths:
(def ^XPath -xpath (.newXPath (XPathFactory/newInstance)))
(defmacro xpath [s]
(.compile -xpath s))
(query doc (xpath "a"))
=> Syntax error compiling fn* at (...).
Can't embed object in code, maybe print-dup not defined: org.apache.xpath.jaxp.XPathExpressionImpl@32639a47
What would be the most appropriate alternative?Er - I may have misunderstood both the question and the answer, but - isn't it a matter of, what do you want computed at compile time, vs run time, and if the best you can do at compile time is emit a readable thing which will execute that .newXpath constructor at run time, then is it very important to use a macro?
That's the point - the best thing is better than emitting (.compile ...)
. It's actually calling that before run time.
Does anyone know of a barebones way of decrypting an RSA-OAEP encrypted payload? I don’t want any additional hashing, no symmetric encryption, etc. Just a server-side reversal of the WebAPI SubtleCrypto encryption of data with that algorithm. Everything I’m seeing so far combines this algo with other layers that I do not need or would vastly complicate what I’m trying to do.
For a bit more detail, I want to encrypt and/or sign a browser-side payload so it can be verified on the server. Symmetric encryption would expose the key. Asymmetric signing also exposes a private key. It seems the only option is encryption, where the private key is on the server, and the public key is in the browser. However, I cannot find any clojure libraries that will do just that: decrypt the payload without signing or using any other ciphers.
I actually think I might ditch it all and use ECDSA… it works in SubtleCrypto and in Buddy
but for signing, you should be able to sign with a private key and verify with a public key
Yes, I’m back to where I started: exposing a private key in the browser that is signing/sending the data
> It seems the only option is encryption, where the private key is on the server, and the public key is in the browser. this seems like the reverse of what you are saying you want, but reads like that is what you think your only option is
Well, it’s ok to use a public key in the browser, right? So the only option is encryption. Then the server decrypts with the private key.
It seems ‘incorrect’ to use asymmetric keys to encrypt the payload itself. That’s how the libraries make it seem.
This is promising, let me take a look, thanks…
looks like you can specify the hash option in either on the js side or the java crypto side, and you just have to make sure they match
ok here goes..
This code prints out 1003 items:
(let [get-first (fn [xform coll]
(first (sequence (comp
xform
(map (fn [t]
(println "item" t)
t)))
coll)))
data [{}
{:a []}
{:a [{:b []} {:b [1 2 3]}]}
{:a [{:b (range 1000)}]}]]
(get-first (comp (mapcat :a)
(mapcat :b))
data))
But why? I'd expect at most 32 items because that's the chunk size.
As expected, an alternative that uses transduce
+ reduced
works flawlessly and prints it only once.If you care about when things happen, don't use lazy sequences. Even if it does work, it's not guaranteed to continue to work and is brittle.
I know. But in this particular case, I would like to understand why the whole collection is traversed.
Debugging it is rather painful, especially given that -Dclojure.compiler.disable-locals-clearing=true
doesn't seem to work for me (assuming it's useful at all without an explicit call to compile
).
Other than curiosity, is there a particular reason for trying to learn the implementation details of the lazy sequence?
Just wondering if there's an X/Y question here and maybe there's an easier way to solve your problem.
No, no XY question. It's not my first post on this server. ;) I'm applying the "XY heuristic" to my own questions before I post them.
So it doesn't seem to be 32 to the power of 2, 3, and even 4. And a plain
(first (sequence (map (fn [i]
(println "item" i)
i))
(range 1000)))
prints out only the first chunk.pretty sure that it has something to do with the mapcat:
(first (sequence (mapcat (fn [i]
(println "item" i)
i))
[(range 1000)]))
Transducers are push, lazy chunking is pull. It's not possible to pause a transducing step, therefore the full range has to be traversed.
The only way to get a partial result from expanding transducers like mapcat
is to use early reduction. This will print once :
(let [get-first (fn [xform coll]
(reduce (comp reduced {}) nil
(eduction xform
(map (fn [t]
(println "item" t)
t)) coll)))
data [{}
{:a []}
{:a [{:b []} {:b [1 2 3]}]}
{:a [{:b (range 1000)}]}]]
(get-first (comp (mapcat :a)
(mapcat :b))
data))
I'm not sure how to reconcile your first two statements with the fact that a simple map
in my last code block doesn't result in printing of more than 32 items.
The simple map
doesn't use cat
. 🐈
what version of Clojure are you using?
particularly, is it 1.12.0-alpha1
@U7RJTCH6J It does work correctly though, at least the way I understand it.
mapcat
chunks over the collection that it processes (I think), so [(range 1000)]
prints out the whole range, because there's just one item in the outer collection, while (map vector (range 1000))
prints out just 32 single-element vectors. That's why I was checking for powers of 32, because I have a combination of two mapcat
s.
without digging into the details of this code, what is (comp reduced {})
doing in there?
The 2-arity always returns its second argument. The 1-arity isn't used by reduce
but yeah, would return nil
.
@U2FRKM4TW I don't know why you think the transducer form of mapcat
chunks. You can see in the implementation of cat
that it immediately reduces over each sequence it sees.
Well, I was thinking that because I had a wrong mental model of cat
. :) Thanks for pointing me in the right direction.

Currently using https://github.com/juxt/aero to configure a project and I’m wondering if there is a way to do nested profiles, e.g.
[:test :test-instrumentation]
versus [:test :test-no-instrumentation]
Because currently we’re in a situation where we want two profiles that are identical except for a single config var, so having to similar top-level profiles would be incredibly needlessly redundant
In such cases, I don't use profiles and instead use simple config vars. Usually as env vars. I've seen other people implement custom aero reader tags that use more intricate logic but with the same end result.
Shouldn't you use derive in that case? https://clojuredocs.org/clojure.core/derive
@U2FRKM4TW Yeah in other codebases we’ve implemented config value overrides that apply custom per-test values after the Aero config is read in. But that’s always been kind of a hacky solution.
@UK0810AQ2 Aero does not rely on keyword hierarchies. It's a simple get
when it comes to profiles.
@U02FU7RMG8M It should be possible to implement your own profile
-like Aero reader.
Could you resolve that with a #ref
for the single nested config var, or am I misunderstanding?
@UK0810AQ2 It's actually very trivial. :)
(defmethod aero.core/eval-tagged-literal 'instrumentation
[tl opts env ks]
(aero.alpha.core/expand-case (:instrumentation opts) tl opts env ks))
That's it. You'll have to pass another option along with :profile
, though.@U2FRKM4TW you know the trick of posting wrong answered to nerd snipe someone to post the correct answer? 🙃
Just a note, but a pattern I’ve found useful for situations where you have different environments is to consider each EDN document to be a profile, and to meta-merge them together in a profile chain.
This means you can keep things DRY by having the latter profiles easily override definitions in the earlier profiles.
It’s https://github.com/lambdaisland/kaocha/pull/128/commits/0403b58b2e0467526a766449772720b2836b9579 to add a #meta-merge
tagged reader to aero too, allowing you to write profile chains like:
#meta-merge [#include "base.edn" #include "test.edn"]
I appreciate meta-merge can be hard to reason about, but 99% of the time I find it works really well; especially if you avoid the extra metadata options, and instead just try and arrange the data in your profiles so they’re monotonically increasing.So we ultimately went with the post-config-read override since we didn’t want to get too fancy for a feature that’s only used in testing
Calling pmap, in a specific context obviously, causes my %cpu to spike to up past 1000%. If i call it on a smaller list, it's fine. I had assumed pmap would only take a parallel but constant amount of work, so there would be much different between (->> l (take 100) (pmap f))
and (pmap f l)
in terms of CPU overhead.
If you need more predictable control over parallel resource usage then I'd recommend using the claypoole
library, which makes it easy to limit a parallel operation to a fixed size threadpool
I think the idea with pmap is that it wants to saturate the available CPU. My guess is that 100 items isn’t enough to do that, but a larger sequence is.
you can search this slack to find critiques of pmap, in particular suggestions that pmap is not great for parallel io, which is often what people that ask about pmap are trying to do with it
That makes sense, i think in this case i'll be happier with regular old map!
and if for some reason you need the most detailed way of control you can do something like that to create each worker and control it.
(dotimes [_ pool-size]
(async/go-loop []
(when-let [f (async/<! fns-chan)]
(try
(f)
(catch Exception e
(l/error e "sync-db go-loop worker" )))
(recur))))
oh and pmap
doesn’t use all CPU, it use constant number of parallelism based on your CPU. I don’t remember the pattern but let’s say it is number of cores / 4 +2 or something like that.
what I usually do is:
1) pmap
to prove of work and it can be all what you need depends what you do
2) if not satisfy me, then pipeline
3) if I need more control, than I create workers with go-loop
I don’t think I have ever needed anything else, than above
thanks @U0WL6FA77 That makes sense, thanks a lot for the advice 🙂
What would be the correct java interop way to access javax.crypto.spec.PSource.PSpecified/DEFAULT? I’m getting syntax errors, class not found errors, etc.
javax.crypto.spec.PSource$PSpecified/DEFAULT inner classes take a dollar sign https://docs.oracle.com/en/java/javase/19/docs/api/java.base/javax/crypto/spec/PSource.html
Excellent! That was it, thanks!
Quick side question: This type of reference requires the fully specified class name, right? I cannot just require it as PSource and then refer to PSource$PSpecified? I’m getting compilation errors when I do, but having that entire class name looks kludgy.