mirror of
https://github.com/cmur2/dyndnsd.git
synced 2026-11-14 12:55:58 +01:00
gems: include vendored metrisk without hitime dependency
hitime is only needed for Metriks::Timer and requires native extensions. Those do not compile with default settings under Ubuntu 26.04 or Alpine 3.24.
This commit is contained in:
1 parent
645469f41e
commit
7fa9f499e1
10 files changed
+502
-29
No files matched your search
@@ -0,0 +1,34 @@
|
||||
# Minimal pure-Ruby replacement for the 'atomic' gem, covering the exact API
|
||||
# the vendored metriks code uses (Atomic.new, #value, #value=, #update,
|
||||
# #compare_and_swap). Mutex-guarded instead of relying on a native extension.
|
||||
module Metriks
|
||||
class Atomic
|
||||
def initialize(value = nil)
|
||||
@value = value
|
||||
@mutex = Mutex.new
|
||||
end
|
||||
|
||||
def value
|
||||
@mutex.synchronize { @value }
|
||||
end
|
||||
|
||||
def value=(new_value)
|
||||
@mutex.synchronize { @value = new_value }
|
||||
end
|
||||
|
||||
def update
|
||||
@mutex.synchronize { @value = yield(@value) }
|
||||
end
|
||||
|
||||
def compare_and_swap(expected, new_value)
|
||||
@mutex.synchronize do
|
||||
if @value == expected
|
||||
@value = new_value
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,66 @@
|
||||
# Vendored from metriks 0.9.9.8 — https://github.com/eric/metriks
|
||||
# Copyright (c) 2012 Eric Lindvall, MIT licensed.
|
||||
# Trimmed to the subset dyndnsd uses (meters + registry + reporters).
|
||||
|
||||
|
||||
module Metriks
|
||||
class EWMA
|
||||
INTERVAL = 5.0
|
||||
SECONDS_PER_MINUTE = 60.0
|
||||
|
||||
ONE_MINUTE = 1
|
||||
FIVE_MINUTES = 5
|
||||
FIFTEEN_MINUTES = 15
|
||||
|
||||
M1_ALPHA = 1 - Math.exp(-INTERVAL / SECONDS_PER_MINUTE / ONE_MINUTE)
|
||||
M5_ALPHA = 1 - Math.exp(-INTERVAL / SECONDS_PER_MINUTE / FIVE_MINUTES)
|
||||
M15_ALPHA = 1 - Math.exp(-INTERVAL / SECONDS_PER_MINUTE / FIFTEEN_MINUTES)
|
||||
|
||||
def self.new_m1
|
||||
new(M1_ALPHA, INTERVAL)
|
||||
end
|
||||
|
||||
def self.new_m5
|
||||
new(M5_ALPHA, INTERVAL)
|
||||
end
|
||||
|
||||
def self.new_m15
|
||||
new(M15_ALPHA, INTERVAL)
|
||||
end
|
||||
|
||||
def initialize(alpha, interval)
|
||||
@alpha = alpha
|
||||
@interval = interval
|
||||
|
||||
@initialized = false
|
||||
@rate = Atomic.new(0.0)
|
||||
@uncounted = Atomic.new(0)
|
||||
end
|
||||
|
||||
def clear
|
||||
@initialized = false
|
||||
@rate.value = 0.0
|
||||
@uncounted.value = 0
|
||||
end
|
||||
|
||||
def update(value)
|
||||
@uncounted.update { |v| v + value }
|
||||
end
|
||||
|
||||
def tick
|
||||
count = @uncounted.swap(0)
|
||||
instant_rate = count / @interval.to_f
|
||||
|
||||
if @initialized
|
||||
@rate.update { |v| v + @alpha * (instant_rate - v) }
|
||||
else
|
||||
@rate.value = instant_rate
|
||||
@initialized = true
|
||||
end
|
||||
end
|
||||
|
||||
def rate
|
||||
@rate.value
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,88 @@
|
||||
# Vendored from metriks 0.9.9.8 — https://github.com/eric/metriks
|
||||
# Copyright (c) 2012 Eric Lindvall, MIT licensed.
|
||||
# Trimmed to the subset dyndnsd uses (meters + registry + reporters).
|
||||
|
||||
|
||||
require 'metriks/ewma'
|
||||
|
||||
module Metriks
|
||||
class Meter
|
||||
TICK_INTERVAL = 5.0
|
||||
|
||||
def initialize(averager_klass = Metriks::EWMA)
|
||||
@count = Atomic.new(0)
|
||||
@start_time = Time.now.to_f
|
||||
@last_tick = Atomic.new(@start_time)
|
||||
|
||||
@m1_rate = averager_klass.new_m1
|
||||
@m5_rate = averager_klass.new_m5
|
||||
@m15_rate = averager_klass.new_m15
|
||||
end
|
||||
|
||||
def clear
|
||||
@count.value = 0
|
||||
@start_time = Time.now.to_f
|
||||
@last_tick.value = @start_time
|
||||
@m1_rate.clear
|
||||
@m5_rate.clear
|
||||
@m15_rate.clear
|
||||
end
|
||||
|
||||
def tick
|
||||
@m1_rate.tick
|
||||
@m5_rate.tick
|
||||
@m15_rate.tick
|
||||
end
|
||||
|
||||
def tick_if_nessesary
|
||||
old_tick = @last_tick.value
|
||||
new_tick = Time.new.to_f
|
||||
age = new_tick - old_tick
|
||||
if age > TICK_INTERVAL && @last_tick.compare_and_swap(old_tick, new_tick)
|
||||
required_ticks = age / TICK_INTERVAL
|
||||
required_ticks.to_i.times do
|
||||
tick
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def mark(val = 1)
|
||||
tick_if_nessesary
|
||||
@count.update { |v| v + val }
|
||||
@m1_rate.update(val)
|
||||
@m5_rate.update(val)
|
||||
@m15_rate.update(val)
|
||||
end
|
||||
|
||||
def count
|
||||
@count.value
|
||||
end
|
||||
|
||||
def one_minute_rate
|
||||
tick_if_nessesary
|
||||
@m1_rate.rate
|
||||
end
|
||||
|
||||
def five_minute_rate
|
||||
tick_if_nessesary
|
||||
@m5_rate.rate
|
||||
end
|
||||
|
||||
def fifteen_minute_rate
|
||||
tick_if_nessesary
|
||||
@m15_rate.rate
|
||||
end
|
||||
|
||||
def mean_rate
|
||||
if count == 0
|
||||
return 0.0
|
||||
else
|
||||
elapsed = Time.now.to_f - @start_time
|
||||
count / elapsed
|
||||
end
|
||||
end
|
||||
|
||||
def stop
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,127 @@
|
||||
# Vendored from metriks 0.9.9.8 — https://github.com/eric/metriks
|
||||
# Copyright (c) 2012 Eric Lindvall, MIT licensed.
|
||||
# Trimmed to the subset dyndnsd uses (meters + registry + reporters).
|
||||
|
||||
require 'metriks/meter'
|
||||
|
||||
module Metriks
|
||||
# Public: A collection of metrics
|
||||
class Registry
|
||||
# Public: The default registry for the process.
|
||||
#
|
||||
# Returns the default Registry for the process.
|
||||
def self.default
|
||||
@default ||= new
|
||||
end
|
||||
|
||||
# Public: Initializes a new Registry.
|
||||
def initialize
|
||||
@mutex = Mutex.new
|
||||
@metrics = {}
|
||||
end
|
||||
|
||||
# Public: Clear all of the metrics in the Registry. This ensures all
|
||||
# metrics that have been added are stopped.
|
||||
#
|
||||
# Returns nothing.
|
||||
def clear
|
||||
@mutex.synchronize do
|
||||
@metrics.each do |key, metric|
|
||||
metric.stop if metric.respond_to?(:stop)
|
||||
end
|
||||
|
||||
@metrics = {}
|
||||
end
|
||||
end
|
||||
|
||||
# Public: Clear all of the metrics in the Registry. This has the same
|
||||
# effect as calling #clear.
|
||||
#
|
||||
# Returns nothing.
|
||||
def stop
|
||||
clear
|
||||
end
|
||||
|
||||
# Public: Iterate over all of the counters.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# registry.each do |name, metric|
|
||||
# puts name
|
||||
# end
|
||||
#
|
||||
# Returns nothing.
|
||||
def each(&block)
|
||||
metrics = @mutex.synchronize do
|
||||
@metrics.dup
|
||||
end
|
||||
|
||||
metrics.each(&block)
|
||||
end
|
||||
|
||||
# Public: Fetch or create a new meter metric. Meters are a counter that
|
||||
# tracks throughput along with the count.
|
||||
#
|
||||
# name - The String name of the metric to define or fetch
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# registry.meter('resque.calls')
|
||||
#
|
||||
# Returns the Metriks::Meter identified by the name.
|
||||
def meter(name)
|
||||
add_or_get(name, Metriks::Meter)
|
||||
end
|
||||
|
||||
# Public: Fetch an existing metric.
|
||||
#
|
||||
# name - The String name of the metric to fetch
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# registry.get('rack.utilization')
|
||||
#
|
||||
# Returns the metric or nil.
|
||||
def get(name)
|
||||
@mutex.synchronize do
|
||||
@metrics[name]
|
||||
end
|
||||
end
|
||||
|
||||
# Public: Add a new metric.
|
||||
#
|
||||
# name - The String name of the metric to add
|
||||
# metric - The metric instance to add
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# registry.add('method.calls', Metriks::Counter.new)
|
||||
#
|
||||
# Returns nothing.
|
||||
# Raises RuntimeError if the metric name is already defined
|
||||
def add(name, metric)
|
||||
@mutex.synchronize do
|
||||
if @metrics[name]
|
||||
raise "Metric '#{name}' already defined"
|
||||
else
|
||||
@metrics[name] = metric
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def add_or_get(name, klass, &create_metric)
|
||||
@mutex.synchronize do
|
||||
if metric = @metrics[name]
|
||||
if !metric.is_a?(klass)
|
||||
raise "Metric already defined as '#{metric.class}'"
|
||||
else
|
||||
return metric
|
||||
end
|
||||
else
|
||||
@metrics[name] = create_metric ? create_metric.call : klass.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,91 @@
|
||||
# Vendored from metriks 0.9.9.8 — https://github.com/eric/metriks
|
||||
# Copyright (c) 2012 Eric Lindvall, MIT licensed.
|
||||
# Trimmed to the subset dyndnsd uses (meters + registry + reporters).
|
||||
|
||||
require 'socket'
|
||||
|
||||
module Metriks::Reporter
|
||||
class Graphite
|
||||
attr_reader :host, :port
|
||||
|
||||
def initialize(host, port, options = {})
|
||||
@host = host
|
||||
@port = port
|
||||
|
||||
@prefix = options[:prefix]
|
||||
|
||||
@registry = options[:registry] || Metriks::Registry.default
|
||||
@interval = options[:interval] || 60
|
||||
@on_error = options[:on_error] || proc { |ex| }
|
||||
end
|
||||
|
||||
def socket
|
||||
@socket = nil if @socket && @socket.closed?
|
||||
@socket ||= TCPSocket.new(@host, @port)
|
||||
end
|
||||
|
||||
def start
|
||||
@thread ||= Thread.new do
|
||||
loop do
|
||||
sleep @interval
|
||||
|
||||
Thread.new do
|
||||
begin
|
||||
write
|
||||
rescue Exception => ex
|
||||
@on_error[ex] rescue nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def stop
|
||||
@thread.kill if @thread
|
||||
@thread = nil
|
||||
end
|
||||
|
||||
def restart
|
||||
stop
|
||||
start
|
||||
end
|
||||
|
||||
def write
|
||||
@registry.each do |name, metric|
|
||||
case metric
|
||||
when Metriks::Meter
|
||||
write_metric name, metric, [
|
||||
:count, :one_minute_rate, :five_minute_rate,
|
||||
:fifteen_minute_rate, :mean_rate
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def write_metric(base_name, metric, keys, snapshot_keys = [])
|
||||
time = Time.now.to_i
|
||||
|
||||
base_name = base_name.to_s.gsub(/ +/, '_')
|
||||
if @prefix
|
||||
base_name = "#{@prefix}.#{base_name}"
|
||||
end
|
||||
|
||||
keys.flatten.each do |key|
|
||||
name = key.to_s.gsub(/^get_/, '')
|
||||
value = metric.send(key)
|
||||
socket.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)
|
||||
socket.write("#{base_name}.#{name} #{value} #{time}\n")
|
||||
end
|
||||
end
|
||||
rescue Errno::EPIPE
|
||||
socket.close
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,63 @@
|
||||
# Vendored from metriks 0.9.9.8 — https://github.com/eric/metriks
|
||||
# Copyright (c) 2012 Eric Lindvall, MIT licensed.
|
||||
# Trimmed to the subset dyndnsd uses (meters + registry + reporters).
|
||||
|
||||
module Metriks::Reporter
|
||||
class ProcTitle
|
||||
def initialize(options = {})
|
||||
@rounding = options[:rounding] || 1
|
||||
@prefix = options[:prefix] || $0.dup
|
||||
|
||||
@interval = options[:interval] || 5
|
||||
@on_error = options[:on_error] || proc { |ex| }
|
||||
|
||||
@metrics = []
|
||||
end
|
||||
|
||||
def add(name, suffix = nil, &block)
|
||||
@metrics << [ name, suffix, block ]
|
||||
end
|
||||
|
||||
def empty?
|
||||
@metrics.empty?
|
||||
end
|
||||
|
||||
def start
|
||||
@thread ||= Thread.new do
|
||||
loop do
|
||||
begin
|
||||
unless @metrics.empty?
|
||||
title = generate_title
|
||||
if title && !title.empty?
|
||||
$0 = "#{@prefix} #{title}"
|
||||
end
|
||||
end
|
||||
rescue Exception => ex
|
||||
@on_error[ex] rescue nil
|
||||
end
|
||||
sleep @interval
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def stop
|
||||
@thread.kill if @thread
|
||||
@thread = nil
|
||||
end
|
||||
|
||||
def restart
|
||||
stop
|
||||
start
|
||||
end
|
||||
|
||||
protected
|
||||
def generate_title
|
||||
@metrics.collect do |name, suffix, block|
|
||||
val = block.call
|
||||
val = "%.#{@rounding}f" % val if val.is_a?(Float)
|
||||
|
||||
"#{name}: #{val}#{suffix}"
|
||||
end.join(' ')
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user