Fork me on GitHub
#clojure
<
2017-11-26
>
jumar00:11:29

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...

noisesmith00:11:12

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

jumar01:11:59

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

noisesmith01:11:31

it's localhost only by default

noisesmith01:11:49

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

jumar01:11:27

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

noisesmith01:11:22

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

qqq10:11:11

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.

qqq11:11:23

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

gklijs11:11:08

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

itaied12:11:15

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

val_waeselynck12:11:00

@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.

itaied13:11:50

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"})

itaied13:11:48

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

itaied13:11:02

like :name change to :fullname

val_waeselynck14:11:32

@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.

val_waeselynck14:11:09

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

itaied15:11:31

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

zignd17:11:31

@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: https://kotka.de/blog/2010/05/Did_you_know_III.html

zignd17:11:51

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.

qqq12:11:21

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

the-kenny13:11:09

@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").

dottedmag16:11:31

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.

dottedmag16:11:55

@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).

sova-soars-the-sora17:11:29

( for extremely large values of fourteen )

qqq20:11:49

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

phronmophobic20:11:44

i’ve used jna for integration with C

phronmophobic20:11:48

and it was pretty enjoyable

phronmophobic20:11:07

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

phronmophobic20:11:25

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

stuartsierra22:11:24

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.

qqq22:11:00

I currently have a boot process that looks like:

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

qqq22:11:12

(server.ss-web) is a ns that happens to require all the namespaces I care about

qqq22:11:23

I'm trying:

(deftask learning-dev []
  (comp
   (repl :port 4001) 
   (watch)
   (fn [next]
     (fn [fileset] 
       (require 'clojure.tools.namespace.repl)
       [clojure.tools.namespace.repl/refresh]))))
but I am getting error:
java.lang.ClassNotFoundException: clojure.tools.namespace.repl
      clojure.lang.ExceptionInfo: clojure.tools.namespace.repl

noisesmith22:11:49

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

noisesmith22:11:56

you need to use resolve or similar

noisesmith23:11:26

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

qqq23:11:44

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

noisesmith23:11:07

I know nothing about boot

noisesmith23:11:39

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

qqq23:11:34

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

qqq23:11:44

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

noisesmith23:11:49

yeah, that sounds like some boot stuff

qqq23:11:56

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

noisesmith23:11:22

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

qqq23:11:50

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