Skip to content

Commit 7da155c

Browse files
committed
feat(core): switch logging to use lgr
1 parent 50e0b96 commit 7da155c

File tree

3 files changed

+172
-120
lines changed

3 files changed

+172
-120
lines changed

elsa-log.el

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,38 @@
11
;; -*- lexical-binding: t -*-
22

3-
(defconst elsa-log-level-critical 1)
4-
(defconst elsa-log-level-info 2)
5-
(defconst elsa-log-level-debug 3)
6-
(defconst elsa-log-level-trace 4)
3+
(require 'lgr)
4+
(require 'async)
75

8-
(defvar elsa-log-level 2)
6+
(defclass elsa-worker-appender (lgr-appender) ()
7+
"Appender sending messages back to parent process.")
98

10-
;; (elsa-log :: (function (string &rest mixed) string))
9+
(cl-defmethod lgr-append ((this elsa-worker-appender) event)
10+
"Send messages to parent process with `async-send'."
11+
(when async-in-child-emacs
12+
(async-send
13+
:op "echo"
14+
:message (lgr-format-event (oref this layout) event)))
15+
this)
16+
17+
(defclass elsa-plain-layout (lgr-layout) ()
18+
"Simple layout only printing the message.")
19+
20+
(cl-defgeneric lgr-format-event ((_this elsa-plain-layout) (event lgr-event))
21+
"Format EVENT as only the message."
22+
(oref event msg))
23+
24+
(defconst elsa-logger (-> (lgr-get-logger "elsa")
25+
(lgr-reset-appenders)
26+
(lgr-add-appender
27+
(-> (lgr-appender-princ)
28+
(lgr-set-layout (elsa-plain-layout))))
29+
(lgr-set-threshold lgr-level-info))
30+
"Configuration for main elsa logger.")
31+
32+
;; (elsa-log :: (function (string &rest mixed) string))
1133
(defun elsa-log (fmt &rest args)
12-
(let ((msg (apply #'format fmt args)))
13-
(when elsa-is-language-server
14-
(elsa-lsp-send-response
15-
(lsp--make-notification
16-
"window/showMessage"
17-
(lsp-make-message-params :type 3 :message msg))))
18-
(princ (concat msg "\n"))))
19-
20-
(defun elsa-debug (fmt &rest args)
21-
(when (<= elsa-log-level-debug elsa-log-level)
22-
(apply #'elsa-log fmt args)))
34+
"Log messages at info level via `elsa-logger'."
35+
(apply #'lgr-log elsa-logger 400 fmt args))
2336

2437
(defun elsa-get-elapsed (start)
2538
"Get time elapsed since START in floating point seconds."
@@ -30,10 +43,10 @@
3043
(let ((nowvar (make-symbol "now"))
3144
(elapsedvar (make-symbol "elapsed")))
3245
`(let ((,nowvar (current-time)))
33-
(elsa-log "%s..." ,msg)
46+
(lgr-info elsa-logger "%s..." ,msg)
3447
(prog1 (progn ,@body)
3548
(let ((,elapsedvar
3649
(float-time (time-subtract (current-time) ,nowvar))))
37-
(elsa-log "%s...done (%.3fs)" ,msg ,elapsedvar))))))
50+
(lgr-info elsa-logger "%s...done (%.3fs)" ,msg ,elapsedvar))))))
3851

3952
(provide 'elsa-log)

elsa-lsp-core.el

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,43 @@
55

66
(require 'elsa)
77

8+
(defun append-to-log-file (message)
9+
"Appends a message to a log file."
10+
(let ((log-file "elsa-lsp.log"))
11+
(with-temp-buffer
12+
(insert (replace-regexp-in-string "\\(\r\\|\n\\)" "" message) "\n")
13+
(write-region (point-min) (point-max) log-file t))))
14+
15+
(defun elsa-lsp-send-response (message)
16+
(when (or (hash-table-p message)
17+
(and (listp message) (plist-get message :jsonrpc)))
18+
(setq message (lsp--json-serialize message)))
19+
20+
;; (append-to-log-file (concat "<< " message))
21+
(princ (format "Content-Length: %d\r\n\r\n" (string-bytes message)))
22+
(princ message)
23+
(terpri))
24+
25+
(defclass elsa-lsp-appender (lgr-appender) ()
26+
"Appender sending messages to lsp client as window/showMessage.")
27+
28+
(cl-defmethod lgr-append ((this elsa-lsp-appender) event)
29+
"Send window/showMessage LSP notification."
30+
(when elsa-is-language-server
31+
(elsa-lsp-send-response
32+
(lsp--make-notification
33+
"window/showMessage"
34+
(lsp-make-message-params
35+
:type lsp/message-type-info
36+
:message (lgr-format-event (oref this layout) event)))))
37+
this)
38+
39+
(defconst elsa-lsp-logger (-> (lgr-get-logger "elsa")
40+
(lgr-add-appender
41+
(-> (elsa-lsp-appender)
42+
(lgr-set-layout (elsa-plain-layout))
43+
(lgr-set-threshold lgr-level-info)))))
44+
845
(defclass elsa-lsp-file ()
946
((name :type string :initarg :name)
1047
(buffer :type buffer :initarg :buffer)))
@@ -80,23 +117,6 @@ be re-analysed during textDocument/didOpen handler.")))
80117
:priority 1
81118
:server-id 'elsa)))
82119

83-
(defun append-to-log-file (message)
84-
"Appends a message to a log file."
85-
(let ((log-file "elsa-lsp.log"))
86-
(with-temp-buffer
87-
(insert (replace-regexp-in-string "\\(\r\\|\n\\)" "" message) "\n")
88-
(write-region (point-min) (point-max) log-file t))))
89-
90-
(defun elsa-lsp-send-response (message)
91-
(when (or (hash-table-p message)
92-
(and (listp message) (plist-get message :jsonrpc)))
93-
(setq message (lsp--json-serialize message)))
94-
95-
;; (append-to-log-file (concat "<< " message))
96-
(princ (format "Content-Length: %d\r\n\r\n" (string-bytes message)))
97-
(princ message)
98-
(terpri))
99-
100120
(defun elsa-lsp--uri-to-file (uri)
101121
(substring uri 7))
102122

elsa.el

Lines changed: 103 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
;; Maintainer: Matúš Goljer <[email protected]>
77
;; Created: 23rd March 2017
88
;; Version: 0.1.0
9-
;; Package-Requires: ((emacs "26.1") (trinary "0") (f "0") (dash "2.14") (cl-lib "0.3") (lsp-mode "0") (ansi "0") ("async" "1.9.7"))
9+
;; Package-Requires: ((emacs "26.1") (trinary "0") (f "0") (dash "2.14") (cl-lib "0.3") (lsp-mode "0") (ansi "0") (async "1.9.7"))
1010
;; URL: https://github.com/emacs-elsa/Elsa
1111
;; Keywords: languages, lisp
1212

@@ -283,80 +283,100 @@ GLOBAL-STATE is the initial configuration."
283283
"Return function running in the Elsa analysis worker."
284284
(let ((load--path load-path))
285285
(lambda ()
286-
(setq load-path load--path)
287-
(setq elsa-is-language-server nil)
288-
(setq ansi-inhibit-ansi t)
289-
(require 'elsa)
290-
(require 'async)
291-
(let ((msg nil))
292-
(setq elsa-global-state (elsa-global-state))
293-
(oset elsa-global-state project-directory project-directory)
294-
(oset elsa-global-state number-of-files 1)
295-
(oset elsa-global-state processed-file-index 1)
296-
(catch 'done
297-
(while t
298-
(setq msg (async-receive))
299-
(let ((op (plist-get msg :op)))
300-
(cond
301-
((equal op "analyze")
302-
(let* ((dep (plist-get msg :dep))
303-
(library (plist-get msg :file))
304-
(current-time (current-time))
305-
(elsa-cache-file (elsa--get-cache-file-name elsa-global-state dep)))
306-
(elsa--autoload-types elsa-global-state dep)
307-
(elsa--autoload-extension elsa-global-state dep)
308-
(condition-case err
309-
(let ((state (elsa-process-file library elsa-global-state)))
310-
;; `subr' has no provide for some circular
311-
;; dependency "bootstrap" issues. We add it here
312-
;; artificially.
313-
(when (equal dep "subr")
314-
(oset state provide (list 'subr)))
315-
(elsa-save-cache state elsa-global-state))
316-
(error (async-send :ack "error" :error err)))
317-
(async-send :ack "ok" :op op
318-
:worker-id worker-id :dep dep
319-
:file library
320-
:duration (float-time
321-
(time-subtract
322-
(current-time) current-time)))))
323-
((equal op "load-from-cache")
324-
(let ((files (plist-get msg :files)))
325-
(dolist (file files) (load (f-no-ext file) t t))
326-
(async-send :ack "ok" :op op :worker-id worker-id)))
327-
((equal op "quit")
328-
(throw 'done t))))))))))
286+
(condition-case err
287+
(progn
288+
(setq load-path load--path)
289+
(setq elsa-is-language-server nil)
290+
(setq ansi-inhibit-ansi t)
291+
(require 'elsa)
292+
(require 'async)
293+
(require 'lgr)
294+
(-> (lgr-get-logger "elsa")
295+
(lgr-reset-appenders)
296+
(lgr-add-appender
297+
(-> (elsa-worker-appender)
298+
(lgr-set-layout (elsa-plain-layout))))
299+
(lgr-set-threshold lgr-level-info))
300+
(let ((msg nil)
301+
(lgr (lgr-get-logger "elsa.analyse.worker")))
302+
(setq elsa-global-state (elsa-global-state))
303+
(oset elsa-global-state project-directory project-directory)
304+
(oset elsa-global-state number-of-files 1)
305+
(oset elsa-global-state processed-file-index 1)
306+
(catch 'done
307+
(while t
308+
(setq msg (async-receive))
309+
(let ((op (plist-get msg :op)))
310+
(cond
311+
((equal op "analyze")
312+
(let* ((dep (plist-get msg :dep))
313+
(library (plist-get msg :file))
314+
(current-time (current-time))
315+
(elsa-cache-file (elsa--get-cache-file-name elsa-global-state dep)))
316+
(elsa--autoload-types elsa-global-state dep)
317+
(elsa--autoload-extension elsa-global-state dep)
318+
(lgr-debug lgr "Starting analysis of %s" dep)
319+
(let ((state (elsa-process-file library elsa-global-state)))
320+
;; `subr' has no provide for some circular
321+
;; dependency "bootstrap" issues. We add it here
322+
;; artificially.
323+
(lgr-debug lgr "Analysis of %s done" dep)
324+
(when (equal dep "subr")
325+
(oset state provide (list 'subr)))
326+
(elsa-save-cache state elsa-global-state)
327+
(lgr-debug lgr "Finished saving cache for %s" dep))
328+
(async-send :ack "ok" :op op
329+
:dep dep
330+
:file library
331+
:duration (float-time
332+
(time-subtract
333+
(current-time) current-time)))))
334+
((equal op "load-from-cache")
335+
(let ((files (plist-get msg :files)))
336+
(dolist (file files) (load (f-no-ext file) t t))
337+
(async-send :ack "ok" :op op)))
338+
((equal op "quit")
339+
(throw 'done t))))))))
340+
(error (async-send :ack "error" :error err :trace (progn (require 'backtrace) (backtrace-to-string))))))))
329341

330342
(defun elsa--parent-function-factory (worker-id workers-state max-file-name-length global-state)
331343
"Function handling child-to-parent messages and worker exit."
332-
(lambda (result)
333-
(if (async-message-p result)
334-
(let* ((worker-id (plist-get result :worker-id))
335-
(worker-state (assoc worker-id workers-state))
336-
(op (plist-get result :op)))
337-
(cond
338-
((equal op "analyze")
339-
(let* ((dep (plist-get result :dep))
340-
(file (plist-get result :file))
341-
(duration (plist-get result :duration))
342-
(elsa-cache-file (elsa--get-cache-file-name global-state dep)))
344+
(let ((lgr (lgr-get-logger "elsa.analyse.parent")))
345+
(lambda (result)
346+
(if (async-message-p result)
347+
(let* ((worker-state (assoc worker-id workers-state))
348+
(op (plist-get result :op))
349+
(ack (plist-get result :ack)))
350+
(cond
351+
((equal ack "error")
352+
(error "Error in child process %d %s" worker-id (plist-get result :error)))
353+
((equal op "echo")
343354
(elsa-log
344-
(elsa--processing-line global-state "done" file worker-id duration))
345-
(load (f-no-ext elsa-cache-file) t t))
346-
(cl-incf (oref global-state processed-file-index))
347-
(setf (cdr worker-state) (plist-put (cdr worker-state) :ready t)))
348-
((equal op "load-from-cache")
349-
(elsa-debug "Worker %s loaded all cache files for this layer" worker-id)
350-
(setf (cdr worker-state) (plist-put (cdr worker-state) :ready t)))))
351-
(elsa-debug "Async process done in worker %d, result: %s" worker-id result)
352-
t)))
355+
(with-ansi
356+
(red "Worker %d said: " worker-id)
357+
(yellow (plist-get result :message)))))
358+
((equal op "analyze")
359+
(let* ((dep (plist-get result :dep))
360+
(file (plist-get result :file))
361+
(duration (plist-get result :duration))
362+
(elsa-cache-file (elsa--get-cache-file-name global-state dep)))
363+
(elsa-log
364+
(elsa--processing-line global-state "done" file worker-id duration))
365+
(load (f-no-ext elsa-cache-file) t t))
366+
(cl-incf (oref global-state processed-file-index))
367+
(setf (cdr worker-state) (plist-put (cdr worker-state) :ready t)))
368+
((equal op "load-from-cache")
369+
(lgr-debug lgr "Worker %s loaded all cache files for this layer" worker-id)
370+
(setf (cdr worker-state) (plist-put (cdr worker-state) :ready t)))))
371+
(lgr-debug lgr "Async process done in worker %d, result: %s" worker-id result)
372+
t))))
353373

354374
(defun elsa--wait-for-all (get-worker-states)
355375
(catch 'all-workers-ready
356376
(while t
357377
(when (--all? (plist-get (cdr it) :ready) (funcall get-worker-states))
358378
(throw 'all-workers-ready t))
359-
(sleep-for 0.1))))
379+
(sleep-for 0.01))))
360380

361381
(defun elsa-analyse-file-parallel (file global-state &optional already-loaded)
362382
"Analyse FILE with GLOBAL-STATE.
@@ -365,7 +385,8 @@ Optional argument ALREADY-LOADED is used to skip dependencies which
365385
are already loaded in the currently running Emacs process. This is
366386
used by the LSP server to not reload already processed files."
367387
(elsa-with-elapsed-time "Process dependencies"
368-
(let* ((dep-layers (elsa-with-elapsed-time "Resolving dependencies"
388+
(let* ((lgr (lgr-get-logger "elsa.analyse"))
389+
(dep-layers (elsa-with-elapsed-time "Resolving dependencies"
369390
(elsa-get-dependencies-as-layers file)))
370391
(dependencies (let ((deps (append
371392
(plist-get dep-layers :layers)
@@ -399,16 +420,16 @@ used by the LSP server to not reload already processed files."
399420
(oset global-state processed-file-index 1)
400421
(oset global-state number-of-files (length (-flatten dependencies)))
401422
(oset global-state max-file-name-length max-file-name-length)
402-
(elsa-debug "Processing dependency layers: %s" dependencies)
403-
(elsa-debug "Processing dependency alist: %s" dep-to-file)
423+
(lgr-debug lgr "Processing dependency layers: %s" dependencies)
424+
(lgr-debug lgr "Processing dependency alist: %s" dep-to-file)
404425
(dolist (layer (butlast dependencies))
405426
(cl-incf i)
406-
(elsa-debug "Processing layer %s" i)
427+
(lgr-debug lgr "Processing layer %s" i)
407428
(while layer
408429
(-each workers-state
409430
(-lambda ((state &as worker-id . (&plist :ready)))
410431
(when (and ready layer)
411-
(elsa-debug "Worker %s is ready, submitting dependency %s" worker-id (car layer))
432+
(lgr-debug lgr "Worker %s is ready, submitting dependency %s" worker-id (car layer))
412433
(let* ((worker (nth worker-id workers))
413434
(dep (pop layer))
414435
(file (or (cdr (assoc dep dep-to-file))
@@ -433,11 +454,11 @@ used by the LSP server to not reload already processed files."
433454
(elsa--autoload-extension global-state dep)
434455
(setf (cdr state) (plist-put (cdr state) :ready nil))
435456
(async-send worker :op "analyze" :dep dep :file file)))))))
436-
(sleep-for 0.1))
437-
(elsa-debug "All work for layer %s was distributed" i)
457+
(sleep-for 0.01))
458+
(lgr-debug lgr "All work for layer %s was distributed" i)
438459

439460
(elsa--wait-for-all (lambda () workers-state))
440-
(elsa-debug "All workers finished processing layer %s" i)
461+
(lgr-debug lgr "All workers finished processing layer %s" i)
441462

442463
(let ((cache-files (mapcar
443464
(lambda (dep)
@@ -450,11 +471,11 @@ used by the LSP server to not reload already processed files."
450471
(async-send worker :op "load-from-cache" :files cache-files)))))
451472

452473
(elsa--wait-for-all (lambda () workers-state))
453-
(elsa-debug "All workers updated global state for layer %s" i))
474+
(lgr-debug lgr "All workers updated global state for layer %s" i))
454475

455476
(--each workers
456477
(async-send it :op "quit"))
457-
(elsa-debug "All workers quit")
478+
(lgr-debug lgr "All workers quit")
458479

459480
(let ((start-time (current-time))
460481
(state (elsa-process-file (car (-last-item dependencies)) global-state 'no-log))
@@ -611,15 +632,13 @@ This function is soft-deprecated in favour of
611632
(bright-blue "%d notices" notices)
612633
" after "
613634
(blue "%.3f seconds" duration)))
614-
;; (elsa-log "%d elsa-simple-type objects were created" elsa-type-simple-make-count)
615-
;; (elsa-log "%d elsa-composite-type objects were created" elsa-type-composite-make-count)
616-
;; (elsa-log "clone on simple type was called %d times "elsa-type-simple-clone-count)
617-
;; (elsa-debug "memory report %s"
618-
;; (with-current-buffer (get-buffer-create "*Memory Report*")
619-
;; (require 'memory-report)
620-
;; (memory-report)
621-
;; (buffer-string)))
622-
)
635+
636+
(lgr-trace (lgr-get-logger "elsa.perf")
637+
"memory report %s"
638+
(with-current-buffer (get-buffer-create "*Memory Report*")
639+
(require 'memory-report)
640+
(memory-report)
641+
(buffer-string))))
623642
(when (and elsa-cli-with-exit (< 0 errors))
624643
(kill-emacs 1))))
625644

0 commit comments

Comments
 (0)