Browse Source

monitoring: add textfile reporter to write Graphite-style metrics into file

cn 6 months ago
parent
commit
a01276c348
5 changed files with 129 additions and 1 deletions
  1. 6
    0
      .rubocop.yml
  2. 1
    0
      CHANGELOG.md
  3. 5
    1
      README.md
  4. 7
    0
      lib/dyndnsd.rb
  5. 110
    0
      lib/dyndnsd/textfile_reporter.rb

+ 6
- 0
.rubocop.yml View File

@@ -37,6 +37,9 @@ Metrics/PerceivedComplexity:
37 37
 Naming/UncommunicativeMethodParamName:
38 38
   Enabled: false
39 39
 
40
+Naming/MemoizedInstanceVariableName:
41
+  Enabled: false
42
+
40 43
 Style/ConditionalAssignment:
41 44
   Enabled: false
42 45
 
@@ -61,5 +64,8 @@ Style/InverseMethods:
61 64
 Style/NegatedIf:
62 65
   Enabled: false
63 66
 
67
+Style/RescueModifier:
68
+  Enabled: false
69
+
64 70
 Style/SymbolArray:
65 71
   Enabled: false

+ 1
- 0
CHANGELOG.md View File

@@ -11,6 +11,7 @@ IMPROVEMENTS:
11 11
 - Add Ruby 2.5 support
12 12
 - Add experimental [OpenTracing](http://opentracing.io/) support with [CNCF Jaeger](https://github.com/jaegertracing/jaeger)
13 13
 - Support host offlining by deleting the associated DNS records
14
+- Add textfile reporter to write Graphite-style metrics (also compatible with [Prometheus](https://prometheus.io/)) into a file
14 15
 
15 16
 ## 1.6.1 (October 31, 2017)
16 17
 

+ 5
- 1
README.md View File

@@ -135,7 +135,7 @@ The [Debian 6 init.d script](init.d/debian-6-dyndnsd) assumes that dyndnsd.rb is
135 135
 
136 136
 ### Monitoring
137 137
 
138
-For monitoring dyndnsd.rb uses the [metriks](https://github.com/eric/metriks) framework and exposes several metrics like the number of unauthenticated requests, requests that did (not) update a hostname, etc. By default the most important metrics are shown in the [proctitle](https://github.com/eric/metriks#proc-title-reporter) but you can also configure a [Graphite](https://graphiteapp.org/) backend for central monitoring.
138
+For monitoring dyndnsd.rb uses the [metriks](https://github.com/eric/metriks) framework and exposes several metrics like the number of unauthenticated requests, requests that did (not) update a hostname, etc. By default the most important metrics are shown in the [proctitle](https://github.com/eric/metriks#proc-title-reporter) but you can also configure a [Graphite](https://graphiteapp.org/) backend for central monitoring or the [textfile_reporter](https://github.com/prometheus/node_exporter/#textfile-collector) which outputs Graphite-style metrics that are also compatible with Prometheus to a file.
139 139
 
140 140
 ```yaml
141 141
 host: "0.0.0.0"
@@ -147,6 +147,10 @@ graphite:
147 147
   host: localhost # defaults for host and port of a carbon server
148 148
   port: 2003
149 149
   prefix: "my.graphite.metrics.naming.structure.dyndnsd"
150
+# OR configure the textfile reporter instead of Graphite/proctitle
151
+textfile:
152
+  file: /path/to/file.prom
153
+  prefix: "my.graphite.metrics.naming.structure.dyndnsd"
150 154
 # configure the updater, here we use command_with_bind_zone, params are updater-specific
151 155
 updater:
152 156
   name: "command_with_bind_zone"

+ 7
- 0
lib/dyndnsd.rb View File

@@ -18,6 +18,7 @@ require 'dyndnsd/responder/dyndns_style'
18 18
 require 'dyndnsd/responder/rest_style'
19 19
 require 'dyndnsd/database'
20 20
 require 'dyndnsd/helper'
21
+require 'dyndnsd/textfile_reporter'
21 22
 require 'dyndnsd/version'
22 23
 
23 24
 module Dyndnsd
@@ -235,6 +236,12 @@ module Dyndnsd
235 236
         options[:prefix] = config['graphite']['prefix'] if config['graphite']['prefix']
236 237
         reporter = Metriks::Reporter::Graphite.new(host, port, options)
237 238
         reporter.start
239
+      elsif config['textfile']
240
+        file = config['textfile']['file'] || '/tmp/dyndnsd-metrics.prom'
241
+        options = {}
242
+        options[:prefix] = config['textfile']['prefix'] if config['textfile']['prefix']
243
+        reporter = Dyndnsd::TextfileReporter.new(file, options)
244
+        reporter.start
238 245
       else
239 246
         reporter = Metriks::Reporter::ProcTitle.new
240 247
         reporter.add 'good', 'sec' do

+ 110
- 0
lib/dyndnsd/textfile_reporter.rb View File

@@ -0,0 +1,110 @@
1
+
2
+# Adapted from https://github.com/eric/metriks-graphite/blob/master/lib/metriks/reporter/graphite.rb
3
+
4
+require 'metriks'
5
+
6
+module Dyndnsd
7
+  class TextfileReporter
8
+    attr_reader :file
9
+
10
+    def initialize(file, options = {})
11
+      @file = file
12
+
13
+      @prefix = options[:prefix]
14
+
15
+      @registry  = options[:registry] || Metriks::Registry.default
16
+      @interval  = options[:interval] || 60
17
+      @on_error  = options[:on_error] || proc { |ex| }
18
+    end
19
+
20
+    def start
21
+      @thread ||= Thread.new do
22
+        loop do
23
+          sleep @interval
24
+
25
+          Thread.new do
26
+            begin
27
+              write
28
+            rescue StandardError => e
29
+              @on_error[e] rescue nil
30
+            end
31
+          end
32
+        end
33
+      end
34
+    end
35
+
36
+    def stop
37
+      @thread&.kill
38
+      @thread = nil
39
+    end
40
+
41
+    def restart
42
+      stop
43
+      start
44
+    end
45
+
46
+    def write
47
+      File.open(@file, 'w') do |f|
48
+        @registry.each do |name, metric|
49
+          case metric
50
+          when Metriks::Meter
51
+            write_metric f, name, metric, [
52
+              :count, :one_minute_rate, :five_minute_rate,
53
+              :fifteen_minute_rate, :mean_rate
54
+            ]
55
+          when Metriks::Counter
56
+            write_metric f, name, metric, [
57
+              :count
58
+            ]
59
+          when Metriks::UtilizationTimer
60
+            write_metric f, name, metric, [
61
+              :count, :one_minute_rate, :five_minute_rate,
62
+              :fifteen_minute_rate, :mean_rate,
63
+              :min, :max, :mean, :stddev,
64
+              :one_minute_utilization, :five_minute_utilization,
65
+              :fifteen_minute_utilization, :mean_utilization
66
+            ], [
67
+              :median, :get_95th_percentile
68
+            ]
69
+          when Metriks::Timer
70
+            write_metric f, name, metric, [
71
+              :count, :one_minute_rate, :five_minute_rate,
72
+              :fifteen_minute_rate, :mean_rate,
73
+              :min, :max, :mean, :stddev
74
+            ], [
75
+              :median, :get_95th_percentile
76
+            ]
77
+          when Metriks::Histogram
78
+            write_metric f, name, metric, [
79
+              :count, :min, :max, :mean, :stddev
80
+            ], [
81
+              :median, :get_95th_percentile
82
+            ]
83
+          end
84
+        end
85
+      end
86
+    end
87
+
88
+    def write_metric(file, base_name, metric, keys, snapshot_keys = [])
89
+      time = Time.now.to_i
90
+
91
+      base_name = base_name.to_s.gsub(/ +/, '_')
92
+      base_name = "#{@prefix}.#{base_name}" if @prefix
93
+
94
+      keys.flatten.each do |key|
95
+        name = key.to_s.gsub(/^get_/, '')
96
+        value = metric.send(key)
97
+        file.write("#{base_name}.#{name} #{value} #{time}\n")
98
+      end
99
+
100
+      unless snapshot_keys.empty?
101
+        snapshot = metric.snapshot
102
+        snapshot_keys.flatten.each do |key|
103
+          name = key.to_s.gsub(/^get_/, '')
104
+          value = snapshot.send(key)
105
+          file.write("#{base_name}.#{name} #{value} #{time}\n")
106
+        end
107
+      end
108
+    end
109
+  end
110
+end