The Cost of Logging
At NearForm, we like to scratch our own itch, and we build tools based on the needs of our customers and our own needs as consultants. When David Mark Clements and myself were in London conducting a performance training and consulting engagement with Net-A-Porter, we noticed that the routes which were logging more were the slowest ones. Moreover, disabling logging allowed far greater performance.
We started a quest to assess the cost of logging.
As a format, JSON is easy to process, and at nearForm we favour it as a logging format, so fast JSON logging had to be the goal.
As in any performance consultancy, we establish a baseline considering the simplest express application (we used node v4 throughout this post):
In order to measure this, we will use autocannon, an HTTP/1.1 benchmarking tool inspired by wrk and built in Node.js:
Let’s see what happens when we add logging (in all the following example, we will be redirecting the output from stdout to /dev/null
):
We would expect this to have similar throughput to the first one. However we got some surprising results:
Running a server using Winston (version 2) for logging will slow you down by at least 50%.
As part of our consultancy, Dave and myself were asked for a fast alternative, and there wasn’t one. Therefore we set ourselves to the task of writing the fastest possible Node.js logger we could manage. We wanted to build something that could easily replace Winston, Bunyan (or even Bole).
Introducing Pino
Our logger is Pino, named after pine in Italian, because there is a pine in front of my house. Bunyan was a giant lumberjack, and Pino is (99%) API-compliant with Bunyan and Bole.
Pino is the fastest logger for Node.js (full benchmarks found here and here). While you can use Pino directly, you will likely use it with a Web framework, such as express or hapi.
Let’s consider the following example using express-pino-logger:
We can run the same benchmark as before:
Using express-pino-logger
increase the throughput of express-winston
by almost 40%.
Anatomy of Pino
Pino is a fast logger built on several principles:
1) It has the fewest possible features; there are no transports, it just logs to a binary stream (a file or stdout), and no file rotation.
2) It only logs in JSON.
3) It needs to be as fast as possible.
4) It should support child loggers, to allow transactions to have their own metadata.
5) Drop-in compatible API with bunyan, bole, winston wherever possible.
Instantiating Pino is easy:
The Pino family
Pino has a set of companion tools, each of which have been meticulously implemented to have a minimal impact on performance:
express-pino-logger: express integration
koa-pino-logger: koa integration
restify-pino-logger: restify integration
pino-http: barebone logger for node http module, basis of express, koa and restify integrations
pino-socket: forwards pino logs over a TCP or UDP socket
Conclusion
Pino is the fastest logger in town (see the benchmarks), and it uses a full set of performance optimizations to achieve this goal, from avoiding JSON.stringify
, to rolling our own printf style formatting module and flattening strings. These techniques reduce the overhead of logging by 40%. In extreme mode, we also delay flushing to disk, to reduce it even more, by 60%. We have adopted Pino in some projects, and it has increased the throughput (req/s) of those applications by a factor of 20-100%. Stay tuned for more blog posts on the techniques that Pino uses to be so fast, as each of those has its own story.
Insight, imagination and expertly engineered solutions to accelerate and sustain progress.
Contact