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

Add CIDER log middleware #774

Merged
merged 1 commit into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .clj-kondo/config.edn
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{:hooks {:analyze-call {cider.nrepl.middleware.out/with-out-binding
hooks.core/with-out-binding}}
:lint-as {cider.nrepl.middleware.log-test/with-each-framework clojure.core/let}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

@r0man r0man Jun 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean to export this symbol, so it is picked up by clojure lsp in other projects?

I think we don't need this here. It's a macro defined and used only in the cider-nrepl tests. It it not used by other libraries. But maybe you mean something else?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean to export this symbol, so it is picked up by clojure lsp in other projects?

Sure, if logjam includes that file, any consumers (including cider-nrepl) will pick it up. It's DRYer.

:linters {:unresolved-symbol {:exclude [(cider.nrepl/def-wrapper)
(cider.nrepl.middleware.util.instrument/definstrumenter)
(cider.nrepl.middleware.util.instrument/with-break)
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## master (unreleased)

### New features

* [#773](https://github.com/clojure-emacs/cider-nrepl/pull/773) Add middleware to capture, debug, inspect and view log events emitted by Java logging frameworks.

### Changes

* Bump `orchard` to 0.12.0.
Expand Down
6 changes: 6 additions & 0 deletions doc/modules/ROOT/pages/nrepl-api/supplied_middleware.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@
| `inspect-(start/refresh/pop/push/reset/get-path)`
| Inspect a Clojure expression.

| `wrap-log`
| 0.30.1
| No
| `cider/log-add-appender`, `cider/log-add-consumer`, `cider/log-analyze-stacktrace`, `cider/log-clear-appender`, `cider/log-exceptions`, `cider/log-format-event`, `cider/log-frameworks`, `cider/log-inspect-event`, `cider/log-levels`, `cider/log-loggers`, `cider/log-remove-appender`, `cider/log-remove-consumer`, `cider/log-search`, `cider/log-update-appender`, `cider/log-update-consumer`, `cider/log-threads`
| Capture, debug, inspect and view log events emitted by Java logging frameworks.

| `wrap-macroexpand`
| -
| Yes
Expand Down
2 changes: 2 additions & 0 deletions doc/modules/ROOT/pages/usage.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ under `:repl-options`.
cider.nrepl/wrap-format
cider.nrepl/wrap-info
cider.nrepl/wrap-inspect
cider.nrepl/wrap-log
cider.nrepl/wrap-macroexpand
cider.nrepl/wrap-ns
cider.nrepl/wrap-spec
Expand Down Expand Up @@ -153,6 +154,7 @@ That's how CIDER's nREPL handler is created:
cider.nrepl/wrap-format
cider.nrepl/wrap-info
cider.nrepl/wrap-inspect
cider.nrepl/wrap-log
cider.nrepl/wrap-macroexpand
cider.nrepl/wrap-ns
cider.nrepl/wrap-out
Expand Down
7 changes: 6 additions & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
^:inline-dep [cljfmt "0.9.2" :exclusions [org.clojure/clojurescript]]
^:inline-dep [org.clojure/tools.namespace "1.3.0"]
^:inline-dep [org.clojure/tools.trace "0.7.11"]
^:inline-dep [org.clojure/tools.reader "1.3.6"]]
^:inline-dep [org.clojure/tools.reader "1.3.6"]
[mx.cider/logjam "0.1.1"]]
:exclusions [org.clojure/clojure] ; see Clojure version matrix in profiles below

:pedantic? ~(if (System/getenv "CI")
Expand Down Expand Up @@ -102,9 +103,13 @@
:test {:global-vars {*assert* true}
:source-paths ["test/src"]
:java-source-paths ["test/java"]
:jvm-opts ["-Djava.util.logging.config.file=test/resources/logging.properties"]
:resource-paths ["test/resources"]
:dependencies [[boot/base "2.8.3"]
[boot/core "2.8.3"]
;; 1.3.7 and 1.4.7 are working, but we need 1.3.7 for JDK8
[ch.qos.logback/logback-classic "1.3.7"]
[org.clojure/test.check "1.1.1"]
[org.apache.httpcomponents/httpclient "4.5.13" :exclusions [commons-logging]]
[leiningen-core "2.9.10" :exclusions [org.clojure/clojure
commons-codec
Expand Down
130 changes: 130 additions & 0 deletions src/cider/nrepl.clj
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,136 @@ Depending on the type of the return value of the evaluation this middleware may
"var-name" "The var name"}
:returns {"status" "\"done\""}}}}))

(def-wrapper wrap-log cider.nrepl.middleware.log/handle-log
{:doc "Middleware that captures log events and makes them inspect-able."
:requires #{#'session #'wrap-print}
:handles
{"cider/log-add-appender"
{:doc "Add an appender to a log framework."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."
"filters" "A map from filter name to filter condition."
"size" "The number of events the appender keeps in memory."
"threshold" "The threshold in percent used to cleanup events."}
:optional {"logger" "The name of the logger to attach to."}
:returns {"status" "done"
"cider/log-add-appender" "The appender that was added."}}

"cider/log-add-consumer"
{:doc "Add a consumer to an appender of a log framework."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."
"filters" "A map from filter name to filter condition."}
:returns {"status" "done"
"cider/log-add-consumer" "The consumer that was added."}}

"cider/log-analyze-stacktrace"
{:doc "Analyze the stacktrace of a log event."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."
"event" "The id of the event to inspect."}
:returns {"status" "done"}}

"cider/log-clear-appender"
{:doc "Clear all events of a log appender."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."}
:returns {"status" "done"
"cider/log-clear-appender" "The appender that was cleared."}}

"cider/log-exceptions"
{:doc "Return the exceptions and their frequencies for the given framework and appender."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."}
:returns {"status" "done"
"cider/log-exceptions" "A map from exception name to event frequency."}}

"cider/log-frameworks"
{:doc "Return the available log frameworks."
:returns {"status" "done"
"cider/log-frameworks" "A list of log frameworks."}}

"cider/log-format-event"
{:doc "Format a log event."
:requires {"framework" "The id of the log framework."
"appender" "The name of the log appender."
"event" "The id of the log event."}
:optional wrap-print-optional-arguments
:returns {"status" "done"
"cider/log-format-event" "The formatted log event."}}

"cider/log-inspect-event"
{:doc "Inspect a log event."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."
"event" "The id of the event to inspect."}
:returns {"status" "done"
"value" "The inspection result."}}

"cider/log-levels"
{:doc "Return the log levels and their frequencies for the given framework and appender."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."}
:returns {"status" "done"
"cider/log-levels" "A map from log level to event frequency."}}

"cider/log-loggers"
{:doc "Return the loggers and their frequencies for the given framework and appender."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."}
:returns {"status" "done"
"cider/log-loggers" "A map from logger name to event frequency."}}

"cider/log-remove-appender"
{:doc "Remove an appender from a log framework."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."}
:returns {"status" "done"
"cider/log-remove-appender" "The removed appender."}}

"cider/log-remove-consumer"
{:doc "Remove a consumer from the appender of a log framework."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."
"consumer" "The name of the consumer."}
:returns {"status" "done"
"cider/log-add-consumer" "The removed consumer."}}

