Thursday, 26 March 2015

Logging from Go

I recently wrote about some of the features of Go that I really like for getting code into production.  After my initial excitement there were a couple of things I had to check before being certain Go would be a winner.  The first was logging.  Can I easily get log messages from my app to where I can see them?  For us that means the excellent Logentries service.

I've written before about reconfiguring Java syslogging in Mule to send to Logentries.  It was hard won ground and not an experience I would like to repeat.  Logging from Java is a mess.  Throw in multi line strack traces caused by exceptions "bubbling up the stack" and getting a readable message into a syslog server is suddenly an exercise in frustration.  There is an excellent blog about this from ZeroTurnaround - The State of Logging in Java 2013.  An unsurprising finding is that 87% of respondents to a questionnaire have no real-time way of seeing logs from their applications in production.  In 2013 there was already a confusing array of Java logging frameworks and facades. Figuring out how to make them play nicely with your application, your dev, test, and prod environments, and your syslog server is a problem that quickly goes into the basket marked Too Hard.  By 2015 things in Java land have not got simpler.  If you're in that 87% of developers I sympathize - there is little to make logging from your application as easy as it should be.

It turns out logging from Go is so easy I was left wondering how it ever got so hard in that other language.  There are two core Go packages.

  • log - a simple logging package.
  • log/syslog - an interface to the system log service.

Check the Go example for using the log package.  It writes to stderr, if you're a Twelve-Factor App acolyte then you are nearly done (you will need to switch stderr to stdout).  We like to go a step further and have an application in production send it's log messages straight to Logentries.

This is easy to achieve using the log and log/syslog packages using TCP or UDP:



The Logentries docs suggest the use of TLS for untrusted networks.  When we're running code in The Cloud and sending log messages to somewhere else in The Cloud, that means all networks.  By using the crypto packages (also in the Go core) this is easy to achieve.  It's made even easier by the Go code being open source - I can largely copy the experts by reading the syslog code.

log/logentries is a Go package I wrote that makes it easy to reconfigure log to send messages to Logentries.  Before you jump in it's worth understanding my requirements:

  • I'm usually most interested in log messages during app start up (when configuration errors tend to show up).
  • Once an app is up and running we use metrics (not log messages) to track application performance.
  • I don't ever want an app to block on logging.
  • If Logentries is not available for a some time I'm happy to log to stderr and then manually retrieve the logs later if I really need them.  An alternative would be to store and forward.
  • A logger is for logging and a debugger is for, well, debugging.  If you have to use logging for debugging then DELETE those calls before you commit.
  • I want to deploy applications without having to set up a syslog server as well.  Syslog servers and their configuration are an arcane art best left to a specialist

If you need more features, the code is open source.  I hope it makes a useful starting point for you.

Sending our log message to Logentries from Go is now a simple case of calling one method during init.  The rest of the application code is unchanged.  During development we set an empty Logentries token.  This causes the Init method to no-op and the app continues to log only to stderr.  Here's an example app, using the package, that will log to Logentries every five seconds.  Create your own Logentries token and try it out.


This is how easy logging should be.  It's important, I need it, but it shouldn't be a battle.  Go makes it easy to log what I need and spend my energy focusing on the business problem.

Sunday, 8 March 2015

Go


Last year I was trying out some of the cool features in Postgres and Postgis for generating JSON and GeoJSON in the database.  I wanted to try these features for making a web service and I decided to try a new programming language for the task. 

Here's a teaser of the conclusion - more open data from GeoNet.

The image shows a slow slip event or silent earthquake recorded at the Gisborne GPS site.

Going Go


I had already run through the Tour of Go.  A lot has been written about Go syntax and language features.  I liked what I saw well enough to do some investigation where the hard work often is - putting code into production. 

The Web Server


We've been embedding Jetty in our Java apps and deploying them via RPMs for a long time.  I wanted to write a web service in Go and assumed I would need some sort of additional server application to deploy a Go app, or at the very least something to run in front of it.  Nope!  First mistake.  There is a fully functioning web server in the core libs.

Runtime


So I'm bound to need some kind of runtime on production, right?  Nope!  Go apps compile to a single binary. 

Deploying a Go web application looks like this: Drop binary on system. Start it up. Job Done.

Dependencies and Compilation


There are a lot of powerful features in the core Go packages but external dependencies are inevitable at some point.  I expected some binary package management tool.  Dependency repos in the clouds.  Broken meta data.  Version skew in production and general gnashing of teeth.  Nope, nope, and nope!  The Go compiler is so fast you compile all your code and its dependencies from source in single digit seconds or less.  It's straightforward to get or vendor drop dependencies for your code. 

Given the C-like syntax, surely I was going to have to write a Makefile?  Noooope.  If you organise your code as suggested the go tool can build it for you with no further help.

Sold on Go


By this point I was hooked.  No Russain Doll JVM+Container+App deployment.  No dependency hell.  No compile and package time taking so long that I could forget what I was doing while I waited.  It is so easy to compile and deploy Go code.  It looks like someone really cares about making our jobs easier.

A Real Project


I turned the web services experiment into a real project - FITS (Field Time Series) - storing low data rate field data collected for the GeoNet project.  FITS code is available on Github.

The fledgling first version of the FITS api is available to use now.

Here's those JSON and GeoJSON functions in action. They return site information as GeoJSON.

Visualizing the data easily from FITS is important.  I used the excellent svgo package.  SVG browser support is now very good and an SVG image handles well in a responsive web page.  The image at the top of this post is SVG straight from the FITS api.


Deployment - Docker


Having gone trendy with the code, I went full trendy with the deployment.  It's deployed in a Docker container.  The Docker build, including compiling the Go code in the container, is done in Quay.io.  The build is triggered from Github commits.  The FITS Quay repo is available.  Getting code to production this way is embarrassingly easy.  Go and containers work together like two things that go really well together... for example, a glass of whisky and another glass of whisky.

FITS runs in production in Amazon Web Services (AWS) in the Sydney region.  FITS uses AWS Elastic Beanstalk and AWS Relational Database Service running Postgres+Postgis for the database. 

Going Forward


I've done a few projects in Go now.  I still really like it.  Go makes building and deploying code as easy as it should be.  Most importantly to me - I'm really enjoying programming like I javan't done for quite a while.