Docker explorer

Volume 4, Issue 19; 05 Mar 2020

A small hack combining Emacs, docker, and MarkLogic log files.

In my day job, I work on MarkLogic server (and other things). For years, I’ve been doing this by running the server in a Docker container (or often a small cluster of such containers). This isolates my development environment from changes in my laptop (not just OS upgrades, but changing the whole OS).

A typical session goes like this: start a container, start the server, start working on some code, open a shell window, exec into the container, tail -f a log file, go on about my work. This is fine until some bit of code squirts a whole lot of lines into the log file, then I’m scrolling around looking for bits. If I need to search the log, maybe I hack about with cat and grep or maybe I just bring in the big guns and open the log file in Emacs.

Hold that thought.

A few days ago, I saw the release announcement for a new version of transient. Transient is part of the magic that is Magit. I’m not a hard core magit user, I’ve probably barely scratched the surface, but I love the things it does for me.

A quick skim of the transient project left me none the wiser this time than it had last time. But sometime shortly after, probably in r/emacs, I found a link to Adrien Brochard’s talk about integrating transient into a workflow for managing Kubernetes log files. I’m not usually a fan of video tutorials, but I was curious enough about transient to check it out and it is excellent. Adrien does a fantastic job of leading his audience through both how he approached the problem and how he tackled it. I recommend it highly and if you have to choose between reading the rest of this page and watching that video, watch the video. Go! Shoo! I’ve got nothing significant to add.

I’m sort of serious about that last part.

The log file monitoring example that Adrien describes is the same in all but detail to the situation I described above. And reworking it to solve my problem was both an obvious way to learn a little more about transient and an obvious way to improve my workflow.

The project is docker explorer. Yes, it’s about reading MarkLogic log files, but the real beauty here is how transient connects the idea of building a UX with Emacs.

Type M-x docker-explorer and you’ll get a menu of your docker containers.

Container list

Select a running container and press l to open the logs window. (There’s nothing in this first selection that’s related to transient, but I’m already thinking about adding other commands that would use it.)

Logs list

Finally, pressing t brings up the tail menu:

Log tail

What transient is providing here is a nice, declarative interface to this functionality. The relevant bit of code is this:

(define-transient-command dxp--transient-tail-ml ()
  "Docker Explorer Tail command"
   ("-f" "Follow" "-f")
   ("t" "Tail" dxp--tail-ml-function)])

The “​-f​” flag (which creates a process that continues to tail the log file as it changes) is just a flag. The “​-n​” flag takes an argument and it’s declared with dxp-transient:--lines:

(define-infix-argument dxp-transient:--lines ()
  "Transient support for the lines argument."
  :description "Number of lines"
  :class 'transient-option
  :shortarg "-n"
  :argument "-n ")

There’s lots here I’m still digesting, and lots I frankly don’t understand, but it’s enough to see first hand how cleanly the declarative interface works. I’ll be coming back to explore this in more detail when I have the time.

And bonus: now, instead of fiddling with a shell window and trying to find things with grep, the whole searchable, evolving log file is in an Emacs buffer three or four keystrokes away. Win!

Not bad for an evening’s hacking on the sofa and ~150 lines of Emacs lisp.