Working with log files in Emacs
source link: https://writequit.org/articles/working-with-logs-in-emacs.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Reading logs
The number one thing that I expect someone would want to do with logs is to make them readable. "Readable" means a few different things to different people, so this may not hit 100% of the mark, but there are definitely some things you can do to make logs more readable.
Logs that are undergoing writes
I commonly use tail -F
for monitoring logs on Linux systems, and Emacs has something like that
also. To watch a file for changes and update the buffer automatically, open the file and then invoke
M-x auto-revert-tail-mode
. Emacs will then behave just like tail -f
for the currently open file.
Dealing with very large log files
50mb? Okay, no problem.
342mb? Sure, Emacs can handle that.
2.7gb? Well, maybe that is getting a bit large for a single buffer, especially when we want to add searching and all that to the mix. It's not that Emacs can't handle it, it's just that some operations you want to do may be a bit slower than you'd like.
Enter vlf, vlf is short for "View Large Files" and is a very nice way to handle viewing extremely large files in Emacs, not just log files. I've used it successfully for reading log files over 10 gigabytes. I'll leave it to you to read the page about the features it provides, but suffice it to say that it breaks up large files into manageable chunks, and then provides tools to operate on either a small chunk, or across all the chunks of a very large file.
Install vlf, and try to open a 1.2gb log file and you'll get a prompt that says
File my_big_log.log is large (1.2G): open normally (o), open with vlf (v) or abort (a)
You can then hit either o
, v
, or a
depending on what you'd like to do. You can even configure
the limit at which it asks you by configuring the large-file-warning-threshold
setting.
Once you open a file with VLF, you can scroll batches by either going to the bottom/top of the chunk and
then going to the next/previous line, or you can use C-c C-v
and then n
or p
to go to the next
or previous chunk. VLF's bindings all start with the C-c C-v
prefix, so some of the helpful ones
are:
C-c C-v s
andC-c C-v r
for searching forward and backward through the fileC-c C-v o
builds an "occur" index over the entire file. We'll talk more about occur in the "searching" sectionC-c C-v l
jump to a particular line in the big file
You can even edit the file, saving only the batch/chunk you're currently in.
There are even more features, so check out the VLF page for the full documentation if you routinely work with large files.
Using a major mode
Since Elasticsearch is a Java application, it uses logs that are in one of those formats that is common to most other Java applications, the log4j format.
There are a few different options, depending on what sort of logs you are viewing and what format they're in, they're log4j-mode1 which is stripped down and doesn't handle much other than syntax highlighting for different log levels, as well as rudimentary support for filtering included and excluded content from the log file in question. At the time of this writing the site is down, but you can still download the library from MELPA.
Figure 1: An example of what log4j-mode looks like
Along the same lines (focused on a particular format), there is rails-log-mode which is designed for Rails logs, however, I cannot comment on it as I don't use Rails.
Finally, on the more generic side there is a mode called Logview that provides a more feature-rich
experience for viewing logs. At the time of this writing though, it doesn't support the timestamp
format that ES uses (ISO-8601 It also handles ES' timestamp format.
Logview has a lot of features, however I tend to stick with my regular editing habits. I hope to
change this in the future though, so give it a shot if it looks interesting to you.
yyyy-MM-dd'T'HH:mm:ss,SSS
)
I personally stick with log4j-mode, even though it doesn't have many features other than syntax
highlighting. There are a few things you can configure other than faces, and you can jump between
log messages with M-}
and M-{
, but generally we don't look at major modes for log mining
features.
Sometimes when viewing a file, you don't have enough vertical space. To alleviate this, Emacs has a
feature called follow-mode. If you split the buffer vertically with C-x 3
and then invoke M-x
follow-mode
Emacs will treat the pane on the left as the "top" of the buffer and the pane on the
right as the "bottom", making the viewing part essentially twice as high. If you scroll in one pane
the other pane will follow. It's great for viewing very large files as well as large programming
methods!
Helpful minor modes
Okay, there aren't a great number of helpful major modes, but we do have a lot of minor modes to help out with reading the logs, some that are built in, and some that aren't.
I find that line numbers aren't very helpful for reading logs, but I do find that hl-line-mode
is
invaluable for highlighting the current line you are viewing in the logs. There's also
global-hl-line-mode
if you want it everywhere. hl-line
is built in to Emacs, so there's nothing
you'll need to download/install to use it.
It's uncommon in my experience to want to edit the log while viewing it (though you may want to
delete lines from the log), so in that case, I heartily recommend view-mode
. Another built-in
mode, View mode is designed for scanning buffers by the screenful (just what we want to do with
logs!). It helpfully allows using a different keymap, so that you can switch to more "navigation"
style keybindings. It's easy to invoke, simply use M-x view-mode
while on a file; I have the
following for my log4j-mode hooks
(use-package log4j-mode :ensure t :disabled t :init (add-hook #'log4j-mode-hook #'view-mode) (add-hook #'log4j-mode-hook #'read-only-mode) (add-hook #'log4j-mode-hook 'eos/turn-on-hl-line))
And in my customized view-mode bindings
(use-package view :config (defun View-goto-line-last (&optional line) "goto last line" (interactive "P") (goto-line (line-number-at-pos (point-max)))) (define-key view-mode-map (kbd "e") 'View-scroll-half-page-forward) (define-key view-mode-map (kbd "u") 'View-scroll-half-page-backward) ;; less like (define-key view-mode-map (kbd "N") 'View-search-last-regexp-backward) (define-key view-mode-map (kbd "?") 'View-search-regexp-backward?) (define-key view-mode-map (kbd "g") 'View-goto-line) (define-key view-mode-map (kbd "G") 'View-goto-line-last) ;; vi/w3m like (define-key view-mode-map (kbd "h") 'backward-char) (define-key view-mode-map (kbd "j") 'next-line) (define-key view-mode-map (kbd "k") 'previous-line) (define-key view-mode-map (kbd "l") 'forward-char))
I primarily view logs by scrolling half-pages, so I can keep context more easily. If "e" and "u" seem like strange choices to you, it's because I type with a Dvorak keyboard layout and those keys are where "d" and "f" would be on a regular Qwerty keyboard.
As an alternative to view-mode
, I have my own Hydra state that I use for navigation when I don't
feel like holding down modifiers (I am not an EVIL user, so this may not apply if you are)
(defhydra eos/nav-mode (:foreign-keys run) "[NAV-MODE] q or i to exit" ("C-h" hl-line-mode) ("t" toggle-truncate-lines) ("a" beginning-of-line) ("l" forward-char) ("h" backward-char) ("n" next-line) ("j" next-line) ("p" previous-line) ("k" previous-line) ("e" View-scroll-half-page-forward) ("u" View-scroll-half-page-backward) ("SPC" scroll-up-command) ("S-SPC" scroll-down-command) ("<" beginning-of-buffer) (">" end-of-buffer) ("." end-of-buffer) ("C-'" nil) ("d" (when (y-or-n-p "Kill buffer?") (kill-this-buffer)) :exit t) ("/" isearch-forward-regexp :exit t) ("?" isearch-backward-regexp :exit t) ("i" nil :exit t) ("q" nil :exit t))
I bind this to M-V
2, so I can easily invoke it
in any buffer to enter a navigation-like mode, with some keybindings to make it easier to scan
through pages and pages of logs.
Hiding parts of the log file
Sometimes you want to limit the scope of what you're reading, say, between a couple of timestamps. There are a number of ways to do this, but one way that is quite common in Emacs is narrowing. When narrowing, only the text you want will be displayed in the buffer.
I recommend Endless Parentheses' narrow-or-widen-dwim
for this, because it will allow you to use a
single binding for narrowing and widening (undoing the narrow), as well as some nice criteria that
works outside of log viewing as well. For simplicity's and future-proofing sake I'll reproduce the
one I use here, but visit the original page to see the full explanation.
(defun eos/narrow-or-widen-dwim (p) "Widen if buffer is narrowed, narrow-dwim otherwise. Dwim means: region, org-src-block, org-subtree, or defun, whichever applies first. Narrowing to org-src-block actually calls `org-edit-src-code'. With prefix P, don't widen, just narrow even if buffer is already narrowed." (interactive "P") (declare (interactive-only)) (cond ((and (buffer-narrowed-p) (not p)) (widen)) ((region-active-p) (narrow-to-region (region-beginning) (region-end))) ((derived-mode-p 'org-mode) ;; `org-edit-src-code' is not a real narrowing ;; command. Remove this first conditional if ;; you don't want it. (cond ((ignore-errors (org-edit-src-code) t) (delete-other-windows)) ((ignore-errors (org-narrow-to-block) t)) (t (org-narrow-to-subtree)))) ((derived-mode-p 'latex-mode) (LaTeX-narrow-to-environment)) (t (narrow-to-defun))))
I bind mine to C-x C-n
so it's easy to hit
(global-set-key (kbd "C-x C-n") #'eos/narrow-or-widen-dwim)
Since this works on a highlighted region, you can select the text you want to limit your actions on,
and then hit C-x C-n
to shrink the buffer down to just that text. Do whatever analysis you need
to, and then hit C-x C-n
again to widen back to the big file.
Figure 2: A log buffer with text selected prior to narrowing
Figure 3: The same buffer after narrowing to the selected region
Want to have two copies of the buffer, on that is narrowed and one that's un-narrowed? Create an
indirect buffer! Hit C-x 4 c
to "clone" the buffer, you can then narrow each copy independently,
while keeping them synchronized for other actions (like filtering or modifying).
Hiding structured data
In addition to regular log files, I deal a lot with structured log-like data, almost entirely in JSON format. In addition to the regulars like json-mode and json-reformat for just viewing the data, sometimes it's helpful to be able to hide certain parts of the structured data. This is something that Emacs' built-in Hideshow3 is great at.
Before describing it, here's a minimal configuration for it:
(use-package hideshow :bind (("C-c TAB" . hs-toggle-hiding) ("C-\\" . hs-toggle-hiding) ("M-+" . hs-show-all)) :init (add-hook #'prog-mode-hook #'hs-minor-mode) :diminish hs-minor-mode :config (setq hs-special-modes-alist (mapcar 'purecopy '((c-mode "{" "}" "/[*/]" nil nil) (c++-mode "{" "}" "/[*/]" nil nil) (java-mode "{" "}" "/[*/]" nil nil) (js-mode "{" "}" "/[*/]" nil) (json-mode "{" "}" "/[*/]" nil) (javascript-mode "{" "}" "/[*/]" nil)))))
The main way I use this is to put the point (represented as |
in the code below) inside of an
expression and then hit C-c TAB
or C-\
, which changes
{ "foo": {| "bar": "baz" }, "eggplant": 11 }
{ "foo": { ... }, "eggplant": 11 }
Hitting C-c TAB
or C-\
on the block again shows the block. This is especially nice when you have
gigantic JSON files that you want to see different parts of at the same time, as seen below.
Figure 4: An example of Hideshow collapsing part of a JSON buffer
There are a whole bunch of ways to make this nice, I especially recommend reading the manual for
Hideshow and also checking out hs-hide-level
where you can hide everything at a certain nested
level.
Finally, if you want to go all-in for a hierarchical view of JSON data, I'd recommend json-navigator.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK