Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve logging #245

Merged
merged 12 commits into from
Jul 26, 2023
95 changes: 81 additions & 14 deletions src/migratus/cli.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@
[clojure.tools.logging :as log]
[migratus.core :as migratus])
(:import [java.time ZoneOffset]
[java.util.logging ConsoleHandler Logger LogRecord
Formatter SimpleFormatter]))
[java.util.logging
ConsoleHandler
Formatter
Level
LogRecord
Logger
SimpleFormatter]))

(def global-cli-options
[[nil "--config NAME" "Configuration file name" :default "migratus.edn"]
[[nil "--config NAME" "Configuration file name" ]
["-v" nil "Verbosity level; may be specified multiple times to increase value"
:id :verbosity
:default 0
:update-fn inc]
["-h" "--help"]])

(def migrate-cli-options
Expand Down Expand Up @@ -56,6 +65,7 @@

(defn run-migrate [cfg [_ & args]]
(let [{:keys [options arguments errors summary]} (parse-opts args migrate-cli-options :in-order true)]

(cond
errors (error-msg errors)
(:until-just-before options)
Expand Down Expand Up @@ -87,6 +97,7 @@
(defn run-list [cfg [_ & args]]
(let [{:keys [options _arguments errors summary]} (parse-opts args list-cli-options :in-order true)]
(cond

errors (error-msg errors)
(:applyed options) (log/info "listing applyed migrations")
(:pending options) (do (log/info "listing pending migrations, configuration is: \n" cfg)
Expand Down Expand Up @@ -119,31 +130,88 @@
logger (.getLoggerName record)]
(core/format fmt date src logger level msg thr))))

(defn verbose-log-level [v]
sandre1 marked this conversation as resolved.
Show resolved Hide resolved
(case v
0 java.util.logging.Level/INFO ;; :info
1 java.util.logging.Level/FINE ;; :debug
java.util.logging.Level/FINEST)) ;; :trace

(defn set-logger-format
"Configure JUL logger to use a custom log formatter.

* formatter - instance of java.util.logging.Formatter"
([]
(set-logger-format (simple-formatter format-log-record)))
([^Formatter formatter]
([verbosity]
(set-logger-format verbosity (simple-formatter format-log-record)))
([verbosity ^Formatter formatter]
(let [main-logger (doto (Logger/getLogger "")
(.setUseParentHandlers false))
(.setUseParentHandlers false)
(.setLevel (verbose-log-level verbosity)))
handler (doto (ConsoleHandler.)
(.setFormatter formatter))
(.setFormatter formatter)
(.setLevel (verbose-log-level verbosity)))
handlers (.getHandlers main-logger)]
(doseq [h handlers]
(.removeHandler main-logger h))
(.addHandler main-logger handler))))

(defn simple-formatter
"Clojure bridge for java.util.logging.SimpleFormatter.
Can register a clojure fn as a logger formatter.

* format-fn - clojure fn that receives the record to send to logging."
(^SimpleFormatter [format-fn]
(proxy [SimpleFormatter] []
(format [record]
(format-fn record)))))

(defn format-log-record
"Format jul logger record."
(^String [^LogRecord record]
(let [fmt "%5$s"
instant (.getInstant record)
date (-> instant (.atZone ZoneOffset/UTC))
level (.getLevel record)
src (.getSourceClassName record)
msg (.getMessage record)
thr (.getThrown record)
logger (.getLoggerName record)]
(core/format fmt date src logger level msg thr))))

(defn set-logger-format
"Configure JUL logger to use a custom log formatter.

* formatter - instance of java.util.logging.Formatter"
([verbosity]
(set-logger-format verbosity (simple-formatter format-log-record)))
([verbosity ^Formatter formatter]
(let [main-logger (doto (Logger/getLogger "")
(.setUseParentHandlers false)
(.setLevel (verbose-log-level verbosity)))
handler (doto (ConsoleHandler.)
(.setFormatter formatter)
(.setLevel (verbose-log-level verbosity)))
handlers (.getHandlers main-logger)]
(doseq [h handlers]
(.removeHandler main-logger h))
(.addHandler main-logger handler))))

(defn load-config!
"Returns the content of config file as a clojure map datastructure"
[^String config]
(let [config-path (.getAbsolutePath (io/file config))]
(try
(read-string (slurp config-path))
(catch java.io.FileNotFoundException e
(log/info "Missing config file" (.getMessage e)
"\nYou can use --config path_to_file to specify a path to config file")))))

(defn -main [& args]
(let [{:keys [options arguments _errors summary]} (parse-opts args global-cli-options :in-order true)
config (:config options)
config-path (.getAbsolutePath (io/file config))
cfg (read-string (slurp config-path))
verbosity (:verbosity options)
cfg (load-config! config)
action (first arguments)]

(set-logger-format)

(set-logger-format verbosity)
(cond
(:help options) (usage summary)
(nil? (:config options)) (error-msg "No config provided \n --config [file-name]>")
Expand All @@ -159,4 +227,3 @@
(no-match-message arguments summary)))))