<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Node.js Blog</title>
  <atom:link href="http://blog.nodejs.org/module/" rel="self" type="application/rss+xml" />
  <link>http://blog.nodejs.org/</link>
	<description>The Blog about Node.js</description>
  <lastBuildDate>Fri, 17 May 2013 21:36:09 GMT</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>weekly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://nodejs.org/</generator>
  <image>
    <url>http://nodejs.org/images/logo-light.png</url>
		<title>Node.js</title>
    <link>http://blog.nodejs.org/</link>
	</image>
  
    <item>
      <title>multi-server continuous deployment with fleet</title>
      <link>http://blog.nodejs.org/2012/05/02/multi-server-continuous-deployment-with-fleet/</link>
      <pubDate>Wed, 02 May 2012 18:00:00 GMT</pubDate>
      <dc:creator>Isaac Schlueter</dc:creator>
      <category><![CDATA[module]]></category>

      <guid isPermaLink="true">http://blog.nodejs.org/2012/05/02/multi-server-continuous-deployment-with-fleet/</guid>
      <description><![CDATA[<p><img style="float:right;margin-left:1.2em;" alt="substack" src="http://substack.net/images/substackistan.png"><i>This is a guest post by James &quot;SubStack&quot; Halliday, originally posted <a href="http://substack.net/posts/16a9d8/multi-server-continuous-deployment-with-fleet">on his blog</a>, and reposted here with permission.</i></p>

<p>Writing applications as a sequence of tiny services that all talk to each other over the network has many upsides, but it can be annoyingly tedious to get all the subsystems up and running. </p>

<p>Running a <a href="http://substack.net/posts/7a1c42">seaport</a> can help with getting all the services to talk to each other, but running the processes is another matter, especially when you have new code to push into production. </p>

<p><a href="http://github.com/substack/fleet">fleet</a> aims to make it really easy for anyone on your team to push new code from git to an armada of servers and manage all the processes in your stack. </p>

<p>To start using fleet, just install the fleet command with <a href="http://npmjs.org">npm</a>: </p>

<pre style="">npm install -g fleet </pre>

<p>Then on one of your servers, start a fleet hub. From a fresh directory, give it a passphrase and a port to listen on: </p>

<pre style="">fleet hub --port=7000 --secret=beepboop </pre>

<p>Now fleet is listening on :7000 for commands and has started a git server on :7001 over http. There&#39;s no ssh keys or post commit hooks to configure, just run that command and you&#39;re ready to go! </p>

<p>Next set up some worker drones to run your processes. You can have as many workers as you like on a single server but each worker should be run from a separate directory. Just do: </p>

<pre style="">fleet drone --hub=x.x.x.x:7000 --secret=beepboop </pre>

<p>where <span class="code">x.x.x.x</span> is the address where the fleet hub is running. Spin up a few of these drones. </p>

<p>Now navigate to the directory of the app you want to deploy. First set a remote so you don&#39;t need to type <span class="code">--hub</span> and <span class="code">--secret</span> all the time. </p>

<pre style="">fleet remote add default --hub=x.x.x.x:7000 --secret=beepboop </pre>

<p>Fleet just created a <span class="code">fleet.json</span> file for you to save your settings. </p>

<p>From the same app directory, to deploy your code just do: </p>

<pre style="">fleet deploy </pre>

<p>The deploy command does a <span class="code">git push</span> to the fleet hub&#39;s git http server and then the hub instructs all the drones to pull from it. Your code gets checked out into a new directory on all the fleet drones every time you deploy. </p>

<p>Because fleet is designed specifically for managing applications with lots of tiny services, the deploy command isn&#39;t tied to running any processes. Starting processes is up to the programmer but it&#39;s super simple. Just use the <span class="code">fleet spawn</span> command: </p>

<pre style="">fleet spawn -- node server.js 8080 </pre>

<p>By default fleet picks a drone at random to run the process on. You can specify which drone you want to run a particular process on with the <span class="code">--drone</span> switch if it matters. </p>

<p>Start a few processes across all your worker drones and then show what is running with the <span class="code">fleet ps</span> command: </p>

<pre style="">fleet ps
drone#3dfe17b8
├─┬ pid#1e99f4
│ ├── status:   running
│ ├── commit:   webapp/1b8050fcaf8f1b02b9175fcb422644cb67dc8cc5
│ └── command:  node server.js 8888
└─┬ pid#d7048a
  ├── status:   running
  ├── commit:   webapp/1b8050fcaf8f1b02b9175fcb422644cb67dc8cc5
  └── command:  node server.js 8889</pre>

<p>Now suppose that you have new code to push out into production. By default, fleet lets you spin up new services without disturbing your existing services. If you <span class="code">fleet deploy</span> again after checking in some new changes to git, the next time you <span class="code">fleet spawn</span> a new process, that process will be spun up in a completely new directory based on the git commit hash. To stop a process, just use <span class="code">fleet stop</span>. </p>

<p>This approach lets you verify that the new services work before bringing down the old services. You can even start experimenting with heterogeneous and incremental deployment by hooking into a custom <a href="http://substack.net/posts/5bd18d">http proxy</a>! </p>

<p>Even better, if you use a service registry like  <a href="http://substack.net/posts/7a1c42">seaport</a> for managing the host/port tables, you can spin up new ad-hoc staging clusters all the time without disrupting the normal operation of your site before rolling out new code to users. </p>

<p>Fleet has many more commands that you can learn about with its git-style manpage-based help system! Just do <span class="code">fleet help</span> to get a list of all the commands you can run. </p>

<pre style="">fleet help
Usage: fleet &lt;command&gt; [&lt;args&gt;]

The commands are:
  deploy   Push code to drones.
  drone    Connect to a hub as a worker.
  exec     Run commands on drones.
  hub      Create a hub for drones to connect.
  monitor  Show service events system-wide.
  ps       List the running processes on the drones.
  remote   Manage the set of remote hubs.
  spawn    Run services on drones.
  stop     Stop processes running on drones.

For help about a command, try `fleet help `.</pre>

<p><span class="code">npm install -g fleet</span> and <a href="https://github.com/substack/fleet">check out the code on github</a>! </p>

<p><img src="http://substack.net/images/fleet.png" width="849" height="568">
</p>
]]></description>
      <content:encoded><![CDATA[<p><img style="float:right;margin-left:1.2em;" alt="substack" src="http://substack.net/images/substackistan.png"><i>This is a guest post by James &quot;SubStack&quot; Halliday, originally posted <a href="http://substack.net/posts/16a9d8/multi-server-continuous-deployment-with-fleet">on his blog</a>, and reposted here with permission.</i></p>

<p>Writing applications as a sequence of tiny services that all talk to each other over the network has many upsides, but it can be annoyingly tedious to get all the subsystems up and running. </p>

<p>Running a <a href="http://substack.net/posts/7a1c42">seaport</a> can help with getting all the services to talk to each other, but running the processes is another matter, especially when you have new code to push into production. </p>

<p><a href="http://github.com/substack/fleet">fleet</a> aims to make it really easy for anyone on your team to push new code from git to an armada of servers and manage all the processes in your stack. </p>

<p>To start using fleet, just install the fleet command with <a href="http://npmjs.org">npm</a>: </p>

<pre style="">npm install -g fleet </pre>

<p>Then on one of your servers, start a fleet hub. From a fresh directory, give it a passphrase and a port to listen on: </p>

<pre style="">fleet hub --port=7000 --secret=beepboop </pre>

<p>Now fleet is listening on :7000 for commands and has started a git server on :7001 over http. There&#39;s no ssh keys or post commit hooks to configure, just run that command and you&#39;re ready to go! </p>

<p>Next set up some worker drones to run your processes. You can have as many workers as you like on a single server but each worker should be run from a separate directory. Just do: </p>

<pre style="">fleet drone --hub=x.x.x.x:7000 --secret=beepboop </pre>

<p>where <span class="code">x.x.x.x</span> is the address where the fleet hub is running. Spin up a few of these drones. </p>

<p>Now navigate to the directory of the app you want to deploy. First set a remote so you don&#39;t need to type <span class="code">--hub</span> and <span class="code">--secret</span> all the time. </p>

<pre style="">fleet remote add default --hub=x.x.x.x:7000 --secret=beepboop </pre>

<p>Fleet just created a <span class="code">fleet.json</span> file for you to save your settings. </p>

<p>From the same app directory, to deploy your code just do: </p>

<pre style="">fleet deploy </pre>

<p>The deploy command does a <span class="code">git push</span> to the fleet hub&#39;s git http server and then the hub instructs all the drones to pull from it. Your code gets checked out into a new directory on all the fleet drones every time you deploy. </p>

<p>Because fleet is designed specifically for managing applications with lots of tiny services, the deploy command isn&#39;t tied to running any processes. Starting processes is up to the programmer but it&#39;s super simple. Just use the <span class="code">fleet spawn</span> command: </p>

<pre style="">fleet spawn -- node server.js 8080 </pre>

<p>By default fleet picks a drone at random to run the process on. You can specify which drone you want to run a particular process on with the <span class="code">--drone</span> switch if it matters. </p>

<p>Start a few processes across all your worker drones and then show what is running with the <span class="code">fleet ps</span> command: </p>

<pre style="">fleet ps
drone#3dfe17b8
├─┬ pid#1e99f4
│ ├── status:   running
│ ├── commit:   webapp/1b8050fcaf8f1b02b9175fcb422644cb67dc8cc5
│ └── command:  node server.js 8888
└─┬ pid#d7048a
  ├── status:   running
  ├── commit:   webapp/1b8050fcaf8f1b02b9175fcb422644cb67dc8cc5
  └── command:  node server.js 8889</pre>

<p>Now suppose that you have new code to push out into production. By default, fleet lets you spin up new services without disturbing your existing services. If you <span class="code">fleet deploy</span> again after checking in some new changes to git, the next time you <span class="code">fleet spawn</span> a new process, that process will be spun up in a completely new directory based on the git commit hash. To stop a process, just use <span class="code">fleet stop</span>. </p>

<p>This approach lets you verify that the new services work before bringing down the old services. You can even start experimenting with heterogeneous and incremental deployment by hooking into a custom <a href="http://substack.net/posts/5bd18d">http proxy</a>! </p>

<p>Even better, if you use a service registry like  <a href="http://substack.net/posts/7a1c42">seaport</a> for managing the host/port tables, you can spin up new ad-hoc staging clusters all the time without disrupting the normal operation of your site before rolling out new code to users. </p>

<p>Fleet has many more commands that you can learn about with its git-style manpage-based help system! Just do <span class="code">fleet help</span> to get a list of all the commands you can run. </p>

<pre style="">fleet help
Usage: fleet &lt;command&gt; [&lt;args&gt;]

The commands are:
  deploy   Push code to drones.
  drone    Connect to a hub as a worker.
  exec     Run commands on drones.
  hub      Create a hub for drones to connect.
  monitor  Show service events system-wide.
  ps       List the running processes on the drones.
  remote   Manage the set of remote hubs.
  spawn    Run services on drones.
  stop     Stop processes running on drones.

For help about a command, try `fleet help `.</pre>

<p><span class="code">npm install -g fleet</span> and <a href="https://github.com/substack/fleet">check out the code on github</a>! </p>

<p><img src="http://substack.net/images/fleet.png" width="849" height="568">
</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Service logging in JSON with Bunyan</title>
      <link>http://blog.nodejs.org/2012/03/28/service-logging-in-json-with-bunyan/</link>
      <pubDate>Wed, 28 Mar 2012 19:25:26 GMT</pubDate>
      <dc:creator>trentmick</dc:creator>
      <category><![CDATA[module]]></category>

      <guid isPermaLink="true">http://blog.nodejs.org/2012/03/28/service-logging-in-json-with-bunyan/</guid>
      <description><![CDATA[<div style="float:right;margin:0 0 15px 15px;">
<img class="alignnone size-full wp-image-469" title="Bunyan" src="http://nodeblog.files.wordpress.com/2012/03/bunyan.png" alt="Paul Bunyan and Babe the Blue Ox" width="240" height="320" /><br />
<a href="http://www.flickr.com/photos/stublag/2876034487">Photo by Paul Carroll</a>
</div>

<p>Service logs are gold, if you can mine them. We scan them for occasional debugging. Perhaps we grep them looking for errors or warnings, or setup an occasional nagios log regex monitor. If that. This is a waste of the best channel for data about a service.</p>

<p><a href="http://www.youtube.com/watch?v=01-2pNCZiNk">&quot;Log. (Huh) What is it good for. Absolutely ...&quot;</a></p>

<ul>
<li>debugging</li>
<li>monitors tools that alert operators</li>
<li>non real-time analysis (business or operational analysis)</li>
<li>historical analysis</li>
</ul>

<p>These are what logs are good for. The current state of logging is barely adequate for the first of these. Doing reliable analysis, and even monitoring, of varied <a href="http://journal.paul.querna.org/articles/2011/12/26/log-for-machines-in-json/">&quot;printf-style&quot; logs</a> is a grueling or hacky task that most either don&#39;t bother with, fallback to paying someone else to do (viz. Splunk&#39;s great successes), or, for web sites, punt and use the plethora of JavaScript-based web analytics tools.</p>

<p>Let&#39;s log in JSON. Let&#39;s format log records with a filter <em>outside</em> the app. Let&#39;s put more info in log records by not shoehorning into a printf-message. Debuggability can be improved. Monitoring and analysis can <em>definitely</em> be improved. Let&#39;s <em>not</em> write another regex-based parser, and use the time we&#39;ve saved writing tools to collate logs from multiple nodes and services, to query structured logs (from all services, not just web servers), etc.</p>

<p>At <a href="http://joyent.com">Joyent</a> we use node.js for running many core services -- loosely coupled through HTTP REST APIs and/or AMQP. In this post I&#39;ll draw on experiences from my work on Joyent&#39;s <a href="http://www.joyent.com/products/smartdatacenter/">SmartDataCenter product</a> and observations of <a href="http://www.joyentcloud.com/">Joyent Cloud</a> operations to suggest some improvements to service logging. I&#39;ll show the (open source) <strong>Bunyan logging library and tool</strong> that we&#39;re developing to improve the logging toolchain.</p>

<h1 style="margin:48px 0 24px;" id="current-state-of-log-formatting">Current State of Log Formatting</h1>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code># apache access log
10.0.1.22 - - [15/Oct/2010:11:46:46 -0700] "GET /favicon.ico HTTP/1.1" 404 209
fe80::6233:4bff:fe29:3173 - - [15/Oct/2010:11:46:58 -0700] "GET / HTTP/1.1" 200 44

# apache error log
[Fri Oct 15 11:46:46 2010] [error] [client 10.0.1.22] File does not exist: /Library/WebServer/Documents/favicon.ico
[Fri Oct 15 11:46:58 2010] [error] [client fe80::6233:4bff:fe29:3173] File does not exist: /Library/WebServer/Documents/favicon.ico

# Mac /var/log/secure.log
Oct 14 09:20:56 banana loginwindow[41]: in pam_sm_authenticate(): Failed to determine Kerberos principal name.
Oct 14 12:32:20 banana com.apple.SecurityServer[25]: UID 501 authenticated as user trentm (UID 501) for right 'system.privilege.admin'

# an internal joyent agent log
[2012-02-07 00:37:11.898] [INFO] AMQPAgent - Publishing success.
[2012-02-07 00:37:11.910] [DEBUG] AMQPAgent - { req_id: '8afb8d99-df8e-4724-8535-3d52adaebf25',
  timestamp: '2012-02-07T00:37:11.898Z',

# typical expressjs log output
[Mon, 21 Nov 2011 20:52:11 GMT] 200 GET /foo (1ms)
Blah, some other unstructured output to from a console.log call.
</code></pre>

<p>What&#39;re we doing here? Five logs at random. Five different date formats. As <a href="http://journal.paul.querna.org/articles/2011/12/26/log-for-machines-in-json/">Paul Querna points out</a> we haven&#39;t improved log parsability in 20 years. Parsability is enemy number one. You can&#39;t use your logs until you can parse the records, and faced with the above the inevitable solution is a one-off regular expression.</p>

<p>The current state of the art is various <a href="http://search.cpan.org/~akira/Apache-ParseLog-1.02/ParseLog.pm">parsing libs</a>, <a href="http://www.webalizer.org/">analysis</a> <a href="http://awstats.sourceforge.net/">tools</a> and homebrew scripts ranging from grep to Perl, whose scope is limited to a few niches log formats.</p>

<h1 style="margin:48px 0 24px;" id="json-for-logs">JSON for Logs</h1>

<p><code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">JSON.parse()</code> solves all that. Let&#39;s log in JSON. But it means a change in thinking: <strong>The first-level audience for log files shouldn&#39;t be a person, but a machine.</strong></p>

<p>That is not said lightly. The &quot;Unix Way&quot; of small focused tools lightly coupled with text output is important. JSON is less &quot;text-y&quot; than, e.g., Apache common log format. JSON makes <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">grep</code> and <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">awk</code> awkward. Using <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">less</code> directly on a log is handy.</p>

<p>But not handy enough. That <a href="http://bit.ly/wTPlN3">80&#39;s pastel jumpsuit awkwardness</a> you&#39;re feeling isn&#39;t the JSON, it&#39;s your tools. Time to find a <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">json</code> tool -- <a href="https://github.com/trentm/json">json</a> is one, <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">bunyan</code> described below is another one. Time to learn your JSON library instead of your regex library: <a href="https://developer.mozilla.org/en/JSON">JavaScript</a>, <a href="http://docs.python.org/library/json.html">Python</a>, <a href="http://flori.github.com/json/">Ruby</a>, <a href="http://json.org/java/">Java</a>, <a href="http://search.cpan.org/~makamaka/JSON-2.53/lib/JSON.pm">Perl</a>.</p>

<p>Time to burn your log4j Layout classes and move formatting to the tools side. Creating a log message with semantic information and throwing that away to make a string is silly. The win at being able to trivially parse log records is huge. The possibilities at being able to add ad hoc structured information to individual log records is interesting: think program state metrics, think feeding to Splunk, or loggly, think easy audit logs.</p>

<h1 style="margin:48px 0 24px;" id="introducing-bunyan">Introducing Bunyan</h1>

<p><a href="https://github.com/trentm/node-bunyan">Bunyan</a> is <strong>a node.js module for logging in JSON</strong> and <strong>a <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">bunyan</code> CLI tool</strong> to view those logs.</p>

<p>Logging with Bunyan basically looks like this:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>$ cat hi.js
var Logger = require('bunyan');
var log = new Logger({name: 'hello' /*, ... */});
log.info("hi %s", "paul");
</code></pre>

<p>And you&#39;ll get a log record like this:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>$ node hi.js
{"name":"hello","hostname":"banana.local","pid":40026,"level":30,"msg":"hi paul","time":"2012-03-28T17:25:37.050Z","v":0}
</code></pre>

<p>Pipe that through the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">bunyan</code> tool that is part of the &quot;node-bunyan&quot; install to get more readable output:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>$ node hi.js | ./node_modules/.bin/bunyan       # formatted text output
[2012-02-07T18:50:18.003Z]  INFO: hello/40026 on banana.local: hi paul

$ node hi.js | ./node_modules/.bin/bunyan -j    # indented JSON output
{
  "name": "hello",
  "hostname": "banana.local",
  "pid": 40087,
  "level": 30,
  "msg": "hi paul",
  "time": "2012-03-28T17:26:38.431Z",
  "v": 0
}
</code></pre>

<p>Bunyan is log4j-like: create a Logger with a name, call <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">log.info(...)</code>, etc. However it has no intention of reproducing much of the functionality of log4j. IMO, much of that is overkill for the types of services you&#39;ll tend to be writing with node.js.</p>

<h1 style="margin:48px 0 24px;" id="longer-bunyan-example">Longer Bunyan Example</h1>

<p>Let&#39;s walk through a bigger example to show some interesting things in Bunyan. We&#39;ll create a very small &quot;Hello API&quot; server using the excellent <a href="https://github.com/mcavage/node-restify">restify</a> library -- which we used heavily here at <a href="http://joyent.com">Joyent</a>. (Bunyan doesn&#39;t require restify at all, you can easily use Bunyan with <a href="http://expressjs.com/">Express</a> or whatever.)</p>

<p><em>You can follow along in <a href="https://github.com/trentm/hello-json-logging">https://github.com/trentm/hello-json-logging</a> if you like. Note that I&#39;m using the current HEAD of the bunyan and restify trees here, so details might change a bit. Prerequisite: a node 0.6.x installation.</em></p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>git clone https://github.com/trentm/hello-json-logging.git
cd hello-json-logging
make
</code></pre>

<h2 id="bunyan-logger">Bunyan Logger</h2>

<p>Our <a href="https://github.com/trentm/hello-json-logging/blob/master/server.js">server</a> first creates a Bunyan logger:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>var Logger = require('bunyan');
var log = new Logger({
  name: 'helloapi',
  streams: [
    {
      stream: process.stdout,
      level: 'debug'
    },
    {
      path: 'hello.log',
      level: 'trace'
    }
  ],
  serializers: {
    req: Logger.stdSerializers.req,
    res: restify.bunyan.serializers.response,
  },
});
</code></pre>

<p>Every Bunyan logger must have a <strong>name</strong>. Unlike log4j, this is not a hierarchical dotted namespace. It is just a name field for the log records.</p>

<p>Every Bunyan logger has one or more <strong>streams</strong>, to which log records are written. Here we&#39;ve defined two: logging at DEBUG level and above is written to stdout, and logging at TRACE and above is appended to &#39;hello.log&#39;.</p>

<p>Bunyan has the concept of <strong>serializers</strong>: a registry of functions that know how to convert a JavaScript object for a certain log record field to a nice JSON representation for logging. For example, here we register the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">Logger.stdSerializers.req</code> function to convert HTTP Request objects (using the field name &quot;req&quot;) to JSON. More on serializers later.</p>

<h2 id="restify-server">Restify Server</h2>

<p>Restify 1.x and above has bunyan support baked in. You pass in your Bunyan logger like this:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>var server = restify.createServer({
  name: 'Hello API',
  log: log   // Pass our logger to restify.
});
</code></pre>

<p>Our simple API will have a single <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">GET /hello?name=NAME</code> endpoint:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>server.get({path: '/hello', name: 'SayHello'}, function(req, res, next) {
  var caller = req.params.name || 'caller';
  req.log.debug('caller is "%s"', caller);
  res.send({"hello": caller});
  return next();
});
</code></pre>

<p>If we run that, <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">node server.js</code>, and call the endpoint, we get the expected restify response:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>$ curl -iSs http://0.0.0.0:8080/hello?name=paul
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version
Access-Control-Expose-Headers: X-Api-Version, X-Request-Id, X-Response-Time
Server: Hello API
X-Request-Id: f6aaf942-c60d-4c72-8ddd-bada459db5e3
Access-Control-Allow-Methods: GET
Connection: close
Content-Length: 16
Content-MD5: Xmn3QcFXaIaKw9RPUARGBA==
Content-Type: application/json
Date: Tue, 07 Feb 2012 19:12:35 GMT
X-Response-Time: 4

{"hello":"paul"}
</code></pre>

<h2 id="setup-server-logging">Setup Server Logging</h2>

<p>Let&#39;s add two things to our server. First, we&#39;ll use the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">server.pre</code> to hook into restify&#39;s request handling before routing where we&#39;ll <strong>log the request</strong>.</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>server.pre(function (request, response, next) {
  request.log.info({req: request}, 'start');        // (1)
  return next();
});
</code></pre>

<p>This is the first time we&#39;ve seen this <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">log.info</code> style with an object as the first argument. Bunyan logging methods (<code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">log.trace</code>, <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">log.debug</code>, ...) all support an optional <strong>first object argument with extra log record fields</strong>:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>log.info(&lt;object&gt; fields, &lt;string&gt; msg, ...)
</code></pre>

<p>Here we pass in the restify Request object, <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">req</code>. The &quot;req&quot; serializer we registered above will come into play here, but bear with me.</p>

<p>Remember that we already had this debug log statement in our endpoint handler:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>req.log.debug('caller is "%s"', caller);            // (2)
</code></pre>

<p>Second, use the restify server <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">after</code> event to <strong>log the response</strong>:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>server.on('after', function (req, res, route) {
  req.log.info({res: res}, "finished");             // (3)
});
</code></pre>

