I would like to format my logs differently depending on whether my code is being run from a REPL or if I'm running the compiled jar.
Is there any simple way to do this? I was thinking maybe Leiningen leaves a trace somewhere when running the REPL.
(defn current-stack-trace []
(.getStackTrace (Thread/currentThread)))
(defn is-repl-stack-element [stack-element]
(and (= "clojure.main$repl" (.getClassName stack-element))
(= "doInvoke" (.getMethodName stack-element))))
(defn is-in-repl []
(some is-repl-stack-element (current-stack-trace)))
(defn my-log [msg]
(if (is-in-repl)
(prn (str "RUNNING IN REPL : " msg))
(prn msg)))
Related
I've done some coding in clojure inside core.clj which have a -main method that can take 0 or more arguments:
(defn -main
"dequeue function"
[& args]
I'm loading this clj file with:
(load-file "src/exercise/core.clj")
And then i'm trying to learn how to call this within repl in order to develop core_test.clj (if there is any tips about how to develop this auto tests, please give me some hints as well). What I'm trying to do now is:
(-main "resources\\sample-input.json" "a")
But this is printing "Arguments 0" which is a message that I told the code to print just to see how many arguments are being passed with
(println "Arguments" (count *command-line-args*))
How am I suposed to do this?
Thanks!
i'm trying to learn how to call this within repl in order to develop core_test.clj
Usually you'd write other functions that are called from -main and test those rather than the app's entry point -main.
But you should be able to call -main like any other function. I have a src/sandbox/main.clj file:
(ns sandbox.main)
(defn -main [& args]
(prn args))
Starting a REPL in the project folder, I can call -main like this:
(use 'sandbox.main) ;; (load-file "src/sandbox/main.clj") also works
=> nil
(in-ns 'sandbox.main)
=> #object[clojure.lang.Namespace 0x67ccce04 "sandbox.main"]
(-main "some" "args")
;; ("some" "args")
=> nil
There's a key difference in my example though: it's printing -main's args binding; *command-line-args* is nil because you're not running the code from the command line with args, you're running it from a REPL.
Regardless, it's probably a better idea to use an existing library to work with CLI args rather than *command-line-args* directly.
I have created a Leiningen project for Exercise 2 from here. My code looks like this:
(ns random-quotes.core
(:require [clojure.string :as str])
(:gen-class))
(defn word-count [s]
(frequencies (str/split (first (str/split s #"\n")) #"\s")))
(def quote-url "http://www.braveclojure.com/random-quote")
(def total-word-count (atom {}))
(defn update-word-count []
(future
(swap! total-word-count
(partial merge-with +)
(word-count (slurp quote-url)))))
(defn quote-word-count [n]
(doseq [quote-future (doall (repeatedly n update-word-count))]
#quote-future)
#total-word-count)
(defn -main [n]
(doseq [entry (sort-by val (quote-word-count (bigdec n)))]
(println entry)))
All pretty straightforward. When I run, e.g., (-main 5) in lein repl, it runs, prints, and returns as expected. However, when I try lein run 5 instead, it runs and prints but never exits, so I am forced to use Ctrl+C to get my terminal back.
Any idea why this happens?
Clojure has a thread pool that it keeps running for use by the agents. Because those threads are still alive, the JVM can't tell that you're program is done. It's just sitting there waiting for the agents to exit. You can make them finish by calling (shutdown-agents) at the end of your program as described here. Futures use agents.
clojure.core/future-call calls an agent like this:
(let [f (binding-conveyor-fn f)
fut (.submit clojure.lang.Agent/soloExecutor ^Callable f)]
which actually starts your code running. You would not be the only one to voice some criticism of this, and we all hope a more elegant solution is found.
I'm learning about Hystrix and Clojure and don't understand how to (properly) set a timeout on a Hystrix command in Clojure.
I searched StackOverflow and the web more generally. I looked at Hystrix's Clojure wrapper source code (https://github.com/Netflix/Hystrix/blob/master/hystrix-contrib/hystrix-clj/src/main/clojure/com/netflix/hystrix/core.clj). There is a init-fn function parameter that looked promising, but the comments seem to suggest that this won't be a sustainable solution. But would this be a simple start?
I have a ridiculously simple Hystrix command running in Clojure and would appreciate help in extending this to set, say, a 200ms timeout:
(ns hystrix-timeout.core
(:require [clojure.string :as str])
(:require [com.netflix.hystrix.core :as hystrix])
(:gen-class))
(defn my-primary [a]
(if (= a true) (throw (Exception. "Primary failed")) (str "primary: " a)))
(defn my-fallback [a]
(str "fallback: " a))
(hystrix/defcommand my-command
{:hystrix/fallback-fn my-fallback}
[a]
(my-primary a))
(defn -main
"Executes a simple Hystrix command. Will use a timeout when I know how to do this in Clojure."
[& args]
(println (my-command false))
(println (my-command true))
(System/exit 0) ; Exit explicitly as Hystrix threads are still running.
)
I've put my lein project up at https://github.com/oliverbaier/learning/tree/master/hystrix-timeout in case this makes answering easier.
Thanks a lot,
Oliver
The simplest route is to just use System properties. You can set either a global default:
(System/setProperty "hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds" "200")
or a command specific value:
(System/setProperty "hystrix.command.my-command.execution.isolation.thread.timeoutInMilliseconds" "200")
You can perform this in your -main method. If you are running a real web-app sans -main, you can add a ring init in project.clj :ring {:handler your-handler :init your-config-method} your-config-method will be invoked on startup.
I've got the following in a clojure file:
(ns helloworld
(:gen-class
:main -main))
(defn hello-world-fn []
(println "Hello World"))
(defn -main [& args]
(eval (read-string "(hello-world-fn)")))
and I'm running it with
lein run helloworld
and I'm getting the following error:
Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol:
helloworld in this context, compiling:(helloworld.clj:12)
I have a feeling I need to do something with ns-resolve or resolve but I haven't had any success. I've tried the following in the main function:
(let [call-string (read-string "(hello-world-fn)")
func (resolve (symbol (first call-string)))
args (rest call-string)]
(apply func args))
Without success.
Can someone (a) point me in the right direction; and (b) explain precisely what is going on in the Clojure reader when this occurs?
Try to see what the actual namespace is inside your -main.
(defn -main [& args]
(prn *ns*)
(eval (read-string "(hello-world-fn)")))
It outputs #<Namespace user> before bombing out with the exception. This hints that execution of programs with lein run starts out in the user namespace, which obviously does not contain the mapping for your hello-world-fn symbol. You'll need to explicitly qualify it.
(defn -main [& args]
(eval (read-string "(helloworld/hello-world-fn)")))
You can solve your challenge, in a very elegant way, using macros. In fact, you can write a macro that mimics eval.
(defmacro my-eval [s] `~(read-string s))
(my-eval "(hello-world-fn)")); "Hello World"
It works better that eval because the symbol resolution of s occurs in the context that calls my-eval. Thanks to #Matthias Benkard for the clarifications.
You can read about macros and their syntax in http://clojure.org/reader
I have a basic Clojure script containing:
(def test
(future
(loop []
(println "Running")
(recur))))
However, if I execure the file with:
java -cp clojure-1.3.0.jar clojure.main test.clj
Then the screen fills with "Running". How can I change it so the future runs when I want it?
Note: I realise this will run forever, it's just an example of my problem.
A future that doesn't run immediately is just a function with no arguments.
So:
(defn test []
(println "Running")
(recur))
...Later...
(future (test))