Fork me on GitHub
#clojure
<
2023-02-23
>
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 ?

vemv13:02:00

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)

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

delaguardo17:02:32

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

👍 2
delaguardo17:02:11

or nil if namespace or function does not exist

jpmonettas17:02:23

or if you only need to bind ns

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

MegaMatt21:02:49

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

seancorfield21:02:29

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

MegaMatt21:02:15

interesting. thanks

seancorfield21:02:07

Something like:

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

seancorfield21:02:57

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.

lukasz21:02:17

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 clojure.tools.logging

seancorfield21:02:49

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

MegaMatt21:02:18

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

seancorfield21:02:06

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

seancorfield21:02:36

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

lukasz21:02:19

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

MegaMatt21:02:24

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

seancorfield21:02:15

(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."
  [ctx]
  (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)
    {"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))]
     ~@body))
with this import: org.apache.logging.log4j CloseableThreadContext

seancorfield21:02:51

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

seancorfield21:02:53

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.

MegaMatt21:02:32

yeah that’s exactly what i need to do.

MegaMatt14:02:33

@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

lukasz16:02:04

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

👍 2