<h2 id="log-output">Log Output</h2>

<p>Now lets see what log output we get when somebody hits our API&#39;s endpoint:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>$ curl -iSs http://0.0.0.0:8080/hello?name=paul
HTTP/1.1 200 OK
...
X-Request-Id: 9496dfdd-4ec7-4b59-aae7-3fed57aed5ba
...

{"hello":"paul"}
</code></pre>

<p>Here is the server log:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>[trentm@banana:~/tm/hello-json-logging]$ node server.js
... intro "listening at" log message elided ...
{"name":"helloapi","hostname":"banana.local","pid":40341,"level":30,"req":{"method":"GET","url":"/hello?name=paul","headers":{"user-agent":"curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8r zlib/1.2.3","host":"0.0.0.0:8080","accept":"*/*"},"remoteAddress":"127.0.0.1","remotePort":59831},"msg":"start","time":"2012-03-28T17:37:29.506Z","v":0}
{"name":"helloapi","hostname":"banana.local","pid":40341,"route":"SayHello","req_id":"9496dfdd-4ec7-4b59-aae7-3fed57aed5ba","level":20,"msg":"caller is \"paul\"","time":"2012-03-28T17:37:29.507Z","v":0}
{"name":"helloapi","hostname":"banana.local","pid":40341,"route":"SayHello","req_id":"9496dfdd-4ec7-4b59-aae7-3fed57aed5ba","level":30,"res":{"statusCode":200,"headers":{"access-control-allow-origin":"*","access-control-allow-headers":"Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version","access-control-expose-headers":"X-Api-Version, X-Request-Id, X-Response-Time","server":"Hello API","x-request-id":"9496dfdd-4ec7-4b59-aae7-3fed57aed5ba","access-control-allow-methods":"GET","connection":"close","content-length":16,"content-md5":"Xmn3QcFXaIaKw9RPUARGBA==","content-type":"application/json","date":"Wed, 28 Mar 2012 17:37:29 GMT","x-response-time":3}},"msg":"finished","time":"2012-03-28T17:37:29.510Z","v":0}
</code></pre>

