Force JUL with clojure.tools.logging - clojure

My Clojure app needs to log through Java.Util.Logging (JUL) because custom log rotation is no supported at the moment with Elastic Beanstalk. I'm using clojure.tools.logging to write the log files, but the library keeps auto-selecting log4j as the logging engine.
How can I force clojure.tools.logging to use JUL?
I found a thread online that has a solution using alter-var-root to permanently bind the selected factory to logger-factory:
(alter-var-root (var log/*logger-factory*) (constantly (impl/jul-factory)))
...but it's an older thread and didn't know if there was a better way.

I use this one every day:
(alter-var-root
#'clojure.tools.logging/*logger-factory*
(constantly (clojure.tools.logging.slf4j/load-factory))
switching slf4j for impl/jul-factory should be reliable and at least mostly sane.

Related

How can I stop jetty server without restarting repl

Let's say I have a trivial boot-clj task that uses '[pandeiro.boot-http :refer [serve]]. If I make changes and need to restart the task it would complain that the port is already in use. Is there a way to kill jetty server without having to restart repl?
If you want only this many people use this pattern:
(defonce running-server (atom nil))
(defn stop-server [] (#running-server))
(defn go []
(reset! running-server
(org.httpkit.server/run-server
... your stuff here ...))
If this is a longer term project starting with something like the component framework solves this problem in a much more elegant way and allows for many dependent components (hence the name). This is a good place to get started and worth reading before starting your next project.
pandeiro.boot-http supports reloading of your handler so you don't have to restart the serve task. You need to configure it with :reload set to true:
On command line:
boot serve -H myapp.server/app -R wait
Or in your boot script:
(boot (serve :handler 'myapp.server/app :reload true) (wait))
For regular static files serve always returns the current version from the disk so there is no need for reloading for them.
If you really need to restart the task I guess you might be affected by issue in pandeiro.boot-http and might need to contact its maintainer.

Sharing an atom between Clojure and Clojurescript?

Assume I have a Clojurescript namespace called main with a atom within it called state.
(ns main)
(atom state nil)
I compile my Clojurescript app, run it on a server, fire up the Clojurescript repl and then connect to my server using a browser. Everything works dandy.
In the Clojurescript repl, I can comfirm the usual
> (+ 1 1)
2
> (js/alert "Hey there") //shows an alert dialog with "Hey there" in the browser
nil
> main.state
(atom nil)
The Clojurescript repl is great for development. So, clearly I can get and (using swap! or reset!) set the value of a Clojurescript atom from a Clojure application. I was wondering if there was a way to have a connection between the value of an atom in my Clojurescript project and a running Clojure application. Perhaps the Clojurescript client connects to a specified port and sends the result to some Clojure server waiting on that port. Simply stated, I was wondering if it might be possible to have a running server application share the value of the state client atom.
Why, you might ask? Well, I was thinking it would be nice to write the value of the state atom to a actual file (state.clj) whenever state is modified in the running Clojurescript application. This way, I could always have a view of the current value of state. I could use something like emacs (global-auto-revert-mode t) to make sure that state.clj buffer was always fairly recent. This is a little like having a debugger.
Beyond that, my real desire is to then make it so that the running Clojure application would also periodically poll state.clj itself. When the server detects that I modified state.clj, it would accept the modification as the new value of the Clojurescript state atom. It would then do something like what the Clojurescript repl does, illustrated in the following pseudo code:
(send-to-client-for-evaluation
(compile-into-js
(reset!
main.state
the-read-string-value-of-the-content-of-state.clj)))
Basically, I want the ability for the server to have something akin to a shared atom between the client and the server. I want the value of state to be bidirectionally shared between the client and the server. Is any of this possible, or am I just dreaming?
Sure, just make requests to a rest API sending data in EDN format, and voila! If you want to avoid polling, consider running your Jetty or Tomcat behind an Nginx instance to make use of the Nginx HTTP Push Module. I have a somewhat cobwebby example here (this was pre-ClojureScript, so I wrote the client in plain JS). And there is also gifsockets.

How to hot reload a namespace on file save in Leiningen REPL

When using the leiningen REPL, is there a way to make a file or ns automatically reload in the repl on file save. Currently I reload the ns by typing the following in the repl - (use 'sample.ns :reload-all).
However can I have it reload automatically on file save ?
You can easily reuse the code from duct framework.
You will need only hawk files watcher.
Here is how it can be looks like:
(defn- clojure-file? [_ {:keys [file]}]
(re-matches #"[^.].*(\.clj|\.edn)$" (.getName file)))
(defn- auto-reset-handler [ctx event]
(binding [*ns* *ns*]
(clojure.tools.namespace.repl/refresh)
ctx))
(defn auto-reset
"Automatically reset the system when a Clojure or edn file is changed in
`src` or `resources`."
[]
(hawk.core/watch! [{:paths ["src/" "resources/" "dev/src/" "dev/resources/"]
:filter clojure-file?
:handler auto-reset-handler}]))
Clojure-Watch library does what you need. It observes a file and performs some action. In your case, an action would be to reload a namespace from that file. Also, it requires to write some initial code to launch the observer.
This way seems a bit complicated to me. Plain REPL launched directly from Lein is not effective way to develop. You better to use some Clojure-friendly editor like Emacs or Lightable.
Most major editors support custom hotkey bindings and have a Clojure plugin that allows you to connect to the active REPL over the network (via "nREPL"). Personally, I use vim and therefore use vim-fireplace for this purpose.
This means you can have a custom hotkey for reloading whatever file you're editing as you edit it. From there, it's typically trivial to add a custom on-save hook that does the reloading.

How do I programmatically set gzip in Jetty?

I'm writing a web app using Noir and clojure, which uses Jetty. Jetty has two ways of using gzip, one for static, and one for dynamic, they are described in https://stackoverflow.com/a/9113129/104021. I want to turn on both static and dynamic gzipping, but our project doesn't use web.xml files, and doesn't want to start.
How do I programmatically set jetty to use gzip (ie without having a web.xml)?
In a Compojure app I'm working on, I have a Ring/Jetty adapter based on ring-jetty-adapter which programmatically configures Jetty to use a GzipHandler to gzip content dynamically.
(defn- configurator [server ring-handler]
(.setHandler server
(doto (new HandlerCollection)
(.addHandler (doto (new GzipHandler)
(.setHandler (proxy-handler ring-handler))
(.setMimeTypes "text/html,text/plain,text/xml,application/xhtml+xml,text/css,application/javascript,text/javascript,image/svg+xml")))
(.addHandler (doto (new RequestLogHandler) (.setRequestLog (NCSARequestLog.)))))))
This function takes a Server instance and my Ring handler and sets it up with some handlers. Note that the GzipHandler is a HandlerWrapper, so it takes my (proxied) Ring handler and delegates to it. I also add a logging handler which will be executed after the (gzip-wrapped) Ring handler.
Check out the complete working version.
See the startServer method in here:
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java
jetty uses itself extensively for testing so most embedded scenarios people need already exist in the unit tests somewhere, course finding them can be a bit of an issue :)

Reloading code on a production ring-clojure server

What's the best way to push new code to a production ring server without restarting the whole JVM?
Currently I use wrap-reload in production, but this doesn't quite work for me because sometimes I want to run commands in the repl (doing database migrations for example) before ring starts handling requests with the new code. Also various blogs and tutorials out there say not to use wrap-reload in production, though I don't understand why not.
I have come up with the following solution, but I confess I don't have a deep understanding of what's going on under the hood. I was wondering if I could get a sanity check by someone who does. Does this technique seem reasonable?
The idea is to have a path (/admin/reload-clj) that causes all the clojure code to be reloaded.
(defonce ^:dynamic *jetty*)
(declare reload-clj)
(defn app [req]
...
(when (= (req :uri) "/admin/reload-clj") (reload-clj req))
...)
(defn start-jetty []
(let [j (run-jetty app {:port (http-port) :join? false :max-threads 16})]
(dosync (ref-set *jetty* j))
j))
(defn reload-clj [req]
(future
(log/info "Reloading clojure code...")
(require '(whrusrv admin main utils wdb) :reload-all)
(.stop #*jetty*)
(start-jetty)
(log/info "Clojure reload success!"))
{:status 200
:headers {"Content-Type" "text/plain"}
:body "Reloading..."})
(defn -main [& args]
(start-jetty))
The code you have will work, though you should be aware that :reload-all only loads a namespace and that namespaces dependencies. It does not recursively load dependencies of those namespaces.
I should add that reloading in this way is strongly not reccomended in a production system.
Newly deployed code might have errors that aren't apparent until the system is restarted (e.g, they depend on a var that is still defined from the running system but whose declaration was removed). The system will work fine but then fail on restart.
Loading code can also have side effects which could screw up your production environment. Although its good style to avoid these, the only way to truly be sure something unexpected won't happen is to do a JVM restart.
The best way to do a zero-downtime deploy on the JVM is a rolling deploy using a load balancer.
I had an intranet web service in common lisp at a previous job, so I don't know if that qualifies as production. Also, being in CL my answer is neither ring nor clojure specific. Still, it's useful for reloading code.
What I did is to start a swank server (part of slime) on the production lisp instance and connect to it even remotely from my desktop. That way I could write new code, rewrite code, debug, reload, etc. Obviously you'll have to be extra carefull in a real production system.
You can do similarly in clojure, you even have alternatives to swank, like nrepl.
You'll have to take security into account as well and allow only local connections, or whatever works for you.