Как добавить временную метку к каждой записи в буфере Emacs * Messages *?

11

Я очень зависим от *Messages*буфера, но записи не помечены.

Как добавить временную метку к каждой записи в буфере сообщений Emacs ?

Так что как то так:

Loading /Users/gsl/lisp.d/init.el (source)...
No outline structure detected
For information about GNU Emacs and the GNU system, type C-h C-a.
Loading /Users/gsl/lisp.d/var/recentf...done
Error running timer: (wrong-number-of-arguments (lambda nil (setq gc-cons-threshold (* 64 1024 1024)) (message "WARNING: gc-cons-threshold restored to %S")) 1)
[yas] Prepared just-in-time loading of snippets successfully.
M-] is undefined
CHILDREN [2 times]
‘show-all’ is an obsolete command (as of 25.1); use ‘outline-show-all’ instead.
Invalid face reference: nil [33 times]
Auto-saving...done
Saving file /Users/gsl/lisp.d/init.el...
Wrote /Users/gsl/lisp.d/init.el
mwheel-scroll: Beginning of buffer [5 times]
Mark set
previous-line: Beginning of buffer [10 times]
Quit [4 times]

станет примерно так:

2017-02-14-18:50:01 Loading /Users/gsl/lisp.d/init.el (source)...
2017-02-14-18:50:02 No outline structure detected
2017-02-14-18:50:03 For information about GNU Emacs and the GNU system, type C-h C-a.
2017-02-14-18:50:05 Loading /Users/gsl/lisp.d/var/recentf...done
2017-02-14-18:50:10 Error running timer: (wrong-number-of-arguments (lambda nil (setq gc-cons-threshold (* 64 1024 1024)) (message "WARNING: gc-cons-threshold restored     to %S")) 1)
2017-02-14-18:50:12 [yas] Prepared just-in-time loading of snippets successfully.
2017-02-14-18:50:40 M-] is undefined
2017-02-14-18:50:41 CHILDREN [2 times]
2017-02-14-18:50:00 ‘show-all’ is an obsolete command (as of 25.1); use ‘outline-show-all’ instead.
2017-02-14-18:50:01 Invalid face reference: nil [33 times]
2017-02-14-18:51:01 Auto-saving...done
2017-02-14-18:51:03 Saving file /Users/gsl/lisp.d/init.el...
2017-02-14-18:51:06 Wrote /Users/gsl/lisp.d/init.el
2017-02-14-18:51:09 mwheel-scroll: Beginning of buffer [5 times]
2017-02-14-18:51:11 Mark set
2017-02-14-18:51:21 previous-line: Beginning of buffer [10 times]

Я искал в EmacsWiki, Reddit и emacs.sx, конечно, безрезультатно.

Мне известно command-log-mode, что это можно настроить для входа в систему с отметками времени, но это полезно только для интерактивных команд, а не для всех сообщений, включая «системные» в Emacs.

Вместо этого каждое сообщение, занесенное в буфер сообщений, должно иметь метку времени.

Как добавить временную метку к каждой записи в буфере сообщений Emacs , независимо от ее источника?

GSL
источник
2
Это звучит как запрос функции для Emacs. Команда messageреализована на C и, вероятно, имеет прямых вызывающих, так что вы не сможете гарантировать, что каждое зарегистрированное сообщение получит временную метку без сборки Emacs самостоятельно. Тем не менее, вы можете посоветовать messageкоманде ввести метку времени, когда она вызывается из Elisp. Требуется некоторая осторожность: messageможет вызываться без аргументов, пустой строки формата и т. Д. Вы также хотите избежать рекурсивного цикла, если ваш совет по метке времени вызовет messageкакой-либо путь к коду.
glucas
1
Я не пробовал, но, похоже, вы сможете посоветовать сообщение emacswiki.org/emacs/AdvisingFunctions stackoverflow.com/questions/21524488/… superuser.com/questions/669701/…
eflanigan00
1
Я был бы склонен использовать after-change-functions(в буфере сообщений), чтобы реализовать это. Когда что-то вставляется в конец буфера, ставьте перед ним метку времени.
Фил
1
@phils Ссылка с gnu.org/software/emacs/manual/html_node/elisp/Change-Hooks.html Вывод сообщений в буфер сообщений не вызывает эти функции, а также не выполняет определенные изменения внутреннего буфера, такие как изменения в созданных буферах. внутренним Emacs для определенных заданий, которые не должны быть видны программам на Лиспе.
xinfa tang

Ответы:

7

У меня есть следующий фрагмент в моем init.el, который был адаптирован из оригинала, который я нашел в следующей ветке Reddit: http://www.reddit.com/r/emacs/comments/16tzu9/anyone_know_of_a_reasonable_way_to_timestamp/