<p>Lets look at each in turn to see what is interesting -- pretty-printed with <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">node server.js | ./node_modules/.bin/bunyan -j</code>:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>{                                                   // (1)
  "name": "helloapi",
  "hostname": "banana.local",
  "pid": 40442,
  "level": 30,
  "req": {
    "method": "GET",
    "url": "/hello?name=paul",
    "headers": {
      "user-agent": "curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8r zlib/1.2.3",
      "host": "0.0.0.0:8080",
      "accept": "*/*"
    },
    "remoteAddress": "127.0.0.1",
    "remotePort": 59834
  },
  "msg": "start",
  "time": "2012-03-28T17:39:44.880Z",
  "v": 0
}
</code></pre>

<p>Here we logged the incoming request with <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">request.log.info({req: request}, &#39;start&#39;)</code>. The use of the &quot;req&quot; field triggers the <a href="https://github.com/trentm/node-bunyan/blob/master/lib/bunyan.js#L857-870">&quot;req&quot; serializer</a> <a href="https://github.com/trentm/hello-json-logging/blob/master/server.js#L24">registered at Logger creation</a>.</p>

<p>Next the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">req.log.debug</code> in our handler:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>{                                                   // (2)
  "name": "helloapi",
  "hostname": "banana.local",
  "pid": 40442,
  "route": "SayHello",
  "req_id": "9496dfdd-4ec7-4b59-aae7-3fed57aed5ba",
  "level": 20,
  "msg": "caller is \"paul\"",
  "time": "2012-03-28T17:39:44.883Z",
  "v": 0
}
</code></pre>

