248 lines
7.2 KiB
Clojure
Executable File
248 lines
7.2 KiB
Clojure
Executable File
#!/usr/bin/env bb
|
|
|
|
(require '[clojure.string :as str])
|
|
|
|
;; Add Timbre dependency for Babashka
|
|
(require '[babashka.deps :as deps])
|
|
(deps/add-deps '{:deps {com.taoensso/timbre {:mvn/version "6.8.0"}}})
|
|
|
|
(require '[taoensso.timbre :as timbre]
|
|
'[taoensso.timbre.appenders.core :as appenders])
|
|
|
|
(println "\n=== Timbre Logging Examples ===\n")
|
|
|
|
;; Example 1: Basic Logging Levels
|
|
(println "--- Example 1: Basic Logging Levels ---")
|
|
(timbre/trace "Trace level - detailed diagnostics")
|
|
(timbre/debug "Debug level - debugging information")
|
|
(timbre/info "Info level - general information")
|
|
(timbre/warn "Warn level - warning message")
|
|
(timbre/error "Error level - error occurred")
|
|
(timbre/fatal "Fatal level - critical failure")
|
|
(timbre/report "Report level - special reporting")
|
|
|
|
;; Example 2: Formatted Logging
|
|
(println "\n--- Example 2: Formatted Logging ---")
|
|
(let [username "alice"
|
|
port 8080
|
|
percentage 95.5]
|
|
(timbre/infof "User %s connected" username)
|
|
(timbre/infof "Server started on port %d" port)
|
|
(timbre/infof "Success rate: %.2f%%" percentage))
|
|
|
|
;; Example 3: Logging with Data
|
|
(println "\n--- Example 3: Logging with Data ---")
|
|
(timbre/info "User login event"
|
|
{:user-id 123
|
|
:username "bob"
|
|
:ip "192.168.1.100"
|
|
:timestamp (System/currentTimeMillis)})
|
|
|
|
;; Example 4: Exception Logging
|
|
(println "\n--- Example 4: Exception Logging ---")
|
|
(try
|
|
(throw (ex-info "Simulated error" {:code 500}))
|
|
(catch Exception e
|
|
(timbre/error e "Operation failed with exception")))
|
|
|
|
;; Example 5: Spy - Log and Return Value
|
|
(println "\n--- Example 5: Spy - Log and Return Value ---")
|
|
(defn calculate [x y]
|
|
(* x y))
|
|
|
|
(let [result (timbre/spy :info (calculate 6 7))]
|
|
(println "Function returned:" result))
|
|
|
|
;; Example 6: Configuration - Setting Minimum Level
|
|
(println "\n--- Example 6: Setting Minimum Level ---")
|
|
(println "Current min level:" (:min-level @timbre/*config*))
|
|
(timbre/set-min-level! :warn)
|
|
(println "After setting to :warn:")
|
|
(timbre/debug "This debug message won't appear")
|
|
(timbre/warn "This warning will appear")
|
|
(timbre/set-min-level! :debug) ; Reset
|
|
|
|
;; Example 7: Scoped Configuration
|
|
(println "\n--- Example 7: Scoped Configuration ---")
|
|
(timbre/info "Normal log level")
|
|
(timbre/with-min-level :trace
|
|
(timbre/trace "Trace enabled in this scope only"))
|
|
(timbre/trace "Back to normal - trace won't show")
|
|
|
|
;; Example 8: Custom Appender
|
|
(println "\n--- Example 8: Custom Appender ---")
|
|
(def custom-logs (atom []))
|
|
|
|
(defn memory-appender
|
|
"Appender that stores logs in memory"
|
|
[]
|
|
{:enabled? true
|
|
:async? false
|
|
:fn (fn [data]
|
|
(swap! custom-logs conj
|
|
{:level (:level data)
|
|
:msg (force (:msg_ data))
|
|
:timestamp (force (:timestamp_ data))}))})
|
|
|
|
(timbre/merge-config!
|
|
{:appenders {:memory (memory-appender)}})
|
|
|
|
(timbre/info "Message 1 to memory")
|
|
(timbre/warn "Message 2 to memory")
|
|
|
|
(println "Captured logs:" @custom-logs)
|
|
|
|
;; Restore default config
|
|
(timbre/set-config! timbre/default-config)
|
|
|
|
;; Example 9: Context/MDC Support
|
|
(println "\n--- Example 9: Context/MDC Support ---")
|
|
(timbre/with-context {:request-id "req-12345" :user-id 456}
|
|
(timbre/info "Processing request")
|
|
(timbre/info "Request completed"))
|
|
|
|
;; Example 10: Conditional Logging with sometimes
|
|
(println "\n--- Example 10: Probabilistic Logging ---")
|
|
(println "Attempting 10 sometimes calls (10% probability):")
|
|
(dotimes [_ 10]
|
|
(timbre/sometimes 0.1
|
|
(print ".")))
|
|
(println " done")
|
|
|
|
;; Example 11: Rate Limiting
|
|
(println "\n--- Example 11: Rate Limiting ---")
|
|
(def rate-limited-logs (atom []))
|
|
|
|
(timbre/merge-config!
|
|
{:appenders
|
|
{:rate-limited
|
|
{:enabled? true
|
|
:rate-limit [[2 1000]] ; Max 2 logs per second
|
|
:fn (fn [data]
|
|
(swap! rate-limited-logs conj (force (:msg_ data))))}}})
|
|
|
|
(println "Sending 5 messages rapidly:")
|
|
(dotimes [i 5]
|
|
(timbre/info (str "Message " (inc i)))
|
|
(Thread/sleep 100))
|
|
|
|
(println "Messages logged:" (count @rate-limited-logs))
|
|
(println "Content:" @rate-limited-logs)
|
|
|
|
;; Restore default
|
|
(timbre/set-config! timbre/default-config)
|
|
|
|
;; Example 12: Custom Output Function
|
|
(println "\n--- Example 12: Custom Output Function ---")
|
|
(defn simple-output-fn
|
|
[{:keys [level ?ns-str msg_]}]
|
|
(str (str/upper-case (name level))
|
|
" [" ?ns-str "] "
|
|
(force msg_)))
|
|
|
|
(timbre/with-merged-config {:output-fn simple-output-fn}
|
|
(timbre/info "Custom formatted message")
|
|
(timbre/error "Another custom format"))
|
|
|
|
;; Example 13: Namespace Filtering
|
|
(println "\n--- Example 13: Namespace Filtering ---")
|
|
(timbre/set-ns-min-level!
|
|
{:deny #{"user"} ; Deny current namespace
|
|
:allow #{}})
|
|
|
|
(timbre/info "This won't appear - namespace filtered")
|
|
|
|
;; Reset namespace filter
|
|
(timbre/set-ns-min-level! {})
|
|
(timbre/info "Namespace filter cleared - this appears")
|
|
|
|
;; Example 14: Log Errors Helper
|
|
(println "\n--- Example 14: Log Errors Helper ---")
|
|
(defn risky-operation []
|
|
(throw (ex-info "Something went wrong" {:error-code 123})))
|
|
|
|
(println "Using log-errors (suppresses exception):")
|
|
(timbre/log-errors
|
|
(risky-operation))
|
|
(println "Execution continued after exception")
|
|
|
|
;; Example 15: Multiple Appenders
|
|
(println "\n--- Example 15: Multiple Appenders ---")
|
|
(def console-logs (atom []))
|
|
(def file-logs (atom []))
|
|
|
|
(timbre/set-config!
|
|
{:min-level :debug
|
|
:appenders
|
|
{:console
|
|
{:enabled? true
|
|
:fn (fn [data]
|
|
(swap! console-logs conj (force (:msg_ data))))}
|
|
:file
|
|
{:enabled? true
|
|
:min-level :warn ; Only warnings and above
|
|
:fn (fn [data]
|
|
(swap! file-logs conj (force (:msg_ data))))}}})
|
|
|
|
(timbre/debug "Debug message")
|
|
(timbre/info "Info message")
|
|
(timbre/warn "Warning message")
|
|
(timbre/error "Error message")
|
|
|
|
(println "Console appender received:" (count @console-logs) "messages")
|
|
(println "File appender received:" (count @file-logs) "messages (warn+)")
|
|
|
|
;; Example 16: Structured Logging Pattern
|
|
(println "\n--- Example 16: Structured Logging Pattern ---")
|
|
(timbre/set-config! timbre/default-config)
|
|
|
|
(defn log-user-action
|
|
[action user-id metadata]
|
|
(timbre/info "User action"
|
|
(merge {:action action
|
|
:user-id user-id
|
|
:timestamp (System/currentTimeMillis)}
|
|
metadata)))
|
|
|
|
(log-user-action :login 789 {:ip "10.0.0.1" :device "mobile"})
|
|
(log-user-action :purchase 789 {:amount 99.99 :currency "USD"})
|
|
|
|
;; Example 17: Environment-Specific Configuration
|
|
(println "\n--- Example 17: Environment-Specific Configuration ---")
|
|
(defn config-for-env
|
|
[env]
|
|
(case env
|
|
:dev {:min-level :trace
|
|
:appenders {:println (appenders/println-appender)}}
|
|
:prod {:min-level :info
|
|
:appenders {:println (appenders/println-appender)}}))
|
|
|
|
(println "Development config:")
|
|
(timbre/with-config (config-for-env :dev)
|
|
(timbre/trace "Trace visible in dev"))
|
|
|
|
(println "Production config:")
|
|
(timbre/with-config (config-for-env :prod)
|
|
(timbre/trace "Trace hidden in prod")
|
|
(timbre/info "Info visible in prod"))
|
|
|
|
;; Example 18: Middleware Example
|
|
(println "\n--- Example 18: Middleware Example ---")
|
|
(defn add-app-version
|
|
[data]
|
|
(assoc data :app-version "1.0.0"))
|
|
|
|
(defn add-environment
|
|
[data]
|
|
(assoc data :environment "development"))
|
|
|
|
(timbre/merge-config!
|
|
{:middleware [add-app-version add-environment]})
|
|
|
|
(timbre/info "Message with middleware-added data")
|
|
|
|
;; Reset to default
|
|
(timbre/set-config! timbre/default-config)
|
|
|
|
(println "\n=== Examples Complete ===")
|