diff --git a/README.markdown b/README.markdown
index 27daab7..570537e 100644
--- a/README.markdown
+++ b/README.markdown
@@ -16,4 +16,104 @@ How To Use
PM> Install-Package Metrics
-Work in progress, nothing to see here.
\ No newline at end of file
+**Second** ...
+
+Metrics comes with five types of metrics:
+
+* **Gauges** are instantaneous readings of values (e.g., a queue depth).
+* **Counters** are 64-bit integers which can be incremented or decremented.
+* **Meters** are increment-only counters which keep track of the rate of events.
+ They provide mean rates, plus exponentially-weighted moving averages which
+ use the same formula that the UNIX 1-, 5-, and 15-minute load averages use.
+* **Histograms** capture distribution measurements about a metric: the count,
+ maximum, minimum, mean, standard deviation, median, 75th percentile, 95th
+ percentile, 98th percentile, 99th percentile, and 99.9th percentile of the
+ recorded values. (They do so using a method called reservoir sampling which
+ allows them to efficiently keep a small, statistically representative sample
+ of all the measurements.)
+* **Timers** record the duration as well as the rate of events. In addition to
+ the rate information that meters provide, timers also provide the same metrics
+ as histograms about the recorded durations. (The samples that timers keep in
+ order to calculate percentiles and such are biased towards more recent data,
+ since you probably care more about how your application is doing *now* as
+ opposed to how it's done historically.)
+
+Metrics also has support for health checks:
+
+ HealthChecks.Register("database", () =>
+ {
+ if (Database.IsConnected)
+ {
+ return HealthCheck.Healthy;
+ }
+ else
+ {
+ return HealthCheck.Unhealthy("Not connected to database");
+ }
+ });
+
+**Third**, start collecting your metrics.
+
+If you're simply running a benchmark, you can print registered metrics to
+standard error every 10s like this:
+
+ // Print to Console.Error every 10 seconds
+ Metrics.EnableConsoleReporting(10, TimeUnit.Seconds)
+
+If you're writing a ASP.NET MVC-based web service, you can reference `Metrics.AspNetMvc` in
+your web application project and register default routes:
+
+ using metrics;
+
+ public class MvcApplication : HttpApplication
+ {
+ // ...
+
+ protected void Application_Start()
+ {
+ AspNetMvc.Metrics.RegisterRoutes();
+
+ // ...
+ }
+
+ // ...
+ }
+
+The default routes will respond to the following URIs:
+
+* `/metrics`: A JSON object of all registered metrics and a host of CLR metrics.
+* `/ping`: A simple `text/plain` "pong" for load-balancers.
+* `/healthcheck`: Runs through all registered `HealthCheck` instances and reports the results. Returns a `200 OK` if all succeeded, or a `500 Internal Server Error` if any failed.
+* `/threads`: A `text/plain` dump of all threads and their stack traces.
+
+The URIs of these resources can be configured by setting properties prior to registering routes.
+You may also choose to protect these URIs with HTTP Basic authentication:
+
+ using metrics;
+
+ public class MvcApplication : HttpApplication
+ {
+ // ...
+
+ protected void Application_Start()
+ {
+ AspNetMvc.Metrics.HealthCheckPath = "my-healthcheck-uri";
+ AspNetMvc.Metrics.PingPath = "my-ping-uri";
+ AspNetMvc.Metrics.MetricsPath = "my-metrics-uri";
+ AspNetMvc.Metrics.ThreadsPath = "my-threads-uri";
+
+ AspNetMvc.Metrics.RegisterRoutes("username", "password");
+
+ // ...
+ }
+
+ // ...
+ }
+
+License
+-------
+The original Metrics project is Copyright (c) 2010-2011 Coda Hale, Yammer.com
+
+This idiomatic port of Metrics to C# and .NET is Copyright (c) 2011 Daniel Crenna, Wildbit.com
+
+Both works are published under The MIT License, see LICENSE
\ No newline at end of file
diff --git a/metrics.Tests/Core/CLRProfilerTests.cs b/metrics.Tests/Core/CLRProfilerTests.cs
new file mode 100644
index 0000000..0c2c23e
--- /dev/null
+++ b/metrics.Tests/Core/CLRProfilerTests.cs
@@ -0,0 +1,26 @@
+using System.Diagnostics;
+using metrics.Core;
+using NUnit.Framework;
+
+namespace metrics.Tests.Core
+{
+ [TestFixture]
+ public class CLRProfilerTests
+ {
+ [Test]
+ public void Can_get_heap_usage()
+ {
+ var heap = CLRProfiler.HeapUsage;
+ Assert.IsNotNull(heap);
+ Trace.WriteLine(heap);
+ }
+
+ [Test]
+ public void Can_get_uptime()
+ {
+ var heap = CLRProfiler.Uptime;
+ Assert.IsNotNull(heap);
+ Trace.WriteLine(heap);
+ }
+ }
+}
diff --git a/metrics.Tests/metrics.Tests.csproj b/metrics.Tests/metrics.Tests.csproj
index 0278c4f..adf72cb 100644
--- a/metrics.Tests/metrics.Tests.csproj
+++ b/metrics.Tests/metrics.Tests.csproj
@@ -55,6 +55,7 @@
+
diff --git a/metrics/Core/ClrProfiler.cs b/metrics/Core/ClrProfiler.cs
index ff22fce..ffe5306 100644
--- a/metrics/Core/ClrProfiler.cs
+++ b/metrics/Core/ClrProfiler.cs
@@ -1,12 +1,71 @@
using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
namespace metrics.Core
{
public static class CLRProfiler
{
+ private const string CategoryMemory = ".NET CLR Memory";
+ private static readonly Process _process;
+ private static readonly IDictionary> _counters;
+
+ static CLRProfiler()
+ {
+ _process = Process.GetCurrentProcess();
+ _counters = new Dictionary>
+ {
+ {_process, new Dictionary()}
+ };
+ }
+
public static string DumpThreads()
{
- throw new NotImplementedException();
+ return "Not implemented; how about a fork?";
+ }
+
+ ///
+ /// Returns the number of seconds the CLR process has been running
+ ///
+ public static long Uptime
+ {
+ get { return Convert.ToInt64(_process.TotalProcessorTime.TotalSeconds); }
+ }
+
+ ///
+ /// Returns the percentage of the CLR's heap which is being used
+ ///
+ public static double HeapUsage
+ {
+ get
+ {
+ var counter = GetOrInstallCounter("HeapUsage", CategoryMemory);
+ var used = WaitForNextRawValue(counter);
+
+ var available = _process.PrivateMemorySize64;
+ var usage = (double)used / available;
+ return usage;
+ }
+ }
+
+ private static long WaitForNextRawValue(PerformanceCounter counter)
+ {
+ long used;
+ while((used = counter.NextSample().RawValue) == 0)
+ {
+ Thread.Sleep(10);
+ }
+ return used;
+ }
+
+ private static PerformanceCounter GetOrInstallCounter(string property, string category)
+ {
+ if (!_counters[_process].ContainsKey(property))
+ {
+ _counters[_process].Add(property, new PerformanceCounter(category, "# bytes in all heaps", _process.ProcessName));
+ }
+ return _counters[_process][property];
}
}
-}
+}
\ No newline at end of file
diff --git a/metrics/Core/GaugeMetric.cs b/metrics/Core/GaugeMetric.cs
index 57e8424..4416f90 100644
--- a/metrics/Core/GaugeMetric.cs
+++ b/metrics/Core/GaugeMetric.cs
@@ -7,7 +7,7 @@ namespace metrics.Core
/// A gauge metric is an instantaneous reading of a partiular value. To
/// instrument a queue's depth, for example:
///
- ///
+ ///
/// var queue = new Queue();
/// var gauge = new GaugeMetric(() => queue.Count);
///
diff --git a/metrics/Core/HealthCheck.cs b/metrics/Core/HealthCheck.cs
index 65cfdc2..54b6239 100644
--- a/metrics/Core/HealthCheck.cs
+++ b/metrics/Core/HealthCheck.cs
@@ -7,6 +7,10 @@ namespace metrics
///
public class HealthCheck
{
+ public static Result Healthy { get { return Result.Healthy; } }
+ public static Result Unhealthy(string message) { return Result.Unhealthy(message); }
+ public static Result Unhealthy(Exception error) { return Result.Unhealthy(error); }
+
private readonly Func _check;
public String Name { get; private set; }
diff --git a/metrics/Serialization/MetricsConverter.cs b/metrics/Serialization/MetricsConverter.cs
index 961dda3..b99251e 100644
--- a/metrics/Serialization/MetricsConverter.cs
+++ b/metrics/Serialization/MetricsConverter.cs
@@ -6,17 +6,17 @@
namespace metrics.Serialization
{
- internal class MetricItem
- {
- public string Name { get; set; }
- public IMetric Metric { get; set; }
- }
-
///
/// Properly serializes a metrics hash
///
internal class MetricsConverter : JsonConverter
{
+ internal class MetricItem
+ {
+ public string Name { get; set; }
+ public IMetric Metric { get; set; }
+ }
+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (!(value is IDictionary))
diff --git a/metrics/metrics.csproj b/metrics/metrics.csproj
index e43f02b..83f2740 100644
--- a/metrics/metrics.csproj
+++ b/metrics/metrics.csproj
@@ -43,7 +43,7 @@
-
+