(РЕДАКТИРОВАТЬ: модернизировано для добавления-добавления и удаления неуклюжей обработки буфера только для чтения по рекомендации @blujay)

(defun sh/current-time-microseconds ()
  "Return the current time formatted to include microseconds."
  (let* ((nowtime (current-time))
         (now-ms (nth 2 nowtime)))
    (concat (format-time-string "[%Y-%m-%dT%T" nowtime) (format ".%d]" now-ms))))

(defun sh/ad-timestamp-message (FORMAT-STRING &rest args)
  "Advice to run before `message' that prepends a timestamp to each message.

Activate this advice with:
(advice-add 'message :before 'sh/ad-timestamp-message)"
  (unless (string-equal FORMAT-STRING "%s%s")
    (let ((deactivate-mark nil)
          (inhibit-read-only t))
      (with-current-buffer "*Messages*"
        (goto-char (point-max))
        (if (not (bolp))
          (newline))
        (insert (sh/current-time-microseconds) " ")))))

(advice-add 'message :before 'sh/ad-timestamp-message)

Это приводит к оформлению буфера * Messages * следующим образом:

[2017-06-13T07:21:13.270070] Turning on magit-auto-revert-mode...
[2017-06-13T07:21:13.467317] Turning on magit-auto-revert-mode...done
[2017-06-13T07:21:13.557918] For information about GNU Emacs and the GNU system, type C-h C-a.
Стюарт Хикинботтом
источник
3
Интересно, почему это не предусмотрено в качестве опции по умолчанию.
Бертфред
1
Гениально, это именно то, что я искал. Спасибо.
gsl
2
@bertfred Потому что никто этого не сделал. Может быть, это ты?
Фил Лорд
2
Не могли бы вы переписать совет, используя advice-add? Сейчас это предпочтительный метод, поскольку он знает, как обрабатывать ситуации, которые defadviceне могут. Кроме того, вы, вероятно, не должны делать (read-only-mode 0), потому что это, вероятно, навсегда. Вы можете привязать inhibit-read-onlyк tвсему коду , который модифицирует буфер.
Блюджей,
2
Я использую ваш код, но отображаю много сообщений только с отметкой времени
xinfa tang
5

Вот простое решение @ xinfatang для нового advice-addсинтаксиса в качестве обёртки вокруг messageфункции:

(defun my-message-with-timestamp (old-func fmt-string &rest args)
   "Prepend current timestamp (with microsecond precision) to a message"
   (apply old-func
          (concat (format-time-string "[%F %T.%3N %Z] ")
                   fmt-string)
          args))

Выходы *Messages*как:

[2018-02-25 10:13:45.442 PST] Mark set

Добавить:

 (advice-add 'message :around #'my-message-with-timestamp)

Удалять:

 (advice-remove 'message #'my-message-with-timestamp)
Mithos
источник
3
Вы также можете просто отфильтровать аргументы, вместо того, чтобы использовать советы: (advice-add 'message :filter-args 'with-timestamp)будет работать с такой функцией:(defun with-timestamp (args) (push (concat (format-time-string "[%F %T.%3N] ") (car args)) (cdr args)))
glucas
1
@glucas Отлично! Я получаю метки времени без сообщения, когда наведу курсор мыши на минибуфер. Есть ли способ избежать этого?
AstroFloyd
3

См. Https://www.emacswiki.org/emacs/DebugMessages :

(defadvice message (before when-was-that activate)
  "Add timestamps to `message' output."
  (ad-set-arg 0 (concat (format-time-string "[%Y-%m-%d %T %Z] ") 
                        (ad-get-arg 0)) ))

Наконец, мне все еще нравится ответ Стюарта Хикинботтома , потому что он избегает показа метки времени в минибуфере, ниже приводится модифицированная версия, которую я использую, он игнорирует сообщения, отображаемые только в области эха (от let message-log-maxдо nilдо вызова функции сообщения):

 (defun my/ad-timestamp-message (FORMAT-STRING &rest args)
   "Advice to run before `message' that prepends a timestamp to each message.
    Activate this advice with:
      (advice-add 'message :before 'my/ad-timestamp-message)
    Deactivate this advice with:
      (advice-remove 'message 'my/ad-timestamp-message)"
       (if message-log-max
           (let ((deactivate-mark nil)
                 (inhibit-read-only t))
             (with-current-buffer "*Messages*"
               (goto-char (point-max))
               (if (not (bolp))
                   (newline))
               (insert (format-time-string "[%F %T.%3N] "))))))
 (advice-add 'message :before 'my/ad-timestamp-message)
Xinfa Tang
источник
2
Измените формат отметки времени %F %T.%3Nна показ микросекунд
xinfa tang