Skip to content

Commit 15341b1

Browse files
committed
Merge pull request #12 from conormcd/logging
Add logging
2 parents 496f1aa + 3963888 commit 15341b1

15 files changed

+326
-89
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ pom.xml.asc
1010
.hgignore
1111
.hg/
1212
doc/api
13+
test/debug.log

project.clj

+6-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
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"]]
10-
:profiles {:dev {:plugins [[lein-codox "0.9.1"]]}}
9+
[org.clojure/tools.logging "0.3.1"]
10+
[digest "1.4.4"]
11+
[net.n01se/clojure-jna "1.0.0"]
12+
[robert/hooke "1.3.0"]]
13+
:profiles {:dev {:plugins [[lein-codox "0.9.1"]]}
14+
:test {:jvm-opts ["-Djava.util.logging.config.file=test/logging.properties"]}}
1115
:deploy-repositories ^:replace [["clojars" {:url "https://clojars.org/repo"
1216
:username [:gpg :env/clojars_username]
1317
:password [:gpg :env/clojars_password]

release.sh

+2
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ build_jars() {
8080

8181
save_artifacts() {
8282
if [ -n "${CIRCLE_ARTIFACTS:-}" ]; then
83+
echo "Saving debug log..."
84+
cp test/debug.log "${CIRCLE_ARTIFACTS}"
8385
echo "Copying JARs to CircleCI artifacts..."
8486
find . -name '*.jar' -exec cp {} "${CIRCLE_ARTIFACTS}" \;
8587
fi

src/clj_libssh2/agent.clj

+19-18
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"Functions for interacting with an SSH agent. The agent is expected to be
33
available on the UNIX domain socket referred to by the SSH_AUTH_SOCK
44
environment variable."
5-
(:require [clj-libssh2.error :as error :refer [handle-errors with-timeout]]
5+
(:require [clojure.tools.logging :as log]
6+
[clj-libssh2.error :as error :refer [handle-errors with-timeout]]
67
[clj-libssh2.libssh2 :as libssh2]
78
[clj-libssh2.libssh2.agent :as libssh2-agent])
89
(:import [com.sun.jna.ptr PointerByReference]))
@@ -33,10 +34,10 @@
3334
(case ret
3435
0 (.getValue id)
3536
1 nil
36-
(throw (ex-info "libssh2_agent_get_identity returned a bad value."
37-
{:function "libssh2_agent_get_identity"
38-
:return ret
39-
:session session})))))
37+
(error/raise "libssh2_agent_get_identity returned a bad value."
38+
{:function "libssh2_agent_get_identity"
39+
:return ret
40+
:session session}))))
4041

4142
(defn authenticate
4243
"Attempt to authenticate a session using the agent.
@@ -56,25 +57,25 @@
5657
(when (nil? ssh-agent)
5758
(error/maybe-throw-error session libssh2/ERROR_ALLOC))
5859
(try
60+
(log/info "Connecting to the SSH agent...")
5961
(handle-errors session
6062
(with-timeout :agent
6163
(libssh2-agent/connect ssh-agent)))
62-
(when-not (loop [success false
63-
previous nil]
64-
(if success
65-
success
66-
(if-let [id (get-identity session ssh-agent previous)]
67-
(recur
68-
(= 0 (with-timeout :agent
69-
(libssh2-agent/userauth ssh-agent username id)))
70-
id)
71-
false)))
72-
(throw (ex-info "Failed to authenticate using the SSH agent."
73-
{:username username
74-
:session session})))
64+
(when (loop [previous nil]
65+
(log/info "Fetching an ID to authenticate with...")
66+
(if-let [id (get-identity session ssh-agent previous)]
67+
(when-not (= 0 (with-timeout :agent
68+
(libssh2-agent/userauth ssh-agent username id)))
69+
(recur id))
70+
:fail))
71+
(error/raise "Failed to authenticate using the SSH agent."
72+
{:username username
73+
:session session}))
74+
(log/info "Successfully authenticated using the SSH agent.")
7575
true
7676
(finally
7777
(handle-errors session
7878
(with-timeout :agent
79+
(log/info "Disconnecting from the agent...")
7980
(libssh2-agent/disconnect ssh-agent)))
8081
(libssh2-agent/free ssh-agent)))))

src/clj_libssh2/authentication.clj

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
(ns clj-libssh2.authentication
22
"Authenticate a session."
33
(:require [clojure.java.io :refer [file]]
4+
[clojure.tools.logging :as log]
45
[clj-libssh2.agent :as agent]
5-
[clj-libssh2.error :refer [handle-errors with-timeout]]
6+
[clj-libssh2.error :as error :refer [handle-errors with-timeout]]
67
[clj-libssh2.libssh2.userauth :as libssh2-userauth])
78
(:import [java.io FileNotFoundException]
89
[clojure.lang PersistentArrayMap]))
@@ -47,13 +48,15 @@
4748

4849
(defmethod authenticate AgentCredentials
4950
[session credentials]
51+
(log/info "Authenticating using an SSH agent.")
5052
(agent/authenticate session (:username credentials)))
5153

5254
(defmethod authenticate KeyCredentials
5355
[session credentials]
56+
(log/info "Authenticating using a keypair.")
5457
(doseq [keyfile (map #(% credentials) [:private-key :public-key])]
5558
(when-not (.exists (file keyfile))
56-
(throw (FileNotFoundException. keyfile))))
59+
(error/raise (FileNotFoundException. keyfile))))
5760
(handle-errors session
5861
(with-timeout :auth
5962
(libssh2-userauth/publickey-fromfile (:session session)
@@ -65,6 +68,7 @@
6568

6669
(defmethod authenticate PasswordCredentials
6770
[session credentials]
71+
(log/info "Authenticating using a username and password.")
6872
(handle-errors session
6973
(with-timeout :auth
7074
(libssh2-userauth/password (:session session)
@@ -74,12 +78,13 @@
7478

7579
(defmethod authenticate PersistentArrayMap
7680
[session credentials]
81+
(log/info "Deriving correct credential type from a map...")
7782
(loop [m [map->KeyCredentials map->PasswordCredentials map->AgentCredentials]]
7883
(let [creds ((first m) credentials)]
7984
(if (valid? creds)
8085
(authenticate session creds)
8186
(if (< 1 (count m))
8287
(recur (rest m))
83-
(throw (ex-info "Failed to determine credentials type."
84-
{:items (keys credentials)
85-
:session session})))))))
88+
(error/raise "Failed to determine credentials type."
89+
{:items (keys credentials)
90+
:session session}))))))

src/clj_libssh2/channel.clj

+20-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
(ns clj-libssh2.channel
22
"Functions for manipulating channels within an SSH session."
33
(:refer-clojure :exclude [read])
4-
(:require [net.n01se.clojure-jna :as jna]
5-
[clj-libssh2.error :refer [handle-errors]]
4+
(:require [clojure.tools.logging :as log]
5+
[net.n01se.clojure-jna :as jna]
6+
[clj-libssh2.error :as error :refer [handle-errors]]
67
[clj-libssh2.libssh2 :as libssh2]
78
[clj-libssh2.libssh2.channel :as libssh2-channel]
89
[clj-libssh2.libssh2.scp :as libssh2-scp]
@@ -23,6 +24,7 @@
2324
2425
0 on success. An exception will be thrown if an error occurs."
2526
[session channel]
27+
(log/info "Closing channel.")
2628
(block session
2729
(handle-errors session (libssh2-channel/close channel))))
2830

@@ -41,6 +43,7 @@
4143
4244
0 on success. An exception will be thrown if an error occurs."
4345
[session channel commandline]
46+
(log/info "Executing a command on the remote host.")
4447
(block session
4548
(handle-errors session (libssh2-channel/exec channel commandline))))
4649

@@ -63,6 +66,7 @@
6366
:err-msg The error message.
6467
:lang-tag The language tag, if provided."
6568
[session channel]
69+
(log/info "Collecting the exit signal data from the remote host.")
6670
(let [->str (fn [string-ref length-ref]
6771
(let [string (.getValue string-ref)
6872
length (.getValue length-ref)]
@@ -97,6 +101,7 @@
97101
98102
The numeric exit code from the remote process."
99103
[channel]
104+
(log/info "Collecting the exit code from the remote process.")
100105
(libssh2-channel/get-exit-status channel))
101106

102107
(defn free
@@ -125,6 +130,7 @@
125130
126131
A newly-allocated channel object, or throws exception on failure."
127132
[session]
133+
(log/info "Opening a new channel.")
128134
(block-return session (libssh2-channel/open-session (:session session))))
129135

130136
(defn open-scp-recv
@@ -141,6 +147,7 @@
141147
the file information as reported by the remote host. Throws exception on
142148
failure."
143149
[session remote-path]
150+
(log/info "Opening a new channel to receive a file using SCP.")
144151
(let [fileinfo (Stat/newInstance)]
145152
{:channel (block-return session
146153
(libssh2-scp/recv (:session session) remote-path fileinfo))
@@ -164,6 +171,7 @@
164171
165172
A newly-allocated channel object for sending a file via SCP."
166173
[session remote-path {:keys [atime mode mtime size] :as props}]
174+
(log/info "Opening a new channel to send a file using SCP.")
167175
(let [mode (or mode 0644)
168176
mtime (or mtime 0)
169177
atime (or atime 0)]
@@ -182,6 +190,7 @@
182190
183191
0 on success, throws an exception on failure."
184192
[session channel]
193+
(log/info "Notifying the remote host of EOF")
185194
(block session (handle-errors session (libssh2-channel/send-eof channel))))
186195

187196
(defn setenv
@@ -204,14 +213,15 @@
204213
205214
0 on success. Errors will result in exceptions."
206215
[session channel env]
216+
(log/info "Setting environment variables on the remote host.")
207217
(let [->str (fn [v]
208218
(cond (nil? v) ""
209219
(keyword? v) (name v)
210220
:else (str v)))
211221
fail-if-forbidden (fn [ret]
212222
(if (= libssh2/ERROR_CHANNEL_REQUEST_DENIED ret)
213-
(throw (ex-info "Setting environment variables is not permitted."
214-
{:session session}))
223+
(error/raise "Setting environment variables is not permitted."
224+
{:session session})
215225
ret))]
216226
(doseq [[k v] env]
217227
(block session
@@ -394,11 +404,11 @@
394404
(when (and (= pump-fn pull)
395405
(= :eagain new-status)
396406
(< (-> session :options :read-timeout) (- now last-read-time)))
397-
(throw (ex-info "Read timeout on a channel."
398-
{:direction (-> stream :direction name)
399-
:id (-> stream :id)
400-
:timeout (-> session :options :read-timeout)
401-
:session session})))
407+
(error/raise "Read timeout on a channel."
408+
{:direction (-> stream :direction name)
409+
:id (-> stream :id)
410+
:timeout (-> session :options :read-timeout)
411+
:session session}))
402412
(assoc stream :status new-status :last-read-time now))
403413
stream))
404414

@@ -427,6 +437,7 @@
427437
:status Always :eof
428438
:stream The OutputStream object connected to the SSH stream."
429439
[session channel input-streams output-streams]
440+
(log/info "Pumping all the streams on a channel.")
430441
(let [now (System/currentTimeMillis)
431442
write-size (-> session :options :write-chunk-size)
432443
streams (concat (->> input-streams

src/clj_libssh2/error.clj

+37-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
(ns clj-libssh2.error
22
"Utility functions for making error handling easier when calling native
33
functions."
4-
(:require [clj-libssh2.libssh2 :as libssh2]
4+
(:require [clojure.tools.logging :as log]
5+
[clj-libssh2.libssh2 :as libssh2]
56
[clj-libssh2.libssh2.session :as libssh2-session])
67
(:import [com.sun.jna.ptr IntByReference PointerByReference]))
78

@@ -65,6 +66,31 @@
6566
libssh2/ERROR_BAD_SOCKET "Bad socket."
6667
libssh2/ERROR_KNOWN_HOSTS "Failed to parse known hosts file."})
6768

69+
(defmacro raise
70+
"Log an error and then throw an exception with the same error message and
71+
optionally some additional information.
72+
73+
Arguments:
74+
75+
message The message to be logged. This will also be the primary
76+
message of the exception. If this message is a Throwable,
77+
then the additional information will be discarded and the
78+
passed-in Throwable will be rethrown after it's logged.
79+
additional-info A map of additional information which might be useful to
80+
anyone debugging an error reported by this exception."
81+
([message]
82+
`(raise ~message {}))
83+
([message additional-info]
84+
`(let [message# ~message
85+
additional-info# ~additional-info]
86+
(try
87+
(throw (if (instance? Throwable message#)
88+
message#
89+
(ex-info message# additional-info#)))
90+
(catch Exception e#
91+
(log/log :error e# (.getMessage e#))
92+
(throw e#))))))
93+
6894
(defn session-error-message
6995
"Call libssh2_session_last_error and return the error message given or nil if
7096
there was no error.
@@ -117,13 +143,13 @@
117143
(not= libssh2/ERROR_EAGAIN error-code))
118144
(let [session-message (session-error-message session)
119145
default-message (get error-messages error-code)]
120-
(throw (ex-info (or session-message
121-
default-message
122-
(format "An unknown error occurred: %d" error-code))
123-
{:error default-message
124-
:error-code error-code
125-
:session session
126-
:session-error session-message})))))
146+
(raise (or session-message
147+
default-message
148+
(format "An unknown error occurred: %d" error-code))
149+
{:error default-message
150+
:error-code error-code
151+
:session session
152+
:session-error session-message}))))
127153

128154
(defmacro handle-errors
129155
"Run some code that might return a negative number to indicate an error.
@@ -198,9 +224,9 @@
198224
timeout# (get-timeout ~timeout)]
199225
(loop [timedout# false]
200226
(if timedout#
201-
(throw (ex-info "Timeout exceeded."
202-
{:timeout ~timeout
203-
:timeout-length timeout#}))
227+
(raise (format "Timeout of %d ms exceeded" timeout#)
228+
{:timeout ~timeout
229+
:timeout-length timeout#})
204230
(let [r# (do ~@body)]
205231
(if (= r# libssh2/ERROR_EAGAIN)
206232
(recur (< timeout# (- (System/currentTimeMillis) start#)))

0 commit comments

Comments
 (0)