Skip to content

Commit 09a8f9a

Browse files
committed
Add CIDER Log Mode
1 parent 1367b25 commit 09a8f9a

File tree

10 files changed

+1743
-2
lines changed

10 files changed

+1743
-2
lines changed

.dir-locals.el

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
(cl-defun . 2)
2929
(with-parsed-tramp-file-name . 2)
3030
(thread-first . 0)
31-
(thread-last . 0)))))
31+
(thread-last . 0)
32+
(transient-define-prefix . defmacro)
33+
(transient-define-suffix . defmacro)))))
3234

3335
;; To use the bug-reference stuff, do:
3436
;; (add-hook 'text-mode-hook #'bug-reference-mode)

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### New features
66

7+
- [#3352](https://github.com/clojure-emacs/cider/pull/3352) Add CIDER Log Mode, a major mode that allows you to capture, debug, inspect and view log events emitted by Java logging frameworks.
78
- [#3354](https://github.com/clojure-emacs/cider/issues/3354): Add new customization variable `cider-reuse-dead-repls` to control how dead REPL buffers are reused on new connections.
89

910
### Bugs fixed

cider-eval.el

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ If CONNECTION is nil, use `cider-current-repl'."
320320
"cider.nrepl/wrap-format"
321321
"cider.nrepl/wrap-info"
322322
"cider.nrepl/wrap-inspect"
323+
"cider.nrepl/wrap-log"
323324
"cider.nrepl/wrap-macroexpand"
324325
"cider.nrepl/wrap-ns"
325326
"cider.nrepl/wrap-out"

cider-log.el

Lines changed: 1403 additions & 0 deletions
Large diffs are not rendered by default.

cider-mode.el

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
(require 'clojure-mode)
3535
(require 'cider-eval)
36+
(require 'cider-log)
3637
(require 'cider-test) ; required only for the menu
3738
(require 'cider-eldoc)
3839
(require 'cider-resolve)
@@ -529,6 +530,12 @@ higher precedence."
529530
(define-key map (kbd "C-c C-? C-d") #'cider-xref-fn-deps-select)
530531
(define-key map (kbd "C-c C-q") #'cider-quit)
531532
(define-key map (kbd "C-c M-r") #'cider-restart)
533+
(define-key map (kbd "C-c l a") #'cider-log-appender)
534+
(define-key map (kbd "C-c l c") #'cider-log-consumer)
535+
(define-key map (kbd "C-c l e") #'cider-log-event)
536+
(define-key map (kbd "C-c l f") #'cider-log-framework)
537+
(define-key map (kbd "C-c l i") #'cider-log-info)
538+
(define-key map (kbd "C-c l l") #'cider-log)
532539
(dolist (variable '(cider-mode-interactions-menu
533540
cider-mode-eval-menu
534541
cider-mode-menu))

cider.el

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
;; Maintainer: Bozhidar Batsov <[email protected]>
1313
;; URL: http://www.github.com/clojure-emacs/cider
1414
;; Version: 1.8.0-snapshot
15-
;; Package-Requires: ((emacs "26") (clojure-mode "5.16.0") (parseedn "1.0.6") (queue "0.2") (spinner "1.7") (seq "2.22") (sesman "0.3.2"))
15+
;; Package-Requires: ((emacs "26") (clojure-mode "5.16.0") (parseedn "1.0.6") (queue "0.2") (spinner "1.7") (seq "2.22") (sesman "0.3.2") (logview "0.16.1") (transient "0.4.1"))
1616
;; Keywords: languages, clojure, cider
1717

1818
;; This program is free software: you can redistribute it and/or modify
495 KB
Loading

doc/modules/ROOT/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
** xref:debugging/debugger.adoc[Debugger]
3939
** xref:debugging/enlighten.adoc[Enlighten]
4040
** xref:debugging/inspector.adoc[Inspector]
41+
** xref:debugging/logging.adoc[Logging]
4142
** xref:debugging/macroexpansion.adoc[Macroexpansion]
4243
** xref:debugging/profiling.adoc[Profiling]
4344
** xref:debugging/tracing.adoc[Tracing]
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
= Logging
2+
:experimental:
3+
4+
CIDER Log Mode allows you to capture, debug, inspect and view log
5+
events emitted by Java logging frameworks. The captured log events can
6+
be searched, streamed to the client, pretty printed and are integrated
7+
with the CIDER link:inspector.html[Inspector] and
8+
link:../usage/dealing_with_errors.html[Stacktrace Mode]. Here is a
9+
screenshot of CIDER Log Mode in action.
10+
11+
image::cider-log.png[CIDER Log]
12+
13+
NOTE: The screenshot displays the list of log events in the
14+
`+*cider-log*+` buffer on the left. To the right, a log event is
15+
visible in the `+*cider-inspect*+` buffer, where the exception of the
16+
event is also displayed in the CIDER Stacktrace Mode. From the
17+
Stacktrace Mode buffer you can jump to the source of each frame. At
18+
the bottom the CIDER log menu is shown from which you can perform
19+
logging related actions.
20+
21+
== Features
22+
23+
- Browse Javadocs and website of log framework.
24+
- Search log events and show them in buffers.
25+
- link:../usage/pretty_printing.html[Pretty Print] log events.
26+
- Show log events in the CIDER link:inspector.html[Inspector]
27+
- Show log event exceptions in the CIDER link:../usage/dealing_with_errors.html[Stacktrace Mode]
28+
29+
== Usage
30+
31+
To use CIDER Log Mode, type kbd:[C-c l l] or kbd:[M-x cider-log] in
32+
any buffer that has a CIDER https://github.com/vspinu/sesman[Sesman]
33+
session attached to it. The first time you run the command, it will
34+
prompt you to select a log framework to use, and then attach a log
35+
appender to the root logger of the selected framework. After the log
36+
appender has been attached, the `cider-log` command will show a
37+
https://www.gnu.org/software/emacs/manual/html_mono/transient.html[Transient]
38+
menu, from which you can take further actions, like managing the log
39+
framework, appenders, consumers and events.
40+
41+
To view log events and stream them to your client, type kbd:[es]
42+
(Search log events) followed by kbd:[s]. This will open the
43+
`+*cider-log*+` buffer showing any log events captured thus far. It will
44+
also add a log consumer to this buffer, which receives newly-arriving
45+
log events.
46+
47+
NOTE: The `+*cider-log*+` buffer might initially be empty, and you may
48+
see a `No log events found` message. This is because nothing has been
49+
logged between adding the appender and searching for events. So, now
50+
would be a good time to run some code that triggers a log event for
51+
the selected framework.
52+
53+
=== Keybindings
54+
55+
|===
56+
| Command | Keyboard shortcut | Description
57+
58+
| `cider-log`
59+
| kbd:[C-c l l]
60+
| Show the CIDER log menu.
61+
62+
| `cider-log-framework`
63+
| kbd:[C-c l f]
64+
| Show the menu to manage a logging framework.
65+
66+
| `cider-log-appender`
67+
| kbd:[C-c l a]
68+
| Show the menu to manage appenders of a logging framework.
69+
70+
| `cider-log-consumer`
71+
| kbd:[C-c l c]
72+
| Show the menu to manage consumers listening to log events.
73+
74+
| `cider-log-event`
75+
| kbd:[C-c l e]
76+
| Show the menu to manage log events.
77+
|===
78+
79+
== Log framework
80+
81+
CIDER Log Mode supports log frameworks that allow reconfiguration at
82+
run time. More specifically the framework should support attaching log
83+
appenders to loggers, in order to capture events.
84+
85+
At the moment the following log frameworks are supported:
86+
87+
- https://docs.oracle.com/en/java/javase/19/core/java-logging-overview.html[Java Util Logging]
88+
- https://logback.qos.ch[Logback]
89+
90+
There is some https://github.com/clojure-emacs/logjam/issues/2[work in
91+
progress] to support https://logging.apache.org/log4j/2.x/[Log4j] as
92+
well, but there are some
93+
https://stackoverflow.com/a/17842174/12711900[difficulties] with
94+
configuration changes made at runtime, which are wiped out by the
95+
Log4j2 reconfiguration mechanism.
96+
97+
=== Keybindings
98+
99+
|===
100+
| Command | Keyboard shortcut | Description
101+
102+
| `cider-log-set-framework`
103+
| kbd:[C-c l f s]
104+
| Select the log framework to use.
105+
106+
| `cider-log-set-buffer`
107+
| kbd:[C-c l f b]
108+
| Select the log buffer to user. Default: `+*cider-log*+`
109+
110+
| `cider-log-browse-javadocs`
111+
| kbd:[C-c l f j]
112+
| Browse the Javadocs of the log framework.
113+
114+
| `cider-log-browse-website`
115+
| kbd:[C-c l f w]
116+
| Browse the website of the log framework.
117+
|===
118+
119+
== Log Appender
120+
121+
In order to capture log events, a log appender needs to be attached to
122+
a logger of a framework. Once an appender is attached to a logger it
123+
captures the log events emitted by the framework in an in-memory
124+
atom. A log appender can be configured to have a certain size
125+
(default: 100000) and a threshold in percentage (default: 10). Log
126+
events are cleared from the appender when threshold (appender size
127+
plus threshold) is reached. Additionally an appender can be configured
128+
to only capture events that match a set of filters.
129+
130+
=== Keybindings
131+
132+
The following keybindings can be used to interact with log appenders.
133+
134+
|===
135+
| Command | Keyboard shortcut | Description
136+
137+
| `cider-log-appender`
138+
| kbd:[C-c l a]
139+
| Show the transient menu to manage log appenders.
140+
141+
| `cider-log-add-appender`
142+
| kbd:[C-c l a a]
143+
| Add a log appender to a logger.
144+
145+
| `cider-log-clear-appender`
146+
| kbd:[C-c l a c]
147+
| Clear all captured events of a log appender.
148+
149+
| `cider-log-kill-appender`
150+
| kbd:[C-c l a k]
151+
| Kill a log appender by removing it from the logger.
152+
153+
| `cider-log-update-appender`
154+
| kbd:[C-c l a u]
155+
| Update the filters, size or threshold of a log appender.
156+
|===
157+
158+
== Log Consumer
159+
160+
Log events can be streamed to a client by attaching a log consumer to
161+
an appender. Once a log consumer has been attached to an appender, it
162+
will receive events from the appender. Similar to log appenders,
163+
consumers can also be configured with a set of filters to only receive
164+
certain events.
165+
166+
=== Keybindings
167+
168+
The following keybindings can be used to interact with log consumers.
169+
170+
|===
171+
| Command | Main / Consumer Menu | Keyboard shortcut | Description
172+
173+
| `cider-log-consumer`
174+
|
175+
| kbd:[C-c l c]
176+
| Show the transient menu to manage log consumers.
177+
178+
| `cider-log-add-consumer`
179+
| kbd:[ca] / kbd:[a]
180+
| kbd:[C-c l c a]
181+
| Add a log consumer to a log appender streaming event to the client.
182+
183+
| `cider-log-kill-consumer`
184+
| kbd:[ck] / kbd:[k]
185+
| kbd:[C-c l c k]
186+
| Kill a log consumer and stop streaming events to the client.
187+
188+
| `cider-log-update-consumer`
189+
| kbd:[cu] / kbd:[u]
190+
| kbd:[C-c l c u]
191+
| Update the filters of a log consumer to change which events are streamed to the client.
192+
|===
193+
194+
== Log Event
195+
196+
Log events can be searched, streamed to a client or viewed in CIDER's
197+
Inspector and Stacktrace Mode. When searching log events the user can
198+
specify a set of filters. Events that match the filters are shown in
199+
the `+*cider-log*+` buffer. Additionally a log consumer will be
200+
attached to the appender to receive log events matching the search
201+
criteria after the search command has been issued. The log appender
202+
will be removed automatically once a new search has been submitted or
203+
when the `+*cider-log*+` buffer gets killed.
204+
205+
=== Keybindings
206+
207+
The following keybindings can be used to interact with log events.
208+
209+
|===
210+
| Command | Keyboard shortcut | Description
211+
212+
| `cider-log-event`
213+
| kbd:[C-c l e]
214+
| Show the transient menu to manage log events.
215+
216+
| `cider-log-clear-event-buffer`
217+
| kbd:[C-c l e c]
218+
| Clear all events from the log event buffer.
219+
220+
| `cider-log-show-stacktrace`
221+
| kbd:[C-c l e e]
222+
| Show the stacktrace of the log event at point in the CIDER Stacktrace Mode.
223+
224+
| `cider-log-inspect-event`
225+
| kbd:[C-c l e i]
226+
| Show the log event in the CIDER Inspector.
227+
228+
| `cider-log-print-event`
229+
| kbd:[C-c l e p]
230+
| Pretty print the log event in the `+*cider-log-event*+` buffer.
231+
232+
| `cider-log-event-search`
233+
| kbd:[C-c l e s]
234+
| Search log events and show them in the `+*cider-log*+` buffer.
235+
|===
236+
237+
== Log Filters
238+
239+
Filters for log events can be attached to log appenders and
240+
consumers. They also take effect when searching events or streaming
241+
them to clients. If multiple filters are chosen they are combined
242+
using logical AND condition. The following filters are available:
243+
244+
|===
245+
| Filter | Keyboard shortcut | Description
246+
247+
| `end-time`
248+
| kbd:[-e]
249+
| Only include log events that were emitted before `end-time`.
250+
251+
| `exceptions`
252+
| kbd:[-E]
253+
| Only include log events caused by an exception in the list of `exceptions`.
254+
255+
| `level`
256+
| kbd:[-l]
257+
| Only include log events with a log level above `level`.
258+
259+
| `loggers`
260+
| kbd:[-L]
261+
| Only include log events that were emitted by a logger in the list of `loggers`.
262+
263+
| `pattern`
264+
| kbd:[-r]
265+
| Only include log events whose message matcches the regular expression `pattern`.
266+
267+
| `start-time`
268+
| kbd:[-s]
269+
| Only include log events that were emitted at, or after `start-time`.
270+
271+
| `threads`
272+
| kbd:[-t]
273+
| Only include log events that were emitted by a thread in the list of `threads`.
274+
|===

test/cider-log-test.el

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
;;; cider-log-tests.el -*- lexical-binding: t; -*-
2+
3+
;; Copyright © 2023 Bozhidar Batsov and CIDER contributors
4+
5+
;; Author: r0man <[email protected]>
6+
7+
;; This file is NOT part of GNU Emacs.
8+
9+
;; This program is free software: you can redistribute it and/or
10+
;; modify it under the terms of the GNU General Public License as
11+
;; published by the Free Software Foundation, either version 3 of the
12+
;; License, or (at your option) any later version.
13+
;;
14+
;; This program is distributed in the hope that it will be useful, but
15+
;; WITHOUT ANY WARRANTY; without even the implied warranty of
16+
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
;; General Public License for more details.
18+
;;
19+
;; You should have received a copy of the GNU General Public License
20+
;; along with this program. If not, see `http://www.gnu.org/licenses/'.
21+
22+
;;; Commentary:
23+
24+
;; This file is part of CIDER
25+
26+
;;; Code:
27+
28+
(require 'buttercup)
29+
(require 'cider-log)
30+
31+
(describe "cider-log"
32+
(let ((framework (nrepl-dict "id" "jul" "name" "Java Util Logging"))
33+
(appender (nrepl-dict "id" "cider-log")))
34+
35+
(it "raises user-error when cider is not connected."
36+
(spy-on 'cider-connected-p :and-return-value nil)
37+
(expect (cider-log framework appender) :to-throw 'user-error))
38+
39+
(it "doesn't add an appender when initialized."
40+
(let ((cider-log--initialized-once-p t))
41+
(spy-on 'cider-sync-request:log-frameworks :and-return-value (list framework))
42+
(spy-on 'transient-setup)
43+
(cider-log framework appender)
44+
(expect 'transient-setup :to-have-been-called-with 'cider-log)))
45+
46+
(it "does add an appender when not initialized."
47+
(let ((cider-log--initialized-once-p nil))
48+
(spy-on 'cider-sync-request:log-frameworks :and-return-value (list framework))
49+
(spy-on 'cider-sync-request:log-add-appender :and-return-value appender)
50+
(spy-on 'transient-setup)
51+
(cider-log framework appender)
52+
(expect 'transient-setup :to-have-been-called-with 'cider-log)))))

0 commit comments

Comments
 (0)