Fork me on GitHub
#clojure
<
2015-07-08
>
jwm00:07:54

hmm 1.6 has some?

joshg01:07:19

@aengelberg: you’re right about the evil nil case. I created an issue earlier: http://dev.clojure.org/jira/browse/CLJ-1775

aengelberg01:07:23

Actually, I believe I am wrong about the evil nil case... (any? #(nil? %) [nil]) would return true for your trivial example. Because some returns the truthy value of the function call.

jv09:07:27

hi all, are there any way to reload java class in the repl?

jv09:07:09

something like (import [my.package HelloWorld] :reload)

lucien.knechtli09:07:22

ew. that's not what i thought pasting the link would do

jv09:07:56

@lucien.knechtli: ah, i meant a case like: I started a repl session, I changed HelloWorld after started repl, now I would like to reload it without restarting repl.

jv09:07:28

I'm afraid vinyasa cannot do that?

lucien.knechtli09:07:19

scroll down to "reimport" in the readme for the repo

lucien.knechtli09:07:36

Isn't that what you're describing?

jv09:07:08

aha, yes, it is! I always thought vinyasa is only for injecting vars

lucien.knechtli09:07:07

You could also change how you're loading the class on the Java side

jv09:07:35

it now looks to me a Swiss army knife!

lucien.knechtli09:07:07

but yea, I'd probably just use Vinyasa, because changing the way you load the class means messing with your deployed code, whereas vinyasa doesn't.

jv09:07:48

yes, vinyasa is a good tool in the repl

jv09:07:07

And I see your point about MyClassFactory too! Thanks!

jv09:07:23

uhmm, what keywords did you use to search about my problem?

lucien.knechtli09:07:45

"clojure repl reload java class"

lucien.knechtli09:07:42

vinyasa was pretty much the only useful thing I got out of the search though

jv09:07:59

haha, great catch though!

lucien.knechtli09:07:02

although, Chriz Zheng's blog looks like it's gonna be some good reading in case I get bored at work today: he wrote vinyasa

jv10:07:42

yes, I actually followed him for quite a while

ivanbokii13:07:06

Hey guys. Any chance anyone knows if there is something like reduce-indexed function (like standard map-indexed)? I don't know the whole standard library, but hope there is something that I can use without implementing it myself. Thanks.

sgerguri13:07:08

Hi, has anyone run into namespace corruptions on :reload? I kept getting my defs corrupted when reloading namespaces with Cascalog, and my colleagues inform me this is not unique in Cascalog and happens in normal Clojure code as well.

sgerguri13:07:19

I wonder what the reason for that might be.

sgerguri13:07:02

I’m on Clojure 1.6, in case anyone’s wondering.

ordnungswidrig13:07:32

sgerguri: one common problem is that you have references from other namespaces to old instances of functions of the reloaded ns.

sgerguri13:07:19

@ordnungswidrig: In my case I def-ed a Cascalog query.

sgerguri13:07:48

Getting the results out of it multiple times prior to reload worked just fine, but reloading - even unrelated funs - corrupted it.

ordnungswidrig13:07:49

sgerguri: make sure that any ns the uses the ns with the query is reloaded, too

sgerguri13:07:19

That was in a live repl session (so ‘user namespace). Can you even reload that?

sgerguri13:07:04

Actually, I take that back - it was in the namespace I was reloading.

sgerguri13:07:27

Ok, so I was in ‘foo.core and was reloading ‘foo.x.y.

ordnungswidrig13:07:43

ivanbokii: you can do sth like (->> [1 2 3] (map-indexed identity) (reduce (fn [s [i x] (+ s (* i x)) 0)))

sgerguri13:07:52

I didn’t reload ‘foo.core, since the definitions I had there were all done manually.

ordnungswidrig13:07:10

sgerguri: maybe one of the references closed over a value from foo.x.y

sgerguri13:07:36

They did actually.

sgerguri13:07:48

Now it makes sense then - thanks!

wiruzx13:07:09

Folks, why we have reduce-kv function when we could use reduce with destructing?

(reduce (fn [acc [key value]] ...

minimal13:07:09

@wiruzx: performance it seems

Alex Miller (Clojure team)14:07:59

it avoids constructing, then tearing apart, the map entry

Alex Miller (Clojure team)14:07:58

reduce-kv just walks over the internal nodes of the map and applies the function directly

devn14:07:02

one of the most confusing errors I've ever had in clojure

devn14:07:18

user.clj was in src/user.clj for component

devn14:07:43

classnotfounderror LoggerFactory when running the built jar

gtrak14:07:17

tools.logging is a pain with aot

noisesmith18:07:19

devn: perhaps you were getting a logging impl from some lein plugin, and never actually depended on one properly in your project?

noisesmith18:07:00

devn: the java loggers are very interface / impl decoupled, and everything avoids forcing a specific impl, you should usually end up having to pick one for every project

noisesmith18:07:49

should unless someone else was poorly behaved and forced one on you

devn19:07:49

@noisesmith: there was commons logging, log4j, and slf4j-log4j12 transitively finding their way in via deps. i am using logback.

Alex Miller (Clojure team)19:07:25

if your log library isn't working, you don't have enough of them

arrdem19:07:53

To how many logs must an application write...

devn19:07:10

anyway, the real solution was to not have src/user.clj there, and specify dev in my :dev profile src-paths

devn19:07:30

but i cant say i totally understand what happened there

devn19:07:35

it was only with the built jar

devn19:07:58

user.clj being a file that referenced components

devn19:07:43

😄 caught you typing

trptcolin19:07:40

for situations where :prep-tasks needs to prepare things that my main component ns needs, because the app itself depends on them, which loads clojure to run the :prep-tasks, which loads RT.java, which loads user

devn23:07:19

anyone here use different logback configurations in dev/test/prod? actually, in general: I could use some help with logging garbage. how the heck do you manage all of these logging deps?

devn23:07:09

it seems like if i pull one thread, another logging dep pops out of the woodwork

devn23:07:58

im sticking with logback because of its LogstashEncoder

devn23:07:16

controlling the insanity is trying my patience, though, i must admit

zentrope23:07:13

I like to have a separate “script” for packaging for deployment. If the app is invoked via a shell script, I just pass in -Dlogback.configurationFile=/path/to/prod/logback.xml for that.

zentrope23:07:57

For testing, I think you can do something similar inside leiningen. Some sort of fixtures thing. I’ve used that to hide all logging when running tests.

devn23:07:00

so you don't package the logback.xml?

devn23:07:19

also, it would seem that logback.configurationFile is only being respected when I run the jar

devn23:07:27

so for local development, it's still not doing the right thing

zentrope23:07:48

For testing:

zentrope23:07:55

:profiles {:uberjar {:aot :all}
             :test {:jvm-opts
                    ["-Dlogback.configurationFile=test/resources/logback.xml”]}

devn23:07:21

hmph, im genuinely confused. it would seem that my profile is not being respected

devn23:07:42

zentrope: do you have logback-core included as a dep?

zentrope23:07:55

For deps, I have the following:

devn23:07:13

i have zookeeper logging using slf4j-log4j12 under the covers

devn23:07:20

and log4j

zentrope23:07:25

[org.clojure/tools.logging "0.3.1"]
   [ch.qos.logback/logback-classic "1.1.3"]

zentrope23:07:53

I have my “dev” logback in the resources directory.

devn23:07:13

named logback.xml?

zentrope23:07:19

For production, I have a separate logback.xml elsewhere. I use that for running the jar (as you said).

devn23:07:36

so do you bundle the other logback.xml in your jar? sounds like no.

zentrope23:07:52

For testing, I have another logback in the test/resources dir, which doesn’t get on the classpath.

zentrope23:07:08

Yes, the default logback is still in the jar, but the -D param overrides it.

zentrope23:07:06

And, yeah, you have to add other slf4j nonsense to bridge dependencies that use something else and won’t shut up … sometimes.

zentrope23:07:27

So, the “prod” logback is NOT in the jar. (Otherwise, ops folks can’t fiddle with it.)

devn23:07:00

ah, that's a good point, i was doing exploded clojure uberwars in a previous job

devn23:07:07

so it was still available on the box

devn23:07:14

but that makes good sense

zentrope23:07:25

Yeah. I’m opinionated in that I like to make a separate project for building-for-production.

zentrope23:07:54

It just checks out the code (or whatever) and adds production style scripts, update.d, launchd, configs, logback, whatever.

zentrope23:07:10

That way my code is simple. No “if” statements. Just overridable defaults.

devn23:07:26

yeah, i was using janino to do conditional expressions inside the logback.xml

devn23:07:30

but that is absolute nonsense

zentrope23:07:34

(This is kinda against the grain for a lot of devs, I admit.)

devn23:07:39

im just going to drop logback.xml into chef and call it a day

zentrope23:07:31

Place I worked wrote software to deploy at customer sites, so had to have logback external to a jar so support could turn stuff on to see what happened.

devn23:07:31

meh, if it works, it works -- i dont want to pass a bunch of "necessary" nonsense logging-related burden onto other devs

devn23:07:41

so im trying to make development simple, clean configurable logging

devn23:07:56

and then have the logstash encoder only exist in the prod environment

zentrope23:07:07

Ops should be able to pass in overrides as they need. It’s not a build-time concern.

devn23:07:27

paths matter to me as well -- would rather not have local devs forced into making /var/log/foo/bar.log with correct permissions

devn23:07:35

i just want those to go to log/bar.log

devn23:07:38

in the local project

zentrope23:07:51

Sensible defaults.

devn23:07:24

one last question for you, and it's a loaded one

devn23:07:30

so, configuration. I'm using environ, which lets you refer to ENV vars and java system properties in your clojure code like (get configuration :foo), but in prod you set the ENV var as FOO=123 java -jar ...

devn23:07:37

this turns out to be pretty handy, but locally we've got a config.edn.example file that specifies local defaults, which you copy to config.edn in order for them to take effect

devn23:07:42

this was all well and good, but of course, doing AOT in an environment that /doesn't/ have a config.edn obviously breaks, which means a bunch of complicated nonsense for the build pipeline, since it needs to go out and grab config

devn23:07:27

so i'm kind of faced with this question of: should I skip AOT and pass the values in as ENV vars when the jar is run?

devn23:07:42

or should i write a file, curl a file, etc. to read values from?

zentrope23:07:26

My preference is to consider the build as a UI problem for devs. The mount of futzing with files is painful.

zentrope23:07:41

So, the app should “just work” with “lein run” and that’s that. ;)

zentrope23:07:55

But what about production?

devn23:07:57

so you run with defaults?

zentrope23:07:09

I use something like: java -jar app.jar —config /path/to/config.edn.

zentrope23:07:25

Then just merge the map there over the top of the sensible defaults.

devn23:07:48

right now im not specifying :main or :aot in project.clj, doing (:gen-class) and ^:skip-aot on the ns with the -main in it

devn23:07:01

so all env vars are set when it runs

zentrope23:07:11

Doesn’t uberjar aot everything anyway?

devn23:07:44

you can avoid it

zentrope23:07:11

As long as you have something like (System/getenv “ENV_VAR” “default”) it doesn’t matter, right?

devn23:07:30

by for instance, specifying :main, and then creating a bootstrap clojure file that references the -main indirectly, so it won't transitively AOT your project

devn23:07:58

so you reference your bootstrap -main instead of your true main

devn23:07:11

so many ways to run clojure 😄

zentrope23:07:22

Okay. Make sense. But how does that impact env vars for configuration?

devn23:07:20

when you go to run locally they still have to be set somewhere, even if you get to avoid them when building the jar

zentrope23:07:59

Yeah. I always go with defaults. localhost database, stock port, etc.

devn23:07:16

this whole scenario is a bit more complicated than im letting on, and i won't bore you with details, just rubber ducking a little bit thinking about the right way to keep development easy, but also close enough to a prod environment that there aren't annoying surprises when deploying

devn23:07:33

API keys still need to live somewhere

zentrope23:07:36

Yeah, that’s tough.

devn23:07:08

which, i could create a development version of those keys and commit them

zentrope23:07:13

Another thing is a “configurator” that just prints out what stuff isn’t set, so devs aren’t faced with bizarre stack traces.

devn23:07:15

but i tend to avoid committed keys at all cost

devn23:07:38

I've used outpace/config in the past

zentrope23:07:49

The problem with dev being too much like prod is that prod becomes frozen.

devn23:07:11

you can generate a config from all the areas you reference config values

zentrope23:07:19

Or, people start relying on stuff being there and don’t build in flexibility at the right places.

devn23:07:21

but it still isn't going to magically insert API keys

zentrope23:07:22

Tradeoffs, eh? ;)

zentrope23:07:04

Api keys, remote databases, etc.

devn23:07:26

yeah, the more i think about it i think that committed, sensible defaults for configuration vars needs to happen, and for the API keys in question, a separate set of test accounts can be created which will never see prod traffic

zentrope23:07:32

I’ve had people just “lein run —config=/path/to/custom.edn” for dev. It’s not too bad.

devn23:07:43

and maybe...just maybe commit those as well -- there's nothing of value in them, after all

zentrope23:07:12

Yeah, if you separate “build for production” vs “build for dev” into separate projects, you can store the production API keys in that project.

devn23:07:35

the main thing is seeing a built uberjar run in your dev environment, for me that matters

devn23:07:45

because sometimes AOT stuff sneaks in and bites you

zentrope23:07:46

Prod project is just shell scripts (say) and conf file that get merged into an RPM (or whatever). Not a clojure project.

zentrope23:07:21

Like serving embedded files via an embedded web-server. That bit me. ;)

zentrope23:07:44

But I just “java -jar target/app.jar —config/resources/default-config.edn” and it works.

zentrope23:07:05

The important bit is “override”.

zentrope23:07:24

That way the prod config.edn doesn’t have to have every setting.

devn23:07:53

then again, i sort of like being forced to be explicit about everything in prod