I recently released Airbrussh, a Ruby gem that alters the logging output of Capistrano. In this article I want to share my thought process that lead me to create Airbrussh, and how I borrowed some ideas from the UI and UX disciplines in order to improve a command-line tool.
A vital part of my Ruby on Rails toolset is Capistrano. Capistrano saves me an immense amount of time and helps me avoid mistakes by automating the entire process of deploying Rails applications onto cloud servers. I’ve even taken it a step further by extending Capistrano to set up the servers themselves.1
But one thing that bugged me about Capistrano was the console output that filled up my screen whenever I performed a deployment. Frankly, it was a bit of a mess. Capistrano’s settings let me dial down the logging verbosity or switch to a minimal “dotted” output, but then I lost a lot of valuable troubleshooting information. There was no good middle ground.
Luckily the authors of Capistrano anticipated that other developers might want to scratch this itch: they provided a hook in Capistrano’s supporting library, SSHKit, so that custom log formatters can be plugged in.2 This allowed me to create Airbrussh, a gem that completely overhauls Capistrano’s logging output.
To make Airbrussh, I tried to approach the problem with a UI designer’s mindset:
- Make it look good
- Strike the right balance of form and function
- Improve the user experience
Good UI is all about “look and feel”. For Capistrano, I looked for opportunities to remove clutter, simplify, and apply some basic visual design principles.
The first thing I tried to solve was simply reducing the volume of data. For example, I noticed that every command was prefixed with
/usr/bin/env, and this wasn’t critical to describing what was being executed. Airbrussh uses a regex to remove this portion of the command string when printing it.
Next, I saw that the full text of every command was being logged before execution, then at the end of execution. This information was duplicated again for every server. Airbrussh only displays each command once.
Capistrano logs every command with a unique identifier that looks somewhat like a short git SHA. That’s great for guaranteeing uniqueness and is perfectly suitable for machine parsing, but for humans it is mostly gibberish. Airbrussh replaces them with a simple 01, 02, 03 sequence of numbers.
I found that Capistrano’s long commands meant that each log message would always wrap onto multiple lines. This made reading the logs difficult. Airbrussh truncates each message to the width of the console window.
In UI design, achieving an aesthetically-satisfying result often means simplifying and removing information. However, this can be taken too far and valuable data can be lost as a result. On the web we can use accordion widgets, tooltips, advanced tabs, and other design patterns to keep the 80% case simple, and still ensure that the additional data is available when needed.
For Airbrussh, stripping out things like
/usr/bin/env certainly cleans up the output, which is good for the general case. But when something goes wrong with a deployment, it’s important to have access to the actual, un-stripped command that failed to execute.
To strike the right balance, I implemented the logging equivalent of an “advanced tab”: Airbrussh sends all of Capistrano’s default, unabbreviated output to a separate log file. If a deployment goes badly, I can dig into that file for all the forensic data I need.
$ cap production deploy
Using airbrussh format.
Verbose output is being written to log/capistrano.log.
So far I’ve talked about how Airbrussh makes Capistrano’s output prettier and easier to read, which are typically considered UI concerns. What about UX, then?
What I consider to be the core of UX is figuring out what users are trying to accomplish, then building new paths or optimizing existing ones to help users meet those goals. Here’s what I came up with in terms of UX improvements as applied to Airbrussh.
Capistrano’s default output shows you the actual commands being executed on the servers, but it makes no mention of why they are being run. Airbrussh prints the name of the parent task so that the chain of events that leads to commands being executed is nice and clear.
Capistrano deployments can take a long time, and it’s the job of the logging output to explain why – or at least, to show where the time is spent. To address this, Airbrussh displays the elapsed time in the left margin of the output, along with timing information for each execution.
I’ve learned on the web that users expect some sort of visual feedback whenever a task takes longer than a second or two to complete. The same applies to Capistrano, and I’d love to add a progress bar, or at least a spinner animation while slow commands are being executed (
rake assets:precompile, I’m looking at you). Pull requests are welcome!
Finally, an often overlooked part of UX is making the “first run” experience as welcoming and self-explanatory as possible. For Airbrussh, that means a quick and painless installation process. Just add
airbrussh to the Gemfile and Capfile.3 It doesn’t get much simpler than that!
gem "airbrussh", :require => false
Years ago, when I switched from Java development to Rails, one of the first differences that struck me was the logging output. Benchmarks! Easy to follow request traces! ANSI color! It was a breath of fresh air. In the Rails world, even the logs looked better and were more useful.
If you are an open source contributor, I encourage you to look for opportunities to make similar improvements to the console and log output of the tools you use. Even if it’s just adding ANSI colors or touching up alignment and indentation, consider opening a pull request for those small changes. For those of us staring at our screens and digging through logs day after day, your attention to detail will not go unappreciated!
Oh, and if you haven’t installed Airbrussh yet, give it a try.
I created the capistrano-mb gem that extends Capistrano with many “server provisioning” tasks, like setting up Nginx and PostgreSQL, compiling Ruby, and lots more. I found that using a familiar tool like Capistrano was an easy way to automate these tasks, rather than deal with the learning curve of something like Chef or Puppet. ↩
To oversimplify a bit, a log formatter is an object that has a
<<(obj)method. The job of this method is to take in a command or log message, format it as desired, and then write it to the underlying output (usually stdout). Commands in Capistrano are represented as rich objects that contain information about when the command was started, the server where it is being executed, and its exit status – this makes Airbrussh’s formatting possible. ↩
Airbrussh offers a special
require "airbrussh/capistrano"entry point that automates the 80% case of plugging into Capistrano’s logging system at startup. The default
require "airbrussh"has no special side-effects, so developers can always opt-out of this magic. ↩