README.md in harness-0.9.1 vs README.md in harness-1.0.0
- old
+ new
@@ -1,345 +1,130 @@
# Harness
-[][travis]
+[][travis]
[][gem]
-[][codeclimate]
-[][gemnasium]
+[][codeclimate]
+[][gemnasium]
[gem]: https://rubygems.org/gems/harness
-[travis]: http://travis-ci.org/twinturbo/harness
-[gemnasium]: https://gemnasium.com/twinturbo/harness
-[codeclimate]: https://codeclimate.com/github/twinturbo/harness
-[coveralls]: https://coveralls.io/r/twinturbo/harness
+[travis]: http://travis-ci.org/ahawkins/harness
+[gemnasium]: https://gemnasium.com/ahawkins/harness
+[codeclimate]: https://codeclimate.com/github/ahawkins/harness
+[coveralls]: https://coveralls.io/r/ahawkins/harness
-Harness connects measurements coming from `ActiveSupport::Notifications`
-to external metric tracking services. Counters are stored locally with
-redis before being sent to the service.
+Harness provides you with high level application metrics. It collects
+metrics from various sources and forwards them to the collector. You
+can use any collector that implements the `Statsd` interface. Harness
+also collects metrics from `ActiveSupport::Notifications` and forwards
+them to the collector.
-Currently Supported Services:
+Harness only assumes one thing: the collector can do proper metric
+aggregation and statistics. Example: using statsd will calculate the
+90th percentile and averages.
-* Librato
-* Statsd (thanks to fluxlux)
-* Stathat
+Harness is designed for very high traffic applications. Instrumenting
+code should cost as close to 0 as possible. All metrics are processed
+in a separate thread. The main thread will never do any more work than
+needed. Using a thread allows you to instrument 10,000's metrics per
+second without worrying.
-Current Features:
+Harness's has two main goals:
-* Track counters over time (# of registered users)
-* Read time specific values (# time to cache something)
-* Build meters on top of counters (# requests per second)
-* Sidekiq integration
-* Resque integration
-* Rails integration
-* Capture and log all measurements coming out of Rails
+1. Make instrumentation fast and cheap
+2. Provide high level system metrics (think like a car dashboard for
+ your app).
-**Crash Course**
+Solving #1 is easy: include `Harness::Instrumented` in your class. #2
+is slightly more complicated, but Harness automatically collects all
+the metrics for you.
-```ruby
-class ComplicatedClass
- def hard_work
- # Automatically track how long each of these calls takes so they can
- # tracked and compared over time.
- ActiveSupport::Notifications.instrument "hard_work", :gauge => true do
- # do hard_work
- end
- end
+## Application Independent Metrics
- def register_user
- # Automatically track the total # of registered users you have.
- # As well, as be able to take measurements of users created in a
- # specific interval
- ActiveSupport::Notifications.instrument "register_user", :counter => true do
- # register_user
- end
- end
-end
-```
+Most ruby applications are using a similar stack: rack, a cache, a key
+value store, job processor, and persistent data store. Visiblity is
+the most important thing when it comes to application performance. You
+can only improve something when you can measure it. Harness takes care
+of the measuring. Harness integrates with common components in the
+ruby eosystem and gives you the data you need. You should put this
+data on your dashboard and pay attention to it.
-## Installation
+These metrics should be enough to give you a high level overview on
+how all the different layers in your stack are performing. **Harness
+is not for drilling down into a specific request or peice of code.**
+You should use the ruby-prof for that. In short, Harness is not a
+replacement for new-relic. They serve different purposes. However, you
+could deduce all the information newrelic provides from
+instrumentation data.
-Add this line to your application's Gemfile:
+## Supported Libraries & Projects
-```ruby
-gem 'harness'
-```
+Harness is an interface. All integrations use the interface.
+Instrumentation for popular libraries are provided as gems. This
+allows anyone to release instrumentations. Individual gems can be
+maintained and released separate of this gem. Here is the definite
+list.
-And then execute:
+* [harness-actioncontroller](http://github.com/ahawkins/harness-actioncontroller)
+* [harness-actionmailer](http://github.com/ahawkins/harness-actionmailer)
+* [harness-actionview](http://github.com/ahawkins/harness-actionview)
+* [harness-activerecord](http://github.com/ahawkins/harness/activerecord)
+* [harness-active\_model\_serialzier](http://github.com/ahawkins/harness-active_model_serializers)
+* [harness-activesupport](http://github.com/ahawkins/harness-activesupport)
+* [harness-haproxy](http://github.com/ahawkins/harness-haproxy)
+* [harness-memcached](http://github.com/ahawkins/harness-memcached) - [dalli](http://github.com/merpahm/dalli) through harness-activesupport
+* [harness-moped](http://github.com/ahawkins/harness-moped) - (mongoid)
+* [harness-rack](http://github.com/ahawkins/harness-rack)
+* [harness-redis](http://github.com/ahawkins/harness-redis)
+* [harness-sequel](http://github.com/ahawkins/harness-sequel)
+* [harness-sidekiq](http://github.com/ahawkins/harness-sidekiq)
+* [harness-varnish](http://github.com/ahawkins/harness-varnish)
-```shell
-bundle
-```
+## Instrumenting
-Or install it yourself as:
+`Harness` provides the same interface as `statsd`. You can interact
+with `Harness` directly. This is not advised. You should `include` or
+`extend` `Harness::Instrumentation` in your class. Here are some
+examples.
-```shell
-gem install harness
-```
-
-## Usage
-
-In the metrics world there are two types of things: Gauges and Counters.
-Gauges are time sensitive and represent something at a specific point in
-time. Counters keep track of things and should be increasing. Counters
-can be reset back to zero. You can combine counters and/or gauges to
-correlate data about your application. Meters monitor counters. They
-allow you look at rates of counters (read: counters per second).
-
-Harness makes this process easily. Harness' primary goal it make it dead
-simple to start measuring different parts of your application.
-`ActiveSupport::Notifications` makes this very easy because it provides
-measurements and implements the observer pattern.
-
-## Tracking Things
-
-I guess you read the `ActiveSupport::Notifications`
-[documentation](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html)
-before going any further or this will seems like php to you. Harness
-hooks into your notifications and looks for `:gauge` or `:counter`
-options. If either is present, it will be sent to the external service.
-For example, you can track how long it's taking to do a specific thing:
-
```ruby
-class MyClass
- def important_method(stuff)
- ActiveSupport::Notifications.instrument "important_method.my_class", :gauge => true do
- do_important_stuff
- end
- end
-end
-```
+class UseCase
+ include Harness::Instrumentation
-You can do the same with a counter. Counter values are automatically
-stored in redis and incremented. This means you can simply pass
-`:counter => true` in instrumentations if you'd like to count it. You
-may also pass `:counter => 5` if you'd like to provide your own value.
-This value is stored in redis so the next time `:counter => true` will
-work correctly. You can reset all the counters back to zero by calling:
-`Harness.reset_counters!`.
+ def run!
+ increment 'foo'
+ increment 'foo', 5
-**NOTE**: You should use the bundled rake task to reset counters with
-a cron job. This will prevent unbounded growth of this metadata. You
-can call `rake harness:reset_counters` to do this. You should call
-this rake task at whatever your longest measurable interval is. Here's
-an example: You log gauges every 12 hours. You should reset the
-counters every 12 hours. This issue is discussed [here](https://github.com/twinturbo/harness/issues/15).
+ decrement 'foo'
+ decrement 'foo', 5
-```ruby
-class MyClass
- def important_method(stuff)
- ActiveSupport::Notifications.instrument "important_method.my_class", :counter => true do
- do_important_stuff
- end
- end
-end
-```
+ count 'foo', 1000
-The instruments name will be sent as the name (`important_method.my_class`)
-for that gauge or counter.
-
-Note that `ActiveSupport::Notifications.instrument` doesn't require
-a block. This can be useful when you are taking an instant measurement.
-
-```ruby
-class MyClass
- def important_method(stuff)
- ActiveSupport::Notifications.instrument "important_method.my_class", :counter => true
- end
-end
-```
-
-Harness will do all the extra work in sending these metrics to whatever
-service you're using.
-
-Once you the counters are you are instrumented, then you can meter them.
-Meters allow you take arbitrary readings of counter rates. The results
-return a gauge so they can be logged as well.
-
-```ruby
-# Define a counter
-class MyClass
- def important_method(stuff)
- ActiveSupport::Notifications.instrument "important_method.my_class", :counter => true do
- do_important_stuff
+ time 'foo' do
+ # do hard work
end
end
end
-
-# Now you can meter it
-meter = Harness::Meter.new('important_method.my_class')
-meter.per_second # returns a gauge
-meter.per_second.value # if you just want the number
-meter.per(1.hour).value # You can use your own interval
-meter.per_minute
-meter.per_hour
```
-## Customizing
+That's all there is to it!
-You can pass a hash to `:counter` or `:gauge` to initialize the
-measurement your own way.
+## Configuring
-If you pass a value attribute to a gauge, it will be the value
-sent instead of the duration of the block.
+Harness has two configuration options: the queue and collector.
+`Harness::AsyncQueue` is the default queue. This means all metrics are
+logged in a separate thread to never block the main thread. This makes
+harness more performant in high traffic scenarios.
+`Harness::NullCollector`. There is also a `Harness::SyncQueue`
+useful for testing (but really used in practice).
-```ruby
-class MyClass
- def important_method(stuff)
- ActiveSupport::Notifications.instrument "important_method.my_class",
- :gauge => { :id => 'custom-id', :name => "My Measurement",
- :value => my_current_val, :units => 'cogs' } do
- do_important_stuff
- end
- end
-end
```
-
-## One Off Gauges and Counters
-
-You can instantiate `Harness::Counter` and `Harness::Gauge` wherever you
-want. Events from `ActiveSupport` are just converted to these classes
-under the covers anyways. You can use these class if you want to take
-periodic measurements or tracking something that happens outside the
-application.
-
-```ruby
-gauge = Harness::Gauge.new
-gauge.id = "foo.bar"
-gauge.name = "Foo's Bar"
-gauge.time # defaults to Time.now
-gauge.value = readings_from_my_server
-gauge.units = 'bytes'
-gauge.log
-
-counter = Harness::Counter.new
-counter.id = "foo.bar"
-counter.name = "# of Foo bars"
-counter.time # defaults to Time.now
-counter.value = read_total_users_in_database
-counter.log
-
-### Both classes take an option hash
-
-gauge = Harness::Gauge.new :time => Time.now, :id => 'foo.bar'
-counter = Harness::Counter.new :time => Time.now, :id => 'foo.bar'
+Harness.collector = Statsd.new 'something.com'
+Harness.queue = Harness::AsyncQueue
```
-## Configuration
-
-### Librato
-
-```ruby
-require 'harness/adapters/librato_adapter'
-
-Harness.config.adapter = :librato
-
-Harness.config.librato.email = 'example@example.com'
-Harness.config.librato.token = 'your-api-key'
-
-```
-
-### StatsD
-
-Harness does **not** configure StatsD for you. It uses the StatsD class
-under the covers. If you've already configured that in your own way, great.
-If not, you can use the configuration proxy as described below. You
-must also add `statsd-instrument` to your `Gemfile`. This is a soft
-dependency that is not installed for you.
-
-```ruby
-require 'harness/adapters/statsd_adapter'
-
-Harness.config.adapter = :statsd
-
-# Harness.config.statsd is a proxy for the StatsD class
-Harness.config.statsd.host = 'localhost'
-Harness.config.statsd.port = '8080'
-Harness.config.statsd.default_sample_rate = 0.1
-Harness.config.statsd.logger = Rails.logger
-
-# You can assign your own StatsD implementation
-# by setting the "backend" attribute
-Harness.config.statsd.backend = CustomStatsD
-```
-
-### Stathat
-
-```ruby
-require 'harness/adapters/stathat_adapter'
-
-Harness.config.adapter = :stathat
-
-Harness.config.stathat.ezkey = 'example@example.com'
-```
-
-## Rails Integration
-
-Harness will automatically log metrics coming from `ActionPack`,
-`ActiveRecord`, and `ActionMailer`. `ActiveSupport` instrumentation is
-disabled by default. First require your adapter in an initializer
-Harness no longer requires adapters with external dependencies for
-you. Create a `config/initializers/harness.rb` and require your
-adapter in it:
-
-```ruby
-require 'harness/adapters/statsd_adapter'
-# other configuration
-```
-
-Also, custom integrations are disabled by default.
-You can turn on instrumentation for specific components like so:
-
-```ruby
-config.harness.instrument.action_controller = false
-config.harness.instrument.active_support = true
-config.harness.instrument.sidekiq = true
-config.harness.instrument.active_model_serializers = true
-```
-
-You can configure Harness from `application.rb`
-
-```ruby
-config.harness.adapter = :librato
-config.harness.librato.email = 'example@example.com'
-config.harness.librato.token = 'your-api-key'
-```
-
-Redis will be automatically configured if you `REDISTOGO_URL` or
-`REDIS_URL` environment variables at set. They are wrapped in a
-namespace so there will be no conflicts. If they are not present, the
-default values are used. You can customize this in an initializer:
-
-```ruby
-# config/initializers/harness.rb
-require 'erb'
-
-file = Rails.root.join 'config', 'resque.yml'
-config = YAML.load(ERB.new(File.read(Rails.root.join('config', 'redis.yml'))).result)
-
-Harness.redis = Redis::Namespace.new('harness', :redis => Redis.connect(:url => config[Rails.env]))
-```
-
-`rake harness:reset_counters` is also added.
-
-### Rails Environments
-
-Measurements are completely ignored in the test env. They are processed
-in development mode, but not sent to the external service. Everything is
-logged in production.
-
-### Background Processing
-
-Harness integrates automatically with Resque or Sidekiq. This is because
-reporting measurements can take time and add unnecessary overhead to the
-response time. If neither of these libraries are present, measurements
-**will be posted in realtime.** You can set your own queue by
-specifying a class like so:
-
-```ruby
-Harness.config.queue = MyCustomQueue
-```
-
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
+