From a01276c348d730372fa613d67f4a34a264b0b032 Mon Sep 17 00:00:00 2001 From: cn Date: Mon, 23 Apr 2018 07:11:18 +0200 Subject: [PATCH] monitoring: add textfile reporter to write Graphite-style metrics into file --- .rubocop.yml | 6 ++ CHANGELOG.md | 1 + README.md | 6 +- lib/dyndnsd.rb | 7 ++ lib/dyndnsd/textfile_reporter.rb | 110 +++++++++++++++++++++++++++++++ 5 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 lib/dyndnsd/textfile_reporter.rb diff --git a/.rubocop.yml b/.rubocop.yml index 77526f6..cb109ad 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -37,6 +37,9 @@ Metrics/PerceivedComplexity: Naming/UncommunicativeMethodParamName: Enabled: false +Naming/MemoizedInstanceVariableName: + Enabled: false + Style/ConditionalAssignment: Enabled: false @@ -61,5 +64,8 @@ Style/InverseMethods: Style/NegatedIf: Enabled: false +Style/RescueModifier: + Enabled: false + Style/SymbolArray: Enabled: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d49114..acecd28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ IMPROVEMENTS: - Add Ruby 2.5 support - Add experimental [OpenTracing](http://opentracing.io/) support with [CNCF Jaeger](https://github.com/jaegertracing/jaeger) - Support host offlining by deleting the associated DNS records +- Add textfile reporter to write Graphite-style metrics (also compatible with [Prometheus](https://prometheus.io/)) into a file ## 1.6.1 (October 31, 2017) diff --git a/README.md b/README.md index fc020ce..36df9f0 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ The [Debian 6 init.d script](init.d/debian-6-dyndnsd) assumes that dyndnsd.rb is ### Monitoring -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. +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. ```yaml host: "0.0.0.0" @@ -147,6 +147,10 @@ graphite: host: localhost # defaults for host and port of a carbon server port: 2003 prefix: "my.graphite.metrics.naming.structure.dyndnsd" +# OR configure the textfile reporter instead of Graphite/proctitle +textfile: + file: /path/to/file.prom + prefix: "my.graphite.metrics.naming.structure.dyndnsd" # configure the updater, here we use command_with_bind_zone, params are updater-specific updater: name: "command_with_bind_zone" diff --git a/lib/dyndnsd.rb b/lib/dyndnsd.rb index 6d6eb41..847ef07 100755 --- a/lib/dyndnsd.rb +++ b/lib/dyndnsd.rb @@ -18,6 +18,7 @@ require 'dyndnsd/responder/dyndns_style' require 'dyndnsd/responder/rest_style' require 'dyndnsd/database' require 'dyndnsd/helper' +require 'dyndnsd/textfile_reporter' require 'dyndnsd/version' module Dyndnsd @@ -235,6 +236,12 @@ module Dyndnsd options[:prefix] = config['graphite']['prefix'] if config['graphite']['prefix'] reporter = Metriks::Reporter::Graphite.new(host, port, options) reporter.start + elsif config['textfile'] + file = config['textfile']['file'] || '/tmp/dyndnsd-metrics.prom' + options = {} + options[:prefix] = config['textfile']['prefix'] if config['textfile']['prefix'] + reporter = Dyndnsd::TextfileReporter.new(file, options) + reporter.start else reporter = Metriks::Reporter::ProcTitle.new reporter.add 'good', 'sec' do diff --git a/lib/dyndnsd/textfile_reporter.rb b/lib/dyndnsd/textfile_reporter.rb new file mode 100644 index 0000000..a19993c --- /dev/null +++ b/lib/dyndnsd/textfile_reporter.rb @@ -0,0 +1,110 @@ + +# Adapted from https://github.com/eric/metriks-graphite/blob/master/lib/metriks/reporter/graphite.rb + +require 'metriks' + +module Dyndnsd + class TextfileReporter + attr_reader :file + + def initialize(file, options = {}) + @file = file + + @prefix = options[:prefix] + + @registry = options[:registry] || Metriks::Registry.default + @interval = options[:interval] || 60 + @on_error = options[:on_error] || proc { |ex| } + end + + def start + @thread ||= Thread.new do + loop do + sleep @interval + + Thread.new do + begin + write + rescue StandardError => e + @on_error[e] rescue nil + end + end + end + end + end + + def stop + @thread&.kill + @thread = nil + end + + def restart + stop + start + end + + def write + File.open(@file, 'w') do |f| + @registry.each do |name, metric| + case metric + when Metriks::Meter + write_metric f, name, metric, [ + :count, :one_minute_rate, :five_minute_rate, + :fifteen_minute_rate, :mean_rate + ] + when Metriks::Counter + write_metric f, name, metric, [ + :count + ] + when Metriks::UtilizationTimer + write_metric f, name, metric, [ + :count, :one_minute_rate, :five_minute_rate, + :fifteen_minute_rate, :mean_rate, + :min, :max, :mean, :stddev, + :one_minute_utilization, :five_minute_utilization, + :fifteen_minute_utilization, :mean_utilization + ], [ + :median, :get_95th_percentile + ] + when Metriks::Timer + write_metric f, name, metric, [ + :count, :one_minute_rate, :five_minute_rate, + :fifteen_minute_rate, :mean_rate, + :min, :max, :mean, :stddev + ], [ + :median, :get_95th_percentile + ] + when Metriks::Histogram + write_metric f, name, metric, [ + :count, :min, :max, :mean, :stddev + ], [ + :median, :get_95th_percentile + ] + end + end + end + end + + def write_metric(file, base_name, metric, keys, snapshot_keys = []) + time = Time.now.to_i + + base_name = base_name.to_s.gsub(/ +/, '_') + base_name = "#{@prefix}.#{base_name}" if @prefix + + keys.flatten.each do |key| + name = key.to_s.gsub(/^get_/, '') + value = metric.send(key) + file.write("#{base_name}.#{name} #{value} #{time}\n") + end + + unless snapshot_keys.empty? + snapshot = metric.snapshot + snapshot_keys.flatten.each do |key| + name = key.to_s.gsub(/^get_/, '') + value = snapshot.send(key) + file.write("#{base_name}.#{name} #{value} #{time}\n") + end + end + end + end +end