Class: StatsD::Instrument::CompiledMetric

Inherits:
Object
  • Object
show all
Defined in:
lib/statsd/instrument/compiled_metric.rb

Overview

A compiled metric pre-builds the datagram template at definition time to minimize allocations during metric emission. This is particularly beneficial for high-frequency metrics with consistent tag patterns.

Example: class CheckoutMetric < StatsD::Instrument::CompiledMetric::Counter define( name: "checkout.completed", static_tags: { service: "web" }, tags: { shop_id: Integer, user_id: Integer } ) end

# Later, emit with minimal allocations: CheckoutMetric.increment(shop_id: 123, user_id: 456, value: 1)

Direct Known Subclasses

Counter, Distribution, Gauge

Defined Under Namespace

Classes: Counter, DatagramBlueprintBuilder, Distribution, Gauge, PrecompiledDatagram

Constant Summary collapse

DEFAULT_MAX_TAG_COMBINATION_CACHE_SIZE =

Default maximum number of unique tag combinations to cache before clearing the cache to prevent unbounded memory growth

5000

Class Method Summary collapse

Class Method Details

.allow_measuring_latencyBoolean

The value kwarg will be ignored and instead the execution time of the block in milliseconds will be used. The return value of the block will be passed through.



86
87
88
# File 'lib/statsd/instrument/compiled_metric.rb', line 86

def allow_measuring_latency
  false
end

.default_valueNumeric?

Returning nil makes value a required argument.

Raises:

  • (NotImplementedError)


79
80
81
# File 'lib/statsd/instrument/compiled_metric.rb', line 79

def default_value
  raise NotImplementedError, "Subclasses must implement #default_value"
end

.define(name:, static_tags: {}, tags: {}, no_prefix: false, sample_rate: nil, max_cache_size: DEFAULT_MAX_TAG_COMBINATION_CACHE_SIZE) ⇒ Class

Defines a new compiled metric class with the given configuration.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/statsd/instrument/compiled_metric.rb', line 35

def define(name:, static_tags: {}, tags: {}, no_prefix: false, sample_rate: nil, max_cache_size: DEFAULT_MAX_TAG_COMBINATION_CACHE_SIZE)
  client = StatsD.singleton_client

  # Build the datagram blueprint using the builder
  # The builder handles prefix, tags compilation, and blueprint construction
  datagram_blueprint = DatagramBlueprintBuilder.build(
    name: name,
    type: type,
    client_prefix: client.prefix,
    no_prefix: no_prefix,
    default_tags: client.default_tags,
    static_tags: static_tags,
    dynamic_tags: tags,
    sample_rate: sample_rate || client.default_sample_rate,
  )

  # Create a new class for this specific metric
  # Using classes instead of instances for better YJIT optimization
  metric_class = tap do
    @name = DatagramBlueprintBuilder.normalize_name(name)
    @datagram_blueprint = datagram_blueprint
    @tag_combination_cache = {}
    @max_cache_size = max_cache_size
    @singleton_client = client
    @sample_rate = sample_rate || client.default_sample_rate

    define_metric_method(tags)
  end

  metric_class
end

.define_metric_method(tags) ⇒ Object

Defines the metric emission method - must be implemented by subclasses



92
93
94
95
96
97
98
# File 'lib/statsd/instrument/compiled_metric.rb', line 92

def define_metric_method(tags)
  if tags.any?
    define_dynamic_method(tags)
  else
    define_static_method
  end
end

.method_nameSymbol

Returns The method name to define (e.g., :increment).

Raises:

  • (NotImplementedError)


73
74
75
# File 'lib/statsd/instrument/compiled_metric.rb', line 73

def method_name
  raise NotImplementedError, "Subclasses must implement #method_name"
end

.sample?(sample_rate) ⇒ Boolean



100
101
102
# File 'lib/statsd/instrument/compiled_metric.rb', line 100

def sample?(sample_rate)
  @singleton_client.sink.sample?(sample_rate)
end

.sample_rateFloat

Will raise when define has not yet been called on the class.

Raises:

  • (ArgumentError)


106
107
108
109
110
# File 'lib/statsd/instrument/compiled_metric.rb', line 106

def sample_rate
  raise ArgumentError, "Every CompiledMetric subclass needs to call `define` before accessing its sample_rate." unless defined?(@sample_rate)

  @sample_rate
end

.typeString

Returns The metric type character (e.g., "c" for counter).

Raises:

  • (NotImplementedError)


68
69
70
# File 'lib/statsd/instrument/compiled_metric.rb', line 68

def type
  raise NotImplementedError, "Subclasses must implement #type"
end