Thursday, May 31, 2012

Logging in Ruby to S3

So one of the requirements I have in my dissertation work is to provide a centralized logging location for the 20-30 VM images I use.  The VM's themselves host a system that provides overlay network functionality in either hierarchical or non-hierarchical forms in a variety of levels of granularity, and the individual nodes in the overlay networks need to report some status and other information regularly that I need to then retrieve and analyze.  Using the filesystem for this is just not workable as the logs are, first, downright hemorrhoidal to download and collate, and second, the providers I'm using like to pseudo-randomly delete transient files from your filesystem.  I decided that the easiest way to go was to use something cheap and easy like S3.  So instead of using something just like S3, I went ahead and used S3.

I also didn't want to create my own logging system, because I wasn't going to spend enough time on it to make it un-sucky.  So I decided to use logging - looks feature rich and easy to use, and nicely tested to boot.  Plus it's newer than log4r, so that's nifty too.  And I can format logging messages in YAML, which means analysis of the log messages is a breeze via the Ruby YAML gem.

Okay, so using logging, I can publish log records in YAML using a mature logging framework.  And I'd like to store these messages in S3.  So how to go about doing that?

Well, first, let's configure a really simple STDOUT logger that formats data in YAML (this is all implemented via examples from the logging distribution, I encourage you to look through the examples).


So this example formats the log entries in YAML, and also formats any saved data structures in YAML for later recreation! Pretty handy:



Some text here.  Now that we have a system that will save information in YAML, we need to send the information to S3 in some way.  In order to do that, we can add a custom appender to the logging library. Fortunately, I'm using Ruby, so this isn't as hard as it sounds.

First, let's create a simple class within the logging modules that recreates the STDOUT logging we just demonstrated.  Looking through the logging codebase, we can follow the example in console.rb by creating a factory method and implementation class.  The final example looks like this:



Now this is hardwired to emit YAML, but that's okay, that's really all I need.  Here, we create a factory method, register the implementation class, and then create a really simple class implementing the methods from the Ruby IO class that we really need (e.g. the syswrite(.) method).  With that in place, we change our logging script to use the new appender:


And we get YAML output with the new field:


Note the new field, source, something pretty important when combining log files from a bunch of different sources.

Now that I have this in place, I'll start looking at how to wire it to S3 and test it in RSpec.

No comments:

Post a Comment