This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-12-15
Channels
- # adventofcode (80)
- # beginners (94)
- # biff (19)
- # cider (74)
- # clj-kondo (11)
- # cljs-dev (7)
- # clojure (110)
- # clojure-austin (3)
- # clojure-australia (1)
- # clojure-belgium (1)
- # clojure-china (1)
- # clojure-europe (83)
- # clojure-filipino (1)
- # clojure-hk (1)
- # clojure-indonesia (1)
- # clojure-japan (1)
- # clojure-korea (1)
- # clojure-my (1)
- # clojure-nl (1)
- # clojure-norway (4)
- # clojure-sg (1)
- # clojure-taiwan (1)
- # clojure-uk (2)
- # cursive (3)
- # data-science (8)
- # datalevin (8)
- # emacs (18)
- # etaoin (5)
- # graalvm (1)
- # holy-lambda (3)
- # honeysql (1)
- # jackdaw (10)
- # java (10)
- # jobs (3)
- # luminus (9)
- # malli (106)
- # off-topic (88)
- # polylith (8)
- # portal (2)
- # re-frame (50)
- # reagent (11)
- # reitit (74)
- # remote-jobs (1)
- # shadow-cljs (46)
- # tools-deps (26)
- # xtdb (49)
Hi everyone,
I need the result of applying filter
and remove
to a coll. i.e.
(let [a (filter ,,, coll)
b (remove ,,, coll)]
[a b]) ;; <- could be a vector or map
and I would like to get the result by just applying one function, I already checked group-by
, but my problem is that it generates a map where the keys are true
and false
, it doesn't look fine.
Do you know how to make this in a more idiomatic way?
Thanks!(let [result (group-by pred coll)]
[(get result true) (get result false)])
☝️:skin-tone-2: would that give you what you need @U02TF2JU3M4@U04V70XH6 I would like not to have the true
and false
keys :thinking_face: since (get result true)
or (result true)
don't look very good.
I was wondering if there's a better way to achieve this
You could wrap the above in a function and just not look at that code any more 🙂
Yep, also I was thinking in modifying the result of pred
to return a keyword instead of true and false :thinking_face:
anyway!
There is a difference in semantics as far as laziness is concerned: filter
and remove
are both lazy but group-by
is eager. You could also use a predicate function that returned :filtered
or :removed
instead of just a Boolean.
Then you'll get a map with those keys instead of true
and false
.
> juxt
The group-by
approach has the benefit of calling the predicate once per element, however.
You can extend a Record during the type declaration.
;; from memory, might have bugs
(defrecord Foo [x y]
extend Bar
(bar-method [this z] (implementation this z)))
(let [foo (->Foo :foo :bar)]
(bar-method foo :baz))
In that ^ example Bar
would be your protocol ...
(defprotocol Bar
(bar-method [this])
... to which you extend Foo
with an implementation of its methods.but you can't make it implement a new interface after declaration - you need to use the fallback protocol dispatch mechanism (which isn't that bad)
So, if I have a Foo record that implements the Bar protocol, I can't extend the already-instantiated record to also implement the Bam protocol? I suppose I can work with that.
it will implement the protocol, just not extend the interface - minor diff depending on what you are doing
If the "new protocol" is extensible via metadata, you can add metadata to any Clojure object at runtime and polymorphic dispatch will work.
I'm trying to make macro that can destructure a map. Here is what i have so far:
(defmacro <-
[m]
`'('let [{:keys (destructure ~m)} ~m]
1)
(def args {:a :b})
(<- args)
;; => ((quote clojure.core/let)
;; [{:keys (centriq-web.jobs.import.fix.import-all-data-assets/destructure args)}
;; args]
;; 1)
i can't tell if thats closer then this
(defmacro <-
[m]
`[{:keys (destructure ~m)} ~m])
(<- args)
;; => [{:keys [a]} {:a :b}]
I get lost on what the plan should be when i introduce the let binding. I imagine it helps first to imagine why it has to be a macro, in this case it's because i need the hashmap passed to be turned into a vector of symbols (thats what destructure fn does), which in turn is returned as part of a let expression.
The interaction with the let binding inside the macro has me confused though. for example
(defmacro <-
[m]
`'(let [{:keys [~(destructure ~m)]} ~m]
1))
(macroexpand-1
`(<- args))
Fails with
Attempting to call unbound fn: #'clojure.core/unquote
~(desctructure ...
needs to happen because i need the hashmap to turn into a vector and i think the unbound unquote is the m in
i just noticed how late it is. 🛏️
See https://stackoverflow.com/questions/9345056/in-clojure-how-to-destructure-all-the-keys-of-a-map (maybe you just need map
, for
or doseq
).
Sorry, let me clarify. Given (def x {:a 1}) The input would be: x The output would be (let [{:keys [a]} x] [a]) This macro would be a useful development tool and save me having to do more typing.
I'm not sure this is what you're asking for, but I can imagine it'd be useful to have a macro that takes a map and a body, like (<- x (prn a))
that expands to (let [{:keys [a]} x] (prn a))
. So that all the map keys are available as locals. But this would be quite tricky to write, because the keys of x
wouldn't be known at macroexpand time.
Why wouldn't they be known? If it look at my examples, getting the keys out wasn't the issue, It was putting it in the let block. @UAEH11THP i don't follow (Vals x) => 1 I want (<- x) => (let [{:keys [a]} x] [a]) It helps so i don't have to type all the keys to x if there are like 10 of them and i need to do something with them in the let block. It's a time saver when developing locally.
To see the code that a macro produces, uses macroexpand-1
, like this: (macroexpand-1 '(<- x))
That should show you the code that would then be compiled. If you use the macro directly without macroexpand
, you'll see the result of evaluating the returned code -- this value usually shouldn't look like code anymore (that is, not a let block like (let [...] ...)
, but rather the result you hope to see at runtime.
(let [{:keys [a]} x] [a]) if the map x only has the key :a then this will be the same as vals though? if you want to put "something else" where the [a] is while having the binding a without knowing the keys, i'd rather just not do that. though i'm not even sure if the compiler would let you. i think it'd yell at you to use auto-gensym names. can you show an usecase for this thing you're trying to do? i can't imagine how it'd be useful
Imagine the hashmap has like 5 or 6 arguments with really long names. Those names are not going to be autcompleted in my editor, because they don't exist in the static text. So right now i first eval the map so i don't have to type but can get tab completion. Here is an example of what i would start with
(def args {:really.long.namespace.in.a.big/project 1
:another.really.long.asdflkjallkjas/lffff334343 2})
after the macro
(let [{:keys [really.long.namespace.in.a.big/project
another.really.long.asdflkjallkjas/lffff334343]} args]
[project lffff334343])
With some manual editing by me to get what i want
(let [{:keys [really.long.namespace.in.a.big/project
another.really.long.asdflkjallkjas/lffff334343]} args]
(+ (http-request project)
lffff334343))
without the macro how many keystrokes would it take to get from the first step to the second? I want it to be 1.
@UAEH11THP hopefully that helps.I think this is more fit for an editor extension (a calva feature) than a macro
Unless your args
are known (static) at macro expansion time I don't think it's possible at all
I think that's true, the keys are only known at run time in cases where the complier can't reach them.
Yeah, the goal was going to be to hook it up to my editor. Though, i think, the fn would be just clojure outside the UI.
I don't know editor extensions but auto-completing \args
to the current value of the args
map shouldn't be hard in the REPL
With a known map you can do something like
user=> (defmacro <- [args]
`(let [{:keys ~(mapv (comp symbol name) (keys args))} ~args]
;;cursor here
""))
#'user/<-
user=> (macroexpand-1 `(<- {:a 1 :b 2}))
(clojure.core/let [{:keys [b a]} {:b 2, :a 1}] "")
I'll take a look, thanks a lot for the help.
Hi @here , How to convert the below map literal with namespace from=>
#:person{:first "Han"
:last "Solo"
:ship #:ship{:name "Millennium Falcon"
:model "YT-1300f light freighter"}}
to=>
{:person/first "Han"
:person/last "Solo"
:person/ship {:ship/name "Millennium Falcon"
:ship/model "YT-1300f light freighter"}}
It’s a print formatting thing. Evaluate this.
(set! *print-namespace-maps* false)