"cider/log-update-appender"
{:doc "Update the appender of a log framework."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."
"filters" "A map from filter name to filter condition."
"size" "The number of events the appender keeps in memory."
"threshold" "The threshold in percent used to cleanup events."}
:returns {"status" "done"
"cider/log-update-appender" "The updated appender."}}

"cider/log-update-consumer"
{:doc "Update the consumer of a log appender."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."
"consumer" "The name of the consumer."
"filters" "A map from filter name to filter condition."}
:returns {"status" "done"
"cider/log-update-consumer" "The consumer that was updated."}}

"cider/log-search"
{:doc "Search the log events of an appender."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."}
:optional {"filters" "A map from filter name to filter condition."
"limit" "Number of log events to return."}
:returns {"status" "done"
"cider/log-search" "The list of log events matching the search."}}

"cider/log-threads"
{:doc "Return the threads and their frequencies for the given framework and appender."
:requires {"framework" "The id of the log framework."
"appender" "The name of the appender."}
:returns {"status" "done"
"cider/log-threads" "A map from thread name to event frequency."}}}})

(def-wrapper wrap-macroexpand cider.nrepl.middleware.macroexpand/handle-macroexpand
(cljs/requires-piggieback
{:doc "Macroexpansion middleware."
Expand Down
1 change: 1 addition & 0 deletions src/cider/nrepl/middleware.clj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
cider.nrepl/wrap-format
cider.nrepl/wrap-info
cider.nrepl/wrap-inspect
cider.nrepl/wrap-log
cider.nrepl/wrap-macroexpand
cider.nrepl/wrap-ns
cider.nrepl/wrap-out
Expand Down
Loading