<p>and the log of response in the &quot;after&quot; event:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>{                                                   // (3)
  "name": "helloapi",
  "hostname": "banana.local",
  "pid": 40442,
  "route": "SayHello",
  "req_id": "9496dfdd-4ec7-4b59-aae7-3fed57aed5ba",
  "level": 30,
  "res": {
    "statusCode": 200,
    "headers": {
      "access-control-allow-origin": "*",
      "access-control-allow-headers": "Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version",
      "access-control-expose-headers": "X-Api-Version, X-Request-Id, X-Response-Time",
      "server": "Hello API",
      "x-request-id": "9496dfdd-4ec7-4b59-aae7-3fed57aed5ba",
      "access-control-allow-methods": "GET",
      "connection": "close",
      "content-length": 16,
      "content-md5": "Xmn3QcFXaIaKw9RPUARGBA==",
      "content-type": "application/json",
      "date": "Wed, 28 Mar 2012 17:39:44 GMT",
      "x-response-time": 5
    }
  },
  "msg": "finished",
  "time": "2012-03-28T17:39:44.886Z",
  "v": 0
}
</code></pre>

<p>Two useful details of note here:</p>

<ol>
<li><p>The last two log messages include <strong>a &quot;req_id&quot; field</strong> (added to the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">req.log</code> logger by restify). Note that this is the same UUID as the &quot;X-Request-Id&quot; header in the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">curl</code> response. This means that if you use <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">req.log</code> for logging in your API handlers you will get an easy way to collate all logging for particular requests.</p>

<p>If your&#39;s is an SOA system with many services, a best practice is to carry that X-Request-Id/req_id through your system to enable collating handling of a single top-level request.</p></li>
<li><p>The last two log messages include <strong>a &quot;route&quot; field</strong>. This tells you to which handler restify routed the request. While possibly useful for debugging, this can be very helpful for log-based monitoring of endpoints on a server.</p></li>
</ol>

<p>Recall that we also setup all logging to go the &quot;hello.log&quot; file. This was set at the TRACE level. Restify will log more detail of its operation at the trace level. See <a href="https://gist.github.com/1761772">my &quot;hello.log&quot;</a> for an example. The <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">bunyan</code> tool does a decent job of <a href="https://gist.github.com/1761772#file_2.+cat+hello.log+pipe+bunyan">nicely formatting</a> multiline messages and &quot;req&quot;/&quot;res&quot; keys (with color, not shown in the gist).</p>

<p><em>This</em> is logging you can use effectively.</p>

<h1 style="margin:48px 0 24px;" id="other-tools">Other Tools</h1>

<p>Bunyan is just one of many options for logging in node.js-land. Others (that I know of) supporting JSON logging are <a href="https://github.com/flatiron/winston#readme">winston</a> and <a href="https://github.com/pquerna/node-logmagic/">logmagic</a>. Paul Querna has <a href="http://journal.paul.querna.org/articles/2011/12/26/log-for-machines-in-json/">an excellent post on using JSON for logging</a>, which shows logmagic usage and also touches on topics like the GELF logging format, log transporting, indexing and searching.</p>

<h1 style="margin:48px 0 24px;" id="final-thoughts">Final Thoughts</h1>

<p>Parsing challenges won&#39;t ever completely go away, but it can for your logs if you use JSON. Collating log records across logs from multiple nodes is facilitated by a common &quot;time&quot; field. Correlating logging across multiple services is enabled by carrying a common &quot;req_id&quot; (or equivalent) through all such logs.</p>

<p>Separate log files for a single service is an anti-pattern. The typical Apache example of separate access and error logs is legacy, not an example to follow. A JSON log provides the structure necessary for tooling to easily filter for log records of a particular type.</p>

<p>JSON logs bring possibilities. Feeding to tools like Splunk becomes easy. Ad hoc fields allow for a lightly spec&#39;d comm channel from apps to other services: records with a &quot;metric&quot; could feed to <a href="http://codeascraft.etsy.com/2011/02/15/measure-anything-measure-everything/">statsd</a>, records with a &quot;loggly: true&quot; could feed to loggly.com.</p>

<p>Here I&#39;ve described a very simple example of restify and bunyan usage for node.js-based API services with easy JSON logging. Restify provides a powerful framework for robust API services. Bunyan provides a light API for nice JSON logging and the beginnings of tooling to help consume Bunyan JSON logs.</p>

<p><strong>Update (29-Mar-2012):</strong> Fix styles somewhat for RSS readers.</p>
]]></description>
      <content:encoded><![CDATA[<div style="float:right;margin:0 0 15px 15px;">
<img class="alignnone size-full wp-image-469" title="Bunyan" src="http://nodeblog.files.wordpress.com/2012/03/bunyan.png" alt="Paul Bunyan and Babe the Blue Ox" width="240" height="320" /><br />
<a href="http://www.flickr.com/photos/stublag/2876034487">Photo by Paul Carroll</a>
</div>

<p>Service logs are gold, if you can mine them. We scan them for occasional debugging. Perhaps we grep them looking for errors or warnings, or setup an occasional nagios log regex monitor. If that. This is a waste of the best channel for data about a service.</p>

<p><a href="http://www.youtube.com/watch?v=01-2pNCZiNk">&quot;Log. (Huh) What is it good for. Absolutely ...&quot;</a></p>

<ul>
<li>debugging</li>
<li>monitors tools that alert operators</li>
<li>non real-time analysis (business or operational analysis)</li>
<li>historical analysis</li>
</ul>

<p>These are what logs are good for. The current state of logging is barely adequate for the first of these. Doing reliable analysis, and even monitoring, of varied <a href="http://journal.paul.querna.org/articles/2011/12/26/log-for-machines-in-json/">&quot;printf-style&quot; logs</a> is a grueling or hacky task that most either don&#39;t bother with, fallback to paying someone else to do (viz. Splunk&#39;s great successes), or, for web sites, punt and use the plethora of JavaScript-based web analytics tools.</p>

<p>Let&#39;s log in JSON. Let&#39;s format log records with a filter <em>outside</em> the app. Let&#39;s put more info in log records by not shoehorning into a printf-message. Debuggability can be improved. Monitoring and analysis can <em>definitely</em> be improved. Let&#39;s <em>not</em> write another regex-based parser, and use the time we&#39;ve saved writing tools to collate logs from multiple nodes and services, to query structured logs (from all services, not just web servers), etc.</p>

<p>At <a href="http://joyent.com">Joyent</a> we use node.js for running many core services -- loosely coupled through HTTP REST APIs and/or AMQP. In this post I&#39;ll draw on experiences from my work on Joyent&#39;s <a href="http://www.joyent.com/products/smartdatacenter/">SmartDataCenter product</a> and observations of <a href="http://www.joyentcloud.com/">Joyent Cloud</a> operations to suggest some improvements to service logging. I&#39;ll show the (open source) <strong>Bunyan logging library and tool</strong> that we&#39;re developing to improve the logging toolchain.</p>

<h1 style="margin:48px 0 24px;" id="current-state-of-log-formatting">Current State of Log Formatting</h1>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code># apache access log
10.0.1.22 - - [15/Oct/2010:11:46:46 -0700] "GET /favicon.ico HTTP/1.1" 404 209
fe80::6233:4bff:fe29:3173 - - [15/Oct/2010:11:46:58 -0700] "GET / HTTP/1.1" 200 44

# apache error log
[Fri Oct 15 11:46:46 2010] [error] [client 10.0.1.22] File does not exist: /Library/WebServer/Documents/favicon.ico
[Fri Oct 15 11:46:58 2010] [error] [client fe80::6233:4bff:fe29:3173] File does not exist: /Library/WebServer/Documents/favicon.ico

# Mac /var/log/secure.log
Oct 14 09:20:56 banana loginwindow[41]: in pam_sm_authenticate(): Failed to determine Kerberos principal name.
Oct 14 12:32:20 banana com.apple.SecurityServer[25]: UID 501 authenticated as user trentm (UID 501) for right 'system.privilege.admin'

# an internal joyent agent log
[2012-02-07 00:37:11.898] [INFO] AMQPAgent - Publishing success.
[2012-02-07 00:37:11.910] [DEBUG] AMQPAgent - { req_id: '8afb8d99-df8e-4724-8535-3d52adaebf25',
  timestamp: '2012-02-07T00:37:11.898Z',

# typical expressjs log output
[Mon, 21 Nov 2011 20:52:11 GMT] 200 GET /foo (1ms)
Blah, some other unstructured output to from a console.log call.
</code></pre>

<p>What&#39;re we doing here? Five logs at random. Five different date formats. As <a href="http://journal.paul.querna.org/articles/2011/12/26/log-for-machines-in-json/">Paul Querna points out</a> we haven&#39;t improved log parsability in 20 years. Parsability is enemy number one. You can&#39;t use your logs until you can parse the records, and faced with the above the inevitable solution is a one-off regular expression.</p>

<p>The current state of the art is various <a href="http://search.cpan.org/~akira/Apache-ParseLog-1.02/ParseLog.pm">parsing libs</a>, <a href="http://www.webalizer.org/">analysis</a> <a href="http://awstats.sourceforge.net/">tools</a> and homebrew scripts ranging from grep to Perl, whose scope is limited to a few niches log formats.</p>

<h1 style="margin:48px 0 24px;" id="json-for-logs">JSON for Logs</h1>

<p><code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">JSON.parse()</code> solves all that. Let&#39;s log in JSON. But it means a change in thinking: <strong>The first-level audience for log files shouldn&#39;t be a person, but a machine.</strong></p>

<p>That is not said lightly. The &quot;Unix Way&quot; of small focused tools lightly coupled with text output is important. JSON is less &quot;text-y&quot; than, e.g., Apache common log format. JSON makes <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">grep</code> and <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">awk</code> awkward. Using <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">less</code> directly on a log is handy.</p>

<p>But not handy enough. That <a href="http://bit.ly/wTPlN3">80&#39;s pastel jumpsuit awkwardness</a> you&#39;re feeling isn&#39;t the JSON, it&#39;s your tools. Time to find a <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">json</code> tool -- <a href="https://github.com/trentm/json">json</a> is one, <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">bunyan</code> described below is another one. Time to learn your JSON library instead of your regex library: <a href="https://developer.mozilla.org/en/JSON">JavaScript</a>, <a href="http://docs.python.org/library/json.html">Python</a>, <a href="http://flori.github.com/json/">Ruby</a>, <a href="http://json.org/java/">Java</a>, <a href="http://search.cpan.org/~makamaka/JSON-2.53/lib/JSON.pm">Perl</a>.</p>

<p>Time to burn your log4j Layout classes and move formatting to the tools side. Creating a log message with semantic information and throwing that away to make a string is silly. The win at being able to trivially parse log records is huge. The possibilities at being able to add ad hoc structured information to individual log records is interesting: think program state metrics, think feeding to Splunk, or loggly, think easy audit logs.</p>

<h1 style="margin:48px 0 24px;" id="introducing-bunyan">Introducing Bunyan</h1>

<p><a href="https://github.com/trentm/node-bunyan">Bunyan</a> is <strong>a node.js module for logging in JSON</strong> and <strong>a <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">bunyan</code> CLI tool</strong> to view those logs.</p>

<p>Logging with Bunyan basically looks like this:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>$ cat hi.js
var Logger = require('bunyan');
var log = new Logger({name: 'hello' /*, ... */});
log.info("hi %s", "paul");
</code></pre>

<p>And you&#39;ll get a log record like this:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>$ node hi.js
{"name":"hello","hostname":"banana.local","pid":40026,"level":30,"msg":"hi paul","time":"2012-03-28T17:25:37.050Z","v":0}
</code></pre>

<p>Pipe that through the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">bunyan</code> tool that is part of the &quot;node-bunyan&quot; install to get more readable output:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>$ node hi.js | ./node_modules/.bin/bunyan       # formatted text output
[2012-02-07T18:50:18.003Z]  INFO: hello/40026 on banana.local: hi paul

$ node hi.js | ./node_modules/.bin/bunyan -j    # indented JSON output
{
  "name": "hello",
  "hostname": "banana.local",
  "pid": 40087,
  "level": 30,
  "msg": "hi paul",
  "time": "2012-03-28T17:26:38.431Z",
  "v": 0
}
</code></pre>

<p>Bunyan is log4j-like: create a Logger with a name, call <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">log.info(...)</code>, etc. However it has no intention of reproducing much of the functionality of log4j. IMO, much of that is overkill for the types of services you&#39;ll tend to be writing with node.js.</p>

<h1 style="margin:48px 0 24px;" id="longer-bunyan-example">Longer Bunyan Example</h1>

<p>Let&#39;s walk through a bigger example to show some interesting things in Bunyan. We&#39;ll create a very small &quot;Hello API&quot; server using the excellent <a href="https://github.com/mcavage/node-restify">restify</a> library -- which we used heavily here at <a href="http://joyent.com">Joyent</a>. (Bunyan doesn&#39;t require restify at all, you can easily use Bunyan with <a href="http://expressjs.com/">Express</a> or whatever.)</p>

<p><em>You can follow along in <a href="https://github.com/trentm/hello-json-logging">https://github.com/trentm/hello-json-logging</a> if you like. Note that I&#39;m using the current HEAD of the bunyan and restify trees here, so details might change a bit. Prerequisite: a node 0.6.x installation.</em></p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>git clone https://github.com/trentm/hello-json-logging.git
cd hello-json-logging
make
</code></pre>

<h2 id="bunyan-logger">Bunyan Logger</h2>

<p>Our <a href="https://github.com/trentm/hello-json-logging/blob/master/server.js">server</a> first creates a Bunyan logger:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>var Logger = require('bunyan');
var log = new Logger({
  name: 'helloapi',
  streams: [
    {
      stream: process.stdout,
      level: 'debug'
    },
    {
      path: 'hello.log',
      level: 'trace'
    }
  ],
  serializers: {
    req: Logger.stdSerializers.req,
    res: restify.bunyan.serializers.response,
  },
});
</code></pre>

<p>Every Bunyan logger must have a <strong>name</strong>. Unlike log4j, this is not a hierarchical dotted namespace. It is just a name field for the log records.</p>

<p>Every Bunyan logger has one or more <strong>streams</strong>, to which log records are written. Here we&#39;ve defined two: logging at DEBUG level and above is written to stdout, and logging at TRACE and above is appended to &#39;hello.log&#39;.</p>

<p>Bunyan has the concept of <strong>serializers</strong>: a registry of functions that know how to convert a JavaScript object for a certain log record field to a nice JSON representation for logging. For example, here we register the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">Logger.stdSerializers.req</code> function to convert HTTP Request objects (using the field name &quot;req&quot;) to JSON. More on serializers later.</p>

<h2 id="restify-server">Restify Server</h2>

<p>Restify 1.x and above has bunyan support baked in. You pass in your Bunyan logger like this:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>var server = restify.createServer({
  name: 'Hello API',
  log: log   // Pass our logger to restify.
});
</code></pre>

<p>Our simple API will have a single <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">GET /hello?name=NAME</code> endpoint:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>server.get({path: '/hello', name: 'SayHello'}, function(req, res, next) {
  var caller = req.params.name || 'caller';
  req.log.debug('caller is "%s"', caller);
  res.send({"hello": caller});
  return next();
});
</code></pre>

<p>If we run that, <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">node server.js</code>, and call the endpoint, we get the expected restify response:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>$ curl -iSs http://0.0.0.0:8080/hello?name=paul
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version
Access-Control-Expose-Headers: X-Api-Version, X-Request-Id, X-Response-Time
Server: Hello API
X-Request-Id: f6aaf942-c60d-4c72-8ddd-bada459db5e3
Access-Control-Allow-Methods: GET
Connection: close
Content-Length: 16
Content-MD5: Xmn3QcFXaIaKw9RPUARGBA==
Content-Type: application/json
Date: Tue, 07 Feb 2012 19:12:35 GMT
X-Response-Time: 4

{"hello":"paul"}
</code></pre>

<h2 id="setup-server-logging">Setup Server Logging</h2>

<p>Let&#39;s add two things to our server. First, we&#39;ll use the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">server.pre</code> to hook into restify&#39;s request handling before routing where we&#39;ll <strong>log the request</strong>.</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>server.pre(function (request, response, next) {
  request.log.info({req: request}, 'start');        // (1)
  return next();
});
</code></pre>

