Class: FormatParser::Measurometer

Inherits:
Object
  • Object
show all
Defined in:
lib/measurometer.rb

Class Method Summary collapse

Class Method Details

.add_distribution_value(value_path, value) ⇒ Object

Adds a distribution value (sample) under a given path

Parameters:

  • value_path (String)

    under which path to push the metric

  • value (Numeric)

    distribution value

Returns:

  • nil



57
58
59
60
# File 'lib/measurometer.rb', line 57

def add_distribution_value(value_path, value)
  (@drivers || []).each { |d| d.add_distribution_value(value_path, value) }
  nil
end

.driversObject

Permits adding instrumentation drivers. Measurometer is 1-1 API compatible with Appsignal, which we use a lot. So to magically obtain all Appsignal instrumentation, add the Appsignal module as a driver.

Measurometer.drivers << Appsignal

A driver must be reentrant and thread-safe - it should be possible to have multiple ‘instrument` calls open from different threads at the same time. The driver must support the same interface as the Measurometer class itself, minus the `drivers` and `instrument_instance_method` methods.

Returns:

  • Array



17
18
19
20
# File 'lib/measurometer.rb', line 17

def drivers
  @drivers ||= []
  @drivers
end

.increment_counter(counter_path, by) ⇒ Object

Increment a named counter under a given path

Parameters:

  • counter_path (String)

    under which path to push the metric

  • by (Integer)

    the counter increment to apply

Returns:

  • nil



67
68
69
70
# File 'lib/measurometer.rb', line 67

def increment_counter(counter_path, by)
  (@drivers || []).each { |d| d.increment_counter(counter_path, by) }
  nil
end

.instrument(block_name, &blk) ⇒ Object

Runs a given block within a cascade of ‘instrument` blocks of all the added drivers.

Measurometer.instrument('do_foo') { compute! }

unfolds to

Appsignal.instrument('do_foo') do
  Statsd.timing('do_foo') do
    compute!
  end
end

A driver must be reentrant and thread-safe - it should be possible to have multiple ‘instrument` calls open from different threads at the same time. The driver must support the same interface as the Measurometer class itself, minus the `drivers` and `instrument_instance_method` methods.

Parameters:

  • block_name (String)

    under which path to push the metric

  • blk (#call)

    the block to instrument

Returns:

  • (Object)

    the return value of &blk



43
44
45
46
47
48
49
50
# File 'lib/measurometer.rb', line 43

def instrument(block_name, &blk)
  return yield unless @drivers && @drivers.any? # The block wrapping business is not free
  @drivers.inject(blk) { |outer_block, driver|
    -> {
      driver.instrument(block_name, &outer_block)
    }
  }.call
end

.instrument_instance_method(target_class, instance_method_name_to_instrument, path_prefix) ⇒ Object

Wrap an anonymous module around an instance method in the given class to have it instrumented automatically. The name of the measurement will be interpolated as:

"#{prefix}.#{rightmost_class_constant_name}.#{instance_method_name}"

Parameters:

  • target_class (Class)

    the class to instrument

  • instance_method_name_to_instrument (Symbol)

    the method name to instrument

  • path_prefix (String)

    under which path to push the instrumented metric

Returns:

  • void



81
82
83
84
85
86
87
88
89
90
# File 'lib/measurometer.rb', line 81

def instrument_instance_method(target_class, instance_method_name_to_instrument, path_prefix)
  short_class_name = target_class.to_s.split('::').last
  instrumentation_name = [path_prefix, short_class_name, instance_method_name_to_instrument].join('.')
  instrumenter_module = Module.new do
    define_method(instance_method_name_to_instrument) do |*any|
      ::FormatParser::Measurometer.instrument(instrumentation_name) { super(*any) }
    end
  end
  target_class.prepend(instrumenter_module)
end