Fork me on GitHub
Alexandre EL-KHOURY11:02:16

Hello guys, I'm using reitit, how can I do to send an error message on all routes that doesnt exist ?


There happens to be a #C7YF1SBT3 channel :) (if there wasn't, I would recommend to post questions as github issues - they're rarely unwelcome in Clojure projects. That way everyone benefits)

Jakub Šťastný17:02:08

Hey guys. How do I refer to a fn in a namespace if given ns is a variable? I have this: (doseq [ns ['oop 'fun]] (in-ns ns) (println "# Namespace" (ns-name *ns*))) This works, but I'd much rather NOT have to change ns and instead refer to the fns via something like (ns/my-fn-defined-in-both-oop-and-fun), but that doesn't work as it treats ns as the final module name rather than a var that it first has to resolve.


you can use (requiring-resolve (symbol ns fn-name)) that should give you a reference to the function

👍 2

or nil if namespace or function does not exist


or if you only need to bind ns

(binding [*ns* (find-ns 'clojure.core)]
        ;; do something


how does one export a macro from another namespace? eg, in my log file i want to export timbre/info which is a macro as my.logger/info


Exporting vars can be problematic for a number of reasons -- you might just as well write your own wrapper macro with the same args.


interesting. thanks


Something like:

(defmacro info [& args]
  `(timbre/info ~@args))
off the top of my head...


Some of this will depend on whether you're doing this just for .clj or for .cljc intending your code to be usable as Clojure and ClojureScript.


Also off the top of my head:

(defmacro info [& args]
  (with-meta `(timbre/info ~@args) ~'(meta &form)))
because most logging libs capture caller's namespace etc so you want to pass that down. I wrote something like that for


Ah, yeah, logging is a bit of a special case. Thanks, @U0JEFEZH6


i wish clojure logging had with-context+ i’d just stick with that.


We use plain tools.logging with log4j2 and that supports MDC which allows you to provide extra context for logging.


(we used to use Timbre but that was just too much "special" stuff so we switched back to plain logging)


We use cambium (+ logback + json formatting), but with our own wrapper namespace that does exactly that (wrapping cambium's macros while preserving context)


do you have a link i could look into for the tools.logging extra context?


(defn stringize-context
  "Given a logging context (that is hopefully a hash map), return a
  hash map with strings for keys and for values. If the context is
  not a hash map, return a hash map with a ctx string key and the
  context value as a string."
  (if (map? ctx)
    (reduce-kv (fn [m k v]
                 (assoc m
                        (if (keyword? k) (name k) (str k))
                        (when (some? v) (pr-str v))))
    {"ctx" (pr-str ctx)}))

(defmacro with-log-context
  "Given a hash map and a body (sequence), add the hash map to the log4j2 mapped
  diagnostic context, and execute the body."
  [ctx body]
  `(with-open [_# (CloseableThreadContext/putAll (stringize-context ~ctx))]
with this import: org.apache.logging.log4j CloseableThreadContext


Then wrap code in (with-log-context {:some "hash" :data "here"} (the-code :args))


We have this inside middleware, for example, that handles auth decoding to identify the logged in user, so the logging context includes the user ID if available.


yeah that’s exactly what i need to do.


@U0JEFEZH6 what’s the ~' for around the meta of the form? it causes Attempting to call unbound fn: #'clojure.core/unquote error removing the unquote and quote makes the macro work but not sure of its purpose


I was typing from memory so that's probably not valid, but the code in the gist def works, I just tried it

👍 2