   "Controls whether operation labels are logged on entry to the [[track]] macro. By default (nil), no
   logging takes places.  Otherwise, this is a logging level (such as :debug or :info) to be used."
   nil)
+
+(defn get-logger
+  "Determines the logger instance for a namespace (by leveraging some clojure.tools.logging internals)."
+  [namespace]
+  (impl/get-logger l/*logger-factory* namespace))
 
 (def ^:private ^Map log-exceptions?
   (WeakHashMap.))

    (.get log-exceptions? (Thread/currentThread))))

(defn- label-to-string
  "Converts a trace to a string; a trace may be a function which is invoked, a string, or any object that can be converted to a string."
  [message]
  (str (if (fn? message) (message) message)))


         (str/join writer/eol)
         (error logger))))

(defn checkpoint*
  "The main implementation of [[checkpoint]], using a specific logger.

  :logger
  : logger to use when logging the operation trace.

  :f
  : function to evaluate.

  The result of the function is returned.

  If the function throws an exception, it may be logged (and rethrown).  When the exception is logged,
  it includes the operation trace (the sequence of active operation labels), then the formatted exception.

  In the logging case, the exception is rethrown, wrapped as a new ex-info exception, with :operation-trace
  as the vector of operation label strings."
  {:added "0.1.5"}
  [logger f]
  (try
    (set-should-log-operations! true)
    (f)
    (catch Throwable t
      (if (should-log-operations?)
        (let [trace-label-strings (operation-labels)]
          (log-trace-label-stack logger trace-label-strings t)
          (set-should-log-operations! false)
          (throw (ex-info (to-message t)
                          {:operation-trace trace-label-strings}
                          t)))
        (throw t)))))

(defmacro checkpoint
  "Establishes a checkpoint, a point at which a thrown exception results in
  logging of the operation trace.

  checkpoint is useful when flow of control passes from one thread to another, such as
  when using clojure.core.async. Although the operation trace, being stored in a dynamic var,
  will be conveyed to the new thread, the exception handler necessary to report an exception
  is not. checkpoint provides that exception handler."
  {:added "0.1.5"}
  [& body]
  `(checkpoint* (get-logger ~*ns*) (fn [] ~@body)))

(defn track*
  "Tracks the execution of a function of no arguments. The [[track]] macro converts into a call to track*.
  Uses [[checkpoint]].
  
  logger
  : Logger where logging should occur (as defined by the clojure.tools.logging Logger protocol)

  label
  : String, object, or function. If a function, the function will only be evaluated if the message
    needs to be printed (when an exception occurs, or when logging traces via [[*log-trace-level*]]).

  f
  : function to invoke. track* returns the result from this function."
