module Etalon

Etalon is a simple tool to instrument Ruby code and output basic metrics to a logger or store them in a hash.

Constants

VERSION

Public Class Methods

activate() click to toggle source

Activates Etalon.

@return [Boolean] Etalon's current activation status

# File lib/etalon.rb, line 93
def activate
  !!ENV["ETALON_ACTIVE"] = "true"
end
active?() click to toggle source

@return [Boolean] whether Etalon is active and recording metrics.

# File lib/etalon.rb, line 10
def active?
  # rubocop:disable Style/DoubleNegation
  !!ENV["ETALON_ACTIVE"]
  # rubocop:enable Style/DoubleNegation
end
deactivate() click to toggle source

Deactivates Etalon.

@return [Boolean] Etalon's current activation status

# File lib/etalon.rb, line 101
def deactivate
  !!ENV["ETALON_ACTIVE"] = nil
end
print_timings() click to toggle source

Uses either Rails.logger or a Syslog::Logger instance to print out iteration count, minimum, maximum, average and standard deviation timings for each individual call instrumented by time.

@return [Hash] all stored metrics indexed by identifier

reset_timings() click to toggle source

Resets Etalon's internal storage to remove all stored timings.

@return [type] [description]

# File lib/etalon.rb, line 85
def reset_timings
  @instrument_store = nil
end
time(identifier) { || ... } click to toggle source

Runs timing metrics on the supplied block of code and stores those metrics for later logging or analysis using the supplied @identifier.

@param identifier [String] A unique identifier used to store calls to

the supplied block and report them later.

@return the supplied block's return value

# File lib/etalon.rb, line 23
def time(identifier)
  if active?
    unless block_given?
      raise "Please supply a block of code for Etalon to instrument"
    end

    start = Time.now

    return_value = yield

    duration = elapsed(start)

    key = key_from(identifier: identifier)
    store = instrument_store_for(key: key)

    store[:count] += 1
    store[:min] = duration if duration < store[:min]
    store[:max] = duration if duration > store[:max]
    store[:all] << duration

    return_value
  else
    yield
  end
end

Private Class Methods

elapsed(start) click to toggle source
# File lib/etalon.rb, line 124
def elapsed(start)
  ((Time.now - start) * 1000).floor
end
instrument_store() click to toggle source
# File lib/etalon.rb, line 107
def instrument_store
  @instrument_store ||= {}
end
instrument_store_for(key:) click to toggle source
# File lib/etalon.rb, line 111
def instrument_store_for(key:)
  instrument_store[key] ||= {
    count: 0,
    min: Float::INFINITY,
    max: 0,
    all: [],
  }
end
key_from(identifier:) click to toggle source
# File lib/etalon.rb, line 120
def key_from(identifier:)
  parameterize(identifier, separator: "_").to_sym
end
logger() click to toggle source
# File lib/etalon.rb, line 152
def logger
  @logger ||= begin
    if defined?(Rails.logger)
      Rails.logger
    else
      require("syslog/logger")
      Syslog::Logger.new
    end
  end
end
mean(samples) click to toggle source
# File lib/etalon.rb, line 128
def mean(samples)
  (samples.sum / samples.length.to_f)
end
parameterize(*args, **kwargs, &block) click to toggle source
# File lib/etalon.rb, line 163
def parameterize(*args, **kwargs, &block)
  ActiveSupport::Inflector.parameterize(*args, **kwargs, &block)
end
square(number) click to toggle source
# File lib/etalon.rb, line 132
def square(number)
  number ** 2
end
standard_deviation(samples) click to toggle source
# File lib/etalon.rb, line 146
def standard_deviation(samples)
  return 0 if samples.length < 2

  Math.sqrt(variance(samples))
end
variance(samples) click to toggle source
# File lib/etalon.rb, line 136
def variance(samples)
  return 0 if samples.length < 2

  sum = samples.inject(0) do |store, value|
    store + square(value - mean(samples))
  end

  sum.fdiv((samples.length - 1).to_f)
end