Aji, those data structures are the same. The difference is just in how they are displayed. Purely visual and due to your REPLs print settings.


Does anyone know of a way to configure logback so that any clojure.lang.ExceptionInfo
that gets logged will have its ex-data
included in the output? In particular, I'd like it included as JSON in the JsonLayout
.
https://github.com/kwladyka/consistency-clj/tree/master/src/consistency/logs/google here is how to do it for JUL
https://github.com/kwladyka/consistency-clj/blob/master/src/consistency/logs/google/json_payload.clj#L30-L44 here is the part which should be the main point
in shortcut it converts log into json, but you have also (assoc :ex-info (ex-data thrown))
there
yeah, I see. Thanks. I wonder what value we're getting out of logback -- configuring it from Clojure and XML seems trickier than what that example shows for JUL.
in other words I would always choose JUL to do custom logging. Not something which is ready by default.
I guess this can be example: let’s say you want to log to a file, but you want to keep 1000 lines in a file and 10 files. It is not included in JUL by default as far as I know.
But if you want to make custom JSON structure logging which is not ready by default anywhere it is a nightmare. At least it was extremely frustrating experience 2 years ago. Then I switched to JUL.
that's where https://github.com/BrunoBonacci/mulog comes in strong
@U050BHA78 I researched this a few months back, and ended up with a small custom logger macro that extracts the exception data with ex-data
and passes it as a net.logstash.logback.argument.StructuredArgument
to the Logger methods (debug, info etc.).
In the Logback config I use net.logstash.logback.encoder.LogstashEncoder
to output log lines as JSON.
@U06BEJGKD out of my curiosity how it looks today to make a custom JOSN logs? Not default one, but custom structure and values where for example if it is error it has to be very specific value in JSON.
@UAEH11THP can mulog work as a forced default output logs for everything? I mean here Java libraries which use other logging frameworks. Can all this be redirected to the mulog?
This is the biggest pain and at least in my opinion it is critical one to use or not use a tool for logging
should be doable with https://gitlab.com/nonseldiha/slf4j-mulog (never tried myself though)
but it should be possible to maintain own library like this if someone really want to
but I really like (μ/with-context {:order "abc123"}
which is often needed for http session
(defmacro thread-local-binding
"Like the `binding` macro but for thread-local vars. (only 1 binding is supported)"
{:style/indent 1}
[binding & body]
(when-not (and (vector? binding) (= 2 (count binding)))
(throw (ex-info "the binding vector must be a clojure vector with 2 elements, symbol and value"
{:bindings binding})))
(let [[sym val] binding]
`(let [^ClojureThreadLocal sym# ~sym
val# ~val
b# (deref sym#)]
(.set sym# val#)
(try ~@body (finally (.set sym# b#))))))
answer myselfcan’t be sure but if I understand this correctly it sets values for a thread, not wrap a code which will still not help for http sessions
i don't know what you're hoping for but with-context does propagate inside function calls
so if the same fn in the same thread is called 10 times each of this call will have own values and not interfere each other?
anyway this is interesting way to achieve adding values to logging by using (.set ^threadLocalValue …) instead of binding
@U0WL6FA77 I’m specifically using https://github.com/logfellow/logstash-logback-encoder#event-specific-custom-fields to make Logback log any extra key/values as additional fields in the JSON output. Like I said, I have logging macro that extracts data from the exception. I’ll post a gist in a sec.
i don't know how could you call the same thing from the same thread multiple times in an interfering manner
(with-values [… unique-request-id]
top level wrap
some async stuff
not async stuff
…)
I mean something like thathttps://gist.github.com/msolli/cbd9c7f7799f6696f8d3a5e3699e03f2 is my application’s logging implementation (“vilect” is my company’s name). It’s inspired by pedestal.log, but takes a more “structured logging” approach. And this is my logback.xml:
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<fieldNames>
<timestamp>timestamp</timestamp>
<stackTrace>exception</stackTrace>
<version>[ignore]</version>
<levelValue>[ignore]</levelValue>
</fieldNames>
<excludeMdcKeyName>trace_flags</excludeMdcKeyName>
</encoder>
</appender>
I use the default one that Logstash dictates, with some minor modifications (see over). It is highly customizable, though.
Here’s the one I use for New Relic, for example:
<appender name="NEWRELIC" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/web.newrelic.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/var/log/newrelic/web.%d.log</fileNamePattern>
</rollingPolicy>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<timestampPattern>[UNIX_TIMESTAMP_AS_NUMBER]</timestampPattern>
<fieldNames>
<timestamp>timestamp</timestamp>
<logger>logger.name</logger>
<level>log.level</level>
<thread>thread.name</thread>
<stackTrace>error.stack</stackTrace>
<version>[ignore]</version>
<levelValue>[ignore]</levelValue>
</fieldNames>
<mdcKeyFieldName>trace_id=trace.id</mdcKeyFieldName>
<mdcKeyFieldName>span_id=span.id</mdcKeyFieldName>
<excludeMdcKeyName>trace_flags</excludeMdcKeyName>
<excludeMdcKeyName>AWS-XRAY-TRACE-ID</excludeMdcKeyName>
<customFields>{"service.name":"vilect-web"}</customFields>
</encoder>
</appender>
The “real” code is in that gist. With those logging macros I get structured JSON logs. I can include any data I want when logging:
(log/debug ::something {:foo foo, :bar "some hardcoded value", :more-data something-data})
Or, to come back to OP’s question, if you want all the ExceptionInfo data included in the log output, I just:
(catch Exception e
(log/error ::some-error {:additional "data"} e)
nil #_"or whatever")
this was asked a while ago. Has anything changed with regards to Java records interop - java.lang.Record ? Related question: should we try to update Clojure Java interop page with information regarding new JVM features? Mention new language features and how to implement them if possible. https://clojure.org/reference/java_interop > https://clojurians.slack.com/archives/C03S1KBA2/p1584980075120800
Nothing has changed. I don’t think that’s the right place for this, but a guide maybe
tools like visualvm have more support for java classes. it would be great to have that. looking at clojure memory allocations is just array, string, char, map etc. which does not provide a lot of information .
As an aside: what could we do as a community to make profilers better at diagnosing issues in our clojure programs? Who needs to get paid?
@U06DQC6MA what are you lacking in the current ecosystem? What sort of issues do you want to find?
I find that I am able to use profilers like VisualVM to fix memory and performance issues to the same extent in Clojure as Java.