<p>This is the first time we&#39;ve seen this <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">log.info</code> style with an object as the first argument. Bunyan logging methods (<code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">log.trace</code>, <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">log.debug</code>, ...) all support an optional <strong>first object argument with extra log record fields</strong>:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>log.info(&lt;object&gt; fields, &lt;string&gt; msg, ...)
</code></pre>

<p>Here we pass in the restify Request object, <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">req</code>. The &quot;req&quot; serializer we registered above will come into play here, but bear with me.</p>

<p>Remember that we already had this debug log statement in our endpoint handler:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>req.log.debug('caller is "%s"', caller);            // (2)
</code></pre>

<p>Second, use the restify server <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">after</code> event to <strong>log the response</strong>:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>server.on('after', function (req, res, route) {
  req.log.info({res: res}, "finished");             // (3)
});
</code></pre>

<h2 id="log-output">Log Output</h2>

<p>Now lets see what log output we get when somebody hits our API&#39;s endpoint:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>$ curl -iSs http://0.0.0.0:8080/hello?name=paul
HTTP/1.1 200 OK
...
X-Request-Id: 9496dfdd-4ec7-4b59-aae7-3fed57aed5ba
...

{"hello":"paul"}
</code></pre>

<p>Here is the server log:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>[trentm@banana:~/tm/hello-json-logging]$ node server.js
... intro "listening at" log message elided ...
{"name":"helloapi","hostname":"banana.local","pid":40341,"level":30,"req":{"method":"GET","url":"/hello?name=paul","headers":{"user-agent":"curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8r zlib/1.2.3","host":"0.0.0.0:8080","accept":"*/*"},"remoteAddress":"127.0.0.1","remotePort":59831},"msg":"start","time":"2012-03-28T17:37:29.506Z","v":0}
{"name":"helloapi","hostname":"banana.local","pid":40341,"route":"SayHello","req_id":"9496dfdd-4ec7-4b59-aae7-3fed57aed5ba","level":20,"msg":"caller is \"paul\"","time":"2012-03-28T17:37:29.507Z","v":0}
{"name":"helloapi","hostname":"banana.local","pid":40341,"route":"SayHello","req_id":"9496dfdd-4ec7-4b59-aae7-3fed57aed5ba","level":30,"res":{"statusCode":200,"headers":{"access-control-allow-origin":"*","access-control-allow-headers":"Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version","access-control-expose-headers":"X-Api-Version, X-Request-Id, X-Response-Time","server":"Hello API","x-request-id":"9496dfdd-4ec7-4b59-aae7-3fed57aed5ba","access-control-allow-methods":"GET","connection":"close","content-length":16,"content-md5":"Xmn3QcFXaIaKw9RPUARGBA==","content-type":"application/json","date":"Wed, 28 Mar 2012 17:37:29 GMT","x-response-time":3}},"msg":"finished","time":"2012-03-28T17:37:29.510Z","v":0}
</code></pre>

<p>Lets look at each in turn to see what is interesting -- pretty-printed with <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">node server.js | ./node_modules/.bin/bunyan -j</code>:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>{                                                   // (1)
  "name": "helloapi",
  "hostname": "banana.local",
  "pid": 40442,
  "level": 30,
  "req": {
    "method": "GET",
    "url": "/hello?name=paul",
    "headers": {
      "user-agent": "curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8r zlib/1.2.3",
      "host": "0.0.0.0:8080",
      "accept": "*/*"
    },
    "remoteAddress": "127.0.0.1",
    "remotePort": 59834
  },
  "msg": "start",
  "time": "2012-03-28T17:39:44.880Z",
  "v": 0
}
</code></pre>

<p>Here we logged the incoming request with <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">request.log.info({req: request}, &#39;start&#39;)</code>. The use of the &quot;req&quot; field triggers the <a href="https://github.com/trentm/node-bunyan/blob/master/lib/bunyan.js#L857-870">&quot;req&quot; serializer</a> <a href="https://github.com/trentm/hello-json-logging/blob/master/server.js#L24">registered at Logger creation</a>.</p>

<p>Next the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">req.log.debug</code> in our handler:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>{                                                   // (2)
  "name": "helloapi",
  "hostname": "banana.local",
  "pid": 40442,
  "route": "SayHello",
  "req_id": "9496dfdd-4ec7-4b59-aae7-3fed57aed5ba",
  "level": 20,
  "msg": "caller is \"paul\"",
  "time": "2012-03-28T17:39:44.883Z",
  "v": 0
}
</code></pre>

<p>and the log of response in the &quot;after&quot; event:</p>

<pre style="overflow:auto;color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:5px;"><code>{                                                   // (3)
  "name": "helloapi",
  "hostname": "banana.local",
  "pid": 40442,
  "route": "SayHello",
  "req_id": "9496dfdd-4ec7-4b59-aae7-3fed57aed5ba",
  "level": 30,
  "res": {
    "statusCode": 200,
    "headers": {
      "access-control-allow-origin": "*",
      "access-control-allow-headers": "Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version",
      "access-control-expose-headers": "X-Api-Version, X-Request-Id, X-Response-Time",
      "server": "Hello API",
      "x-request-id": "9496dfdd-4ec7-4b59-aae7-3fed57aed5ba",
      "access-control-allow-methods": "GET",
      "connection": "close",
      "content-length": 16,
      "content-md5": "Xmn3QcFXaIaKw9RPUARGBA==",
      "content-type": "application/json",
      "date": "Wed, 28 Mar 2012 17:39:44 GMT",
      "x-response-time": 5
    }
  },
  "msg": "finished",
  "time": "2012-03-28T17:39:44.886Z",
  "v": 0
}
</code></pre>

<p>Two useful details of note here:</p>

<ol>
<li><p>The last two log messages include <strong>a &quot;req_id&quot; field</strong> (added to the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">req.log</code> logger by restify). Note that this is the same UUID as the &quot;X-Request-Id&quot; header in the <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">curl</code> response. This means that if you use <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">req.log</code> for logging in your API handlers you will get an easy way to collate all logging for particular requests.</p>

<p>If your&#39;s is an SOA system with many services, a best practice is to carry that X-Request-Id/req_id through your system to enable collating handling of a single top-level request.</p></li>
<li><p>The last two log messages include <strong>a &quot;route&quot; field</strong>. This tells you to which handler restify routed the request. While possibly useful for debugging, this can be very helpful for log-based monitoring of endpoints on a server.</p></li>
</ol>

<p>Recall that we also setup all logging to go the &quot;hello.log&quot; file. This was set at the TRACE level. Restify will log more detail of its operation at the trace level. See <a href="https://gist.github.com/1761772">my &quot;hello.log&quot;</a> for an example. The <code style="color:#999;background-color:#2f2f2f;border:1px solid #484848;padding:.2em .4em;">bunyan</code> tool does a decent job of <a href="https://gist.github.com/1761772#file_2.+cat+hello.log+pipe+bunyan">nicely formatting</a> multiline messages and &quot;req&quot;/&quot;res&quot; keys (with color, not shown in the gist).</p>

<p><em>This</em> is logging you can use effectively.</p>

<h1 style="margin:48px 0 24px;" id="other-tools">Other Tools</h1>

<p>Bunyan is just one of many options for logging in node.js-land. Others (that I know of) supporting JSON logging are <a href="https://github.com/flatiron/winston#readme">winston</a> and <a href="https://github.com/pquerna/node-logmagic/">logmagic</a>. Paul Querna has <a href="http://journal.paul.querna.org/articles/2011/12/26/log-for-machines-in-json/">an excellent post on using JSON for logging</a>, which shows logmagic usage and also touches on topics like the GELF logging format, log transporting, indexing and searching.</p>

<h1 style="margin:48px 0 24px;" id="final-thoughts">Final Thoughts</h1>

<p>Parsing challenges won&#39;t ever completely go away, but it can for your logs if you use JSON. Collating log records across logs from multiple nodes is facilitated by a common &quot;time&quot; field. Correlating logging across multiple services is enabled by carrying a common &quot;req_id&quot; (or equivalent) through all such logs.</p>

<p>Separate log files for a single service is an anti-pattern. The typical Apache example of separate access and error logs is legacy, not an example to follow. A JSON log provides the structure necessary for tooling to easily filter for log records of a particular type.</p>

<p>JSON logs bring possibilities. Feeding to tools like Splunk becomes easy. Ad hoc fields allow for a lightly spec&#39;d comm channel from apps to other services: records with a &quot;metric&quot; could feed to <a href="http://codeascraft.etsy.com/2011/02/15/measure-anything-measure-everything/">statsd</a>, records with a &quot;loggly: true&quot; could feed to loggly.com.</p>

<p>Here I&#39;ve described a very simple example of restify and bunyan usage for node.js-based API services with easy JSON logging. Restify provides a powerful framework for robust API services. Bunyan provides a light API for nice JSON logging and the beginnings of tooling to help consume Bunyan JSON logs.</p>

<p><strong>Update (29-Mar-2012):</strong> Fix styles somewhat for RSS readers.</p>
]]></content:encoded>
    </item>
    
</channel>
</rss>
