Skip to content

Commit 401dc16

Browse files
committed
Add the capability to trace all the functions.
`(clj-libssh2.logging/init)` will cause all of the functions in the library to log their inputs and outputs at level :trace. This can produce a *lot* of output, so it's advisable to configure logging carefully before enabling this. Both `clj-libssh2.logging/trace-fn` and `clj-libssh2.logging/trace-ns` can be used for more fine grained tracing of this library.
1 parent 496f1aa commit 401dc16

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed

project.clj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
:pedantic? :abort
77
:java-source-paths ["src-java"]
88
:dependencies [[org.clojure/clojure "1.7.0"]
9-
[net.n01se/clojure-jna "1.0.0"]]
9+
[org.clojure/tools.logging "0.3.1"]
10+
[net.n01se/clojure-jna "1.0.0"]
11+
[robert/hooke "1.3.0"]]
1012
:profiles {:dev {:plugins [[lein-codox "0.9.1"]]}}
1113
:deploy-repositories ^:replace [["clojars" {:url "https://clojars.org/repo"
1214
:username [:gpg :env/clojars_username]

src/clj_libssh2/logging.clj

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
(ns clj-libssh2.logging
2+
"Functions for weaving some detailed debug logging into every function in
3+
clj-libssh2."
4+
(:require [clojure.tools.logging :as log]
5+
[clojure.pprint :refer [pprint]]
6+
[robert.hooke :as hook]))
7+
8+
(defn- spy-fn
9+
"Create a function that can be used as a hook to log the call and result from
10+
a given function. This is somewhat similar to the log/spy macro in
11+
clojure.tools.logging but that doesn't work too neatly with robert.hooke.
12+
13+
Arguments:
14+
15+
fn-var A var pointing to the function we'll be tracing.
16+
level The level at which the messages should be logged.
17+
18+
Return:
19+
20+
A function of the form `(fn [f & args])` which can be given to
21+
robert.hooke/add-hook to hook a function."
22+
[fn-var level]
23+
(let [fn-meta (meta fn-var)
24+
fn-name (symbol (str (ns-name (:ns fn-meta))) (str (:name fn-meta)))
25+
make-message (fn [args result]
26+
(format "%s => %s"
27+
(with-out-str (pprint (cons fn-name args)))
28+
(with-out-str (pprint result))))]
29+
(fn [f & args]
30+
(try
31+
(let [result (apply f args)]
32+
(log/log level (make-message args result))
33+
result)
34+
(catch Throwable t
35+
(log/log level t (make-message args t))
36+
(throw t))))))
37+
38+
(defn trace-fn
39+
"Hook a function so that all calls to it (and the results of those calls) are
40+
logged at a given level.
41+
42+
Arguments:
43+
44+
fn-var A var pointing to the function to trace.
45+
level The log level at which the function call and result should be logged.
46+
47+
Return:
48+
49+
See robert.hooke/add-hook for the description of the return value."
50+
[fn-var level]
51+
(hook/add-hook fn-var (spy-fn fn-var level)))
52+
53+
(defn trace-ns
54+
"Apply (trace-fn % level) to all functions in a given namespace.
55+
56+
Arguments:
57+
58+
ns-sym The symbolic name of a namespace.
59+
level The level to log all calls at.
60+
61+
Return:
62+
63+
nil"
64+
[ns-sym level]
65+
(doseq [fn-var (filter #(fn? (var-get %)) (vals (ns-interns ns-sym)))]
66+
(trace-fn fn-var level)))
67+
68+
(defn- init*
69+
"Initialise the logging of clj-libssh2 by applying trace-ns to all of the
70+
namespaces in the library if debug logging is enabled."
71+
[]
72+
(doseq [nmspc (all-ns)]
73+
(when (and (not (= 'clj-libssh2.logging (ns-name nmspc)))
74+
(re-find #"^clj-libssh2\." (str (ns-name nmspc))))
75+
(trace-ns nmspc :trace))))
76+
77+
(def ^{:arglists '([])} init
78+
"Initialise the logging of clj-libssh2 by applying trace-ns to all of the
79+
namespaces in the library if debug logging is enabled."
80+
(memoize init*))

0 commit comments

Comments
 (0)