require 'prometheus/client' require 'prometheus/client/mmaped_dict' require 'json' module Prometheus module Client # A float protected by a mutex backed by a per-process mmaped file. class MmapedValue @@files = {} @@files_lock = Mutex.new @@pid = -1 def initialize(type, metric_name, name, labels, multiprocess_mode = '') @pid = Prometheus::Client.pid @file_prefix = type.to_s @metric_name = metric_name @name = name @labels = labels if type == :gauge @file_prefix += '_' + multiprocess_mode.to_s end self.class.reset_on_pid_change if self.class.pid_changed? @mutex = Mutex.new initialize_file end def increment(amount=1) @mutex.synchronize do @value += amount write_value(@key, @value) @value end end def set(value) @mutex.synchronize do @value = value write_value(@key, @value) @value end end def get @mutex.synchronize do return @value end end def self.reset_on_pid_change @@files_lock.synchronize do if pid_changed? @@pid = Prometheus::Client.pid @@files = {} end end end def self.reinitialize_on_pid_change reset_on_pid_change ObjectSpace.each_object(MmapedValue, &:reinitialize) end def self.pid_changed? @@pid != Prometheus::Client.pid end def self.multiprocess true end def reinitialize if @pid != Prometheus::Client.pid @pid = Prometheus::Client.pid initialize_file end end def initialize_file @@files_lock.synchronize do unless @@files.has_key?(@file_prefix) unless @file.nil? @file.close end mmaped_file = Helper::MmapedFile.open_exclusive_file(@file_prefix) @@files[@file_prefix] = MmapedDict.new(mmaped_file) end end @mutex.synchronize do @file = @@files[@file_prefix] labelnames = [] labelvalues = [] @labels.each do |k, v| labelnames << k labelvalues << v end @key = [@metric_name, @name, labelnames, labelvalues].to_json @value = read_value(@key) end end private def write_value(key, val) @file.write_value(key, val) rescue StandardError => e Prometheus::Client.logger.warn("writing value to #{@file.path} failed with #{e}") Prometheus::Client.logger.debug(e.backtrace.join("\n")) end def read_value(key) @file.read_value(key) rescue StandardError => e Prometheus::Client.logger.warn("reading value from #{@file.path} failed with #{e}") Prometheus::Client.logger.debug(e.backtrace.join("\n")) 0 end end end end