Module: Fluent::Plugin::Prometheus

Included in:
PrometheusFilter, PrometheusOutput
Defined in:
lib/fluent/plugin/prometheus.rb,
lib/fluent/plugin/prometheus/placeholder_expander.rb

Defined Under Namespace

Classes: AlreadyRegisteredError, Counter, ExpandBuilder, Gauge, Histogram, Metric, Summary

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.parse_labels_elements(conf) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/fluent/plugin/prometheus.rb', line 35

def self.parse_labels_elements(conf)
  labels = conf.elements.select { |e| e.name == 'labels' }
  if labels.size > 1
    raise ConfigError, "labels section must have at most 1"
  end

  base_labels = {}
  unless labels.empty?
    labels.first.each do |key, value|
      labels.first.has_key?(key)

      # use RecordAccessor only for $. and $[ syntax
      # otherwise use the value as is or expand the value by RecordTransformer for ${} syntax
      if value.start_with?('$.') || value.start_with?('$[')
        base_labels[key.to_sym] = PluginHelper::RecordAccessor::Accessor.new(value)
      else
        base_labels[key.to_sym] = value
      end
    end
  end

  base_labels
end

.parse_metrics_elements(conf, registry, labels = {}) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/fluent/plugin/prometheus.rb', line 59

def self.parse_metrics_elements(conf, registry, labels = {})
  metrics = []
  conf.elements.select { |element|
    element.name == 'metric'
  }.each { |element|
    if element.has_key?('key') && (element['key'].start_with?('$.') || element['key'].start_with?('$['))
      value = element['key']
      element['key'] = PluginHelper::RecordAccessor::Accessor.new(value)
    end
    case element['type']
    when 'summary'
      metrics << Fluent::Plugin::Prometheus::Summary.new(element, registry, labels)
    when 'gauge'
      metrics << Fluent::Plugin::Prometheus::Gauge.new(element, registry, labels)
    when 'counter'
      metrics << Fluent::Plugin::Prometheus::Counter.new(element, registry, labels)
    when 'histogram'
      metrics << Fluent::Plugin::Prometheus::Histogram.new(element, registry, labels)
    else
      raise ConfigError, "type option must be 'counter', 'gauge', 'summary' or 'histogram'"
    end
  }
  metrics
end

.placeholder_expander(log) ⇒ Object



84
85
86
# File 'lib/fluent/plugin/prometheus.rb', line 84

def self.placeholder_expander(log)
  Fluent::Plugin::Prometheus::ExpandBuilder.new(log: log)
end

Instance Method Details

#configure(conf) ⇒ Object



100
101
102
103
104
105
# File 'lib/fluent/plugin/prometheus.rb', line 100

def configure(conf)
  super
  @placeholder_values = {}
  @placeholder_expander_builder = Fluent::Plugin::Prometheus.placeholder_expander(log)
  @hostname = Socket.gethostname
end

#instrument(tag, es, metrics) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/fluent/plugin/prometheus.rb', line 127

def instrument(tag, es, metrics)
  placeholder_values = {
    'tag' => tag,
    'hostname' => @hostname,
    'worker_id' => fluentd_worker_id,
  }

  es.each do |time, record|
    record = stringify_keys(record)
    placeholders = record.merge(placeholder_values)
    expander = @placeholder_expander_builder.build(placeholders)
    metrics.each do |metric|
      begin
        metric.instrument(record, expander)
      rescue => e
        log.warn "prometheus: failed to instrument a metric.", error_class: e.class, error: e, tag: tag, name: metric.name
        router.emit_error_event(tag, time, record, e)
      end
    end
  end
end

#instrument_single(tag, time, record, metrics) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/fluent/plugin/prometheus.rb', line 107

def instrument_single(tag, time, record, metrics)
  @placeholder_values[tag] ||= {
    'tag' => tag,
    'hostname' => @hostname,
    'worker_id' => fluentd_worker_id,
  }

  record = stringify_keys(record)
  placeholders = record.merge(@placeholder_values[tag])
  expander = @placeholder_expander_builder.build(placeholders)
  metrics.each do |metric|
    begin
      metric.instrument(record, expander)
    rescue => e
      log.warn "prometheus: failed to instrument a metric.", error_class: e.class, error: e, tag: tag, name: metric.name
      router.emit_error_event(tag, time, record, e)
    end
  end
end

#stringify_keys(hash_to_stringify) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
# File 'lib/fluent/plugin/prometheus.rb', line 88

def stringify_keys(hash_to_stringify)
  # Adapted from: https://www.jvt.me/posts/2019/09/07/ruby-hash-keys-string-symbol/
  hash_to_stringify.map do |k,v|
    value_or_hash = if v.instance_of? Hash
                      stringify_keys(v)
                    else
                      v
                    end
    [k.to_s, value_or_hash]
  end.to_h
end