Log Reporting library
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


This library provides an easy interface for writing metrics to your logs or another stream. It includes a writer to write l2met 2.0 formatted log lines ultimately bound for Librato's l2met service. If your application is running on AppHarbor this allows you to easily log metrics that can be send to Librato using a log drain.

This library is a port of Librato's own log-reporter library intended for use with .NET applications.

Quick Start

Install MetricReporter in your application using NuGet:

Install-Package MetricReporter

Initialize a MetricReporter while injecting required dependencies:

var metricWriter = new MetricWriter(Console.Out);
var reporter = new MetricReporter(metricWriter);

You can now start writing metrics like so:

# Increment counter metric by one

# Benchmark time to complete a task
reporter.Measure("search.querytime", () =>
        //Do work

# Track averages across processes/thread/requests etc
reporter.Measure("payload.size", 3443);



You can write to any TextWriter by injecting it into the MetricWriter class. For instance, use Console.Out for writing to the standard output. Use the included TraceTextWriter to write to your trace output like so:

var textWriter = new TraceTextWriter();
var metricWriter = new MetricWriter(textWriter);

NOTE: Using the TraceTextWriter is recommended when you use this library on AppHarbor - just make sure tracing is enabled.

Use a StreamWriter to write metrics to a file stream:

var stream = new FileStream("c:\\foobar.txt", FileMode.Append);
var textWriter = new StreamWriter(stream);

Silence output by initializing the StreamWriter with Stream.Null:

var textWriter = new StreamWriter(Stream.Null);


A default metric source can optionally be specified when initializing a MetricReporter:

var reporter = new MetricReporter(metricWriter, defaultSource: "web.1");

If no default source is specified your metric will be submitted without a source, unless specified when calling the helper methods Increment and Measure. You can also override the default source:

reporter.Increment("requests.total", source: "foo.1");
reporter.Measure("request.time", 433, source: "foo.1");

NOTE: On AppHarbor you can access the worker name with the appharbor.worker.name appSettings key.


You can write your metrics with prefixes prepended to all metric names. A PrefixingMetricWriter taking an IMetricWriter is available for this:

var metricWriter = new MetricWriter(Console.Out);
var prefixingMetricWriter = new PrefixingMetricWriter(metricWriter);
var reporter = new MetricReporter(prefixingMetricWriter);

The MetricReporter#Group method will also prepended prefixes to your metric names using a similar approach. Using multiple nested prefixes is supported.

Custom Measurements

Tracking anything that interests you is easy. There are four helpers available in the MetricReporter class:


Use for tracking a running total of something across jobs or requests, examples:

# increment the 'jobs.completed' metric by one

# increment by five
reporter.Increment("items.purchased", incrementBy: 5);

# increment with a custom source
reporter.Increment("user.purchases", source: "web.1");

Other things you might track this way: user activity, requests of a certain type or to a certain route, total jobs queued or processed, emails sent or received


Use when you want to track an average value per-measurement period. Examples:

reporter.Measure("payload.size", 212);

# report from a custom source
reporter.Measure("jobs.by.user', source: job.Requestor.Id)

Measure (action)

Like the other Measure overload this is per-period, but uses the time it takes to execute the action delegate as the measurement value:

The block form auto-submits the time it took for its contents to execute as the measurement value:

reporter.Measure("twitter.lookup.time", () =>


The group helper makes managing nested metrics easier. So this:

reporter.Measure("memcached.gets", 20);
reporter.Measure("memcached.sets", 2);
reporter.Measure("memcached.bytes.read", 342152);
reporter.Measure("memcached.bytes.written", 2183);

Can be written as:

reporter.Group("memcached", x =>
        x.Measure("gets", 20);
        x.Measure("set", 2);

        x.Group("bytes", y =>
                y.Measure("read", 342152);
                y.Measure("written", 2183);


  • Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
  • Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
  • Fork the project and submit a pull request from a feature or bugfix branch.
  • Please include tests. This is important so we don't break your changes unintentionally in a future version.