Fork me on GitHub

I'm using timbre for logging and wondering if there's any way how to change the log level of running application from outside. Sometimes, I want to raise the logging level temporarily - mostly for staging/production environment. I was thinking about something like jmx...


set-level! just changes a key in an atom, but you could easily hook up an api to alter it. My app starts a localhost only socket server that we sometimes connect to in order to change the log level, or the logged namespaces


I was thinking about socket repl but not sure if that's feasible in terms of security compliance on production 🙂. Nevertheless, thanks for advice. Maybe I'll try to add simple jmx api


it's localhost only by default


if they are on localhost, there's nothing they could do via the socket that they couldn't do easier with a shell


That sounds reasonable. Will speak to ops guy and see if that's feasible. Thanks!

Alex Miller (Clojure team)01:11:32

@jumar you don’t actually need the full repl - the socket server can be used to trigger the invocation of an arbitrary function with args


I keep forgetting it can do that, that's smart


spec is not behaving the way I expec it to is there a way to query the "spec database" to see what is "registered" corresponding to a given keyword/spec ?

Oliver George10:11:17

Yep, there’s a private atom & a helper which derefs and returns the current value.


Can you point me at the documentation of the helper function? don'ts see it in the spec guide.


there is (defn get-spec “Returns spec registered for keyword/symbol/var k, or nil.” [k] (get (registry) (if (keyword? k) k (->sym k)))) from the source


What are the benefits of using keyword over string? In particular, in a map?


@itaied there's a performance benefit - because of interning, Clojure Keywords are very fast to check for equality (essentially a pointer comparison), making for fast lookups in maps; they also then to consume less memory. There's also a practical benefit that keywords are functions of the maps that (potentially) contain them as keys. Finally, IMO, there's a clarity benefit: when you see a piece of data as a keywork, you know that it's a programmatic name, not content meant to be shown to a user; Strings have that ambiguity.


ok thanks. One more question, do you use keywords scattered in your codebase or abstract them using a def? What I mean:

(def name :name) 
(name {:name "itaied"})
Rather than (:name {:name "itaied"})


so that if the model name changes (lets say that the map is a dynamic variable), you have to change it in only one place


like :name change to :fullname


@itaied I know why you may feel this is a good idea, but from experience, I recommend using keywords in their literal form, not abstracted behind a name.


This level of indirection is unlikely to make your change non-breaking, because the keyword will probably end up being exposed raw somewhere, e.g serialized over the network


but then the change would be in one place, doesn't it?


@itaied it's not considered idiomatic clojure, people simply use keywords and repeat them whenever they need to, you should also know that there's another feature regarding Clojure keywords that is useful to provide this isolation you're looking for, it's called namespaced keywords. Check this article for more info on that:


also, if you define a name for your keywords you would have to require them in the other namespaces to use them, therefore, keywords and namespaced keywords are easier to use.


(:foo {:foo 20})
("hello" {"hello" 20})
kw works, string gives error


@qqq: keyword implement IFn and act as functions, strings don't. Similarly, you can't use a number as a function like (1 ["foo" "bar" "baz"]). However, maps implement IFn, so you can do ({"hello" 20} "hello").


Hey folks. I’m trying to parse a string of the format aaa bbb "ccc" {:a 1} foo bar..., where non-bracketed whitespace-separated parts are to be read verbatim, and {..}, #{..} and [..]-parts are to be read as ClojureScript expressions. What’s the easiest way to do the expression read? I had a look at clojure.edn/read-string, but it does not return the unread tail, and I wouldn’t want to count brackets manually.


@itaied No, it will be everywhere: instead of changing a keyword throughout the code you’ll need to change a variable throughout the code. If you don’t, you’ll end up with moral equivalent of (def fourteen 17).


( for extremely large values of fourteen )


is there a nice way to interface Clojure with either Rust, C, or C++ ? my ideal setup would be: 1. Clojure has a DSL for Rust/C/C++ 2. I write some high performance code in this DSL 3. at runtime, this DSL -> Rust/C/C++ -> *.so -> dynamic loads as JNI -> I can call it from Clojure The only structured I need to pass back & forth is float-array, int-array, and double-array


i’ve used jna for integration with C


and it was pretty enjoyable


so it seems like you could setup rust code to be called from clojure-jna, although it might involve some boilerplate


the same will apply for c++, where you would create c wrapper functions to your c++ code


I've used Clojure with JNI directly, it was straightforward to follow the JNI docs. You have to be a little careful to make sure pointers passed to native code don't get garbage-collected. I think there is some overhead involved in the interaction between native code and JVM, which might matter if there is a lot of calling back-and-forth between the native code and JVM code.


I currently have a boot process that looks like:

(deftask learning-dev []
   (repl :port 4001) 
   (fn [next]
     (fn [fileset]
       (require ' :reload)))))
the goal is to auto reload all .clj .cljc files unfortuantely, it's not doing that; how can I fix this?


( is a ns that happens to require all the namespaces I care about


I'm trying:

(deftask learning-dev []
   (repl :port 4001) 
   (fn [next]
     (fn [fileset] 
       (require '
but I am getting error:


if you call require inside your function, you can’t compile code for that function that accesses it directly


you need to use resolve or similar


it’s much simpler if you can move the require outside the function and into the top level of the code


@noisesmith: can you head ovedr to #boot ? I have code via resolve, but it's failing with a different error


I know nothing about boot


resolve returns a var, you might need to dereference it and get the actual function? usually that doesn’t matter


(deftask learning-dev []
   (repl :port 4001) 
   (fn [next]
     (fn [fileset] 
       (require '
       ((resolve '
is what I have, but it's causing prolblems with "set! on non-binding thread"


but at this point, I guess it's a boot problem, and not a cloju4re problem


yeah, that sounds like some boot stuff


repl/refresh is being called properly, just on a different thread


one thing to try could be bound-fn, which creates an fn that will have all your current dynamic bindings when called


eh, I'm just going to have emacs hot key send it to repl 🙂