Intro
Recently, I decided I wanted to customize the output of a Rake run so that the various messages emitting during Rake’s processing were preceded by a timestamp, something like this:
[08:32:02.013] cc -c foo.c -Iinclude
[08:32:02.821] cc -o foo foo.o -Llib
In addition, I wanted a simple function that would write a message to
standard output or error, if rake
had been invoked with the -v
(verbose)
command line option.
I figured these goals should be easily satisfied.
- Rake already emits some messages only if
-v
is specified, so I assumed a function already existed that I could use; I’d merely have to find it. - The Rakefile is, essentially, an instance of a
Rake::Application
object and has access to much of the Rake runtime, so it should be able to customize whatever message format is used to emit Rake messages.
As it happens, solving both problems was less trivial than I expected. I did come up with a solution, but it’s brittle and likely to break if subsequent versions of Rake change how things are done under the covers.
Perhaps someone else out there has solved these problems more elegantly.
Hacking Rake’s Output Messages
To solve this problem, I had to do a little metaprogramming. I located two places where Rake emits messages. The first is via the FileUtils module, which Rake augments. Digging through the code, I noticed that FileUtils supports a label that can be set to a prefix to use for output messages. So, it’s possible to patch FileUtils, like so:
1 2 3 4 5 6 7 |
|
The other method that needs to be patched is Rake’s rake_output_message
function:
1 2 3 4 |
|
Emitting Verbose Messages
I thought Rake might have a method that one could call to emit messages
only if -v
had been specified, akin to the way logging frameworks work.
I couldn’t find one, however, so I simply wrote my own:
1 2 3 4 5 |
|
This function, in combination with the metaprogramming, above, allows me to write tasks like this:
1 2 3 4 |
|
Putting It All Together
I elected to put this hack in a gem, which consolidates the timestamp stuff into one place, like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
The GrizzledRake::TimeFormat
module simply consolidates the timeformat
handling in one place.
Once the gem is installed, two lines of code in my Rakefile will enable timestamps:
1 2 3 4 5 |
|
Note that I extended the strftime escapes to support a $m
escape, allowing
the insertion of milliseconds into the output. strftime does not support
that capability.
Conclusion
This works, but it’s a complete hack, and it’s brittle: If the innards of
FileUtils
or Rake change, this approach might break, without warning.
Ideally, Rake’s API would provide a clean way to accomplish these goals, without this kind of hacking. Until it does, though, metaprogramming for the win.