Code Climate

Process Metrics

This project aims to collect metrics for processes.

It differs from other metric gems by measuring processes instead of code execution.

A process can begin in one point in time and finish in another thread, or even another server.

Features

  • Sub-process: Start a process, track each individual step and see the global metric. This is similar to how web browsers show you in the Network view how much time each asset takes to load. See where the holes are.
  • Unobtrusive: Failure in saving a metric will not break your code unless you use Metric.measure!, Metric#find! and Metric#finish!
  • Assyncronous: Persistence is made in parallel, so measurement itself will not affect the results.
  • Multiple data stores: ActiveRecord for now. Leela2 in the near future. Implement your own if you want/need.

Usage

Manual

Single process

ProcessMetrics.measure('name') do |metric|
  do_work
  metric.data = { key: 'value' }  # optional
end

Sub Process in the same block

ProcessMetrics.measure('name') do |metric|
  metric.measure('first sub process') do |sub_metric|
    do_work
    sub_metric.data = { key: 'value' } # optional
  end

  do_more_work

  metric.measure('second sub process') do |sub_metric|
    do_even_more_work
    sub_metric.data = { key: 'value' } # optional
  end
end

Sub Processes in different places

# in app/controller/my_controller.rb
metric = ProcessMetrics.new 'name' # metric objects have an uuid
save_metric(metric.uuid)
schedule_worker

# in lib/workers/my_worker.rb
ProcessMetrics.find(metric_uuid).measure('sub process') do |sub_metric|
  do_work
  submetric.data = { key: 'value' }  # optional
end

Automatic

Single process

class MyModel
  include ProcessMetrics::Timer
  measure :perform,
          name: -> { "metric name" } # Default would be "MyModel#perform"

  def perform
    do_some_work
  end
end

Sub processes

class MyWorker
  include ProcessMetrics::Timer
  measure :perform,
          parent_metric_uuid: -> { "2d931510-d99f-494a-8c67-87feb05e1594" }

  belongs_to :my_model

  def perform
    do_some_work
  end
end

Persistence

Data collected will be serialized into a json and persisted. You can put any data you like into the data field and it will be serialized as well.

{
    "metrics": [{
        "uuid": "bad85eb9-0713-4da7-8d36-07a8e4b00eab",
        "name": "virtual_machine_provisioning",
        "started_at": "2014-03-13T11:34:53-03:00",
        "finished_at": "2014-03-13T11:35:14-03:00",
        "data": {
            "customer_login": "anon",
            "provisioning_id": 6000123456,
            "object_type": "virtual_machine",
            "object_id": "cpro123456"
        },
        "links": {
            "metrics": [
                "2d931510-d99f-494a-8c67-87feb05e1594",
                "62936e70-1815-439b-bf89-8492855a7e6b"
            ]
        }
    }]
}

Configuration

One time, in a migration

ProcessMetrics::Persistence::ActiveRecord.table_name = 'onon' # optional
ProcessMetrics::Persistence::ActiveRecord.setup!

Then, in an initializer

ProcessMetrics.config.logger = Rails.logger
ProcessMetrics.persistence = Metric::Persistence::ActiveRecord # Default is Logger