require 'prometheus/client/uses_value_type' require 'prometheus/client/helper/json_parser' require 'prometheus/client/helper/plain_file' require 'prometheus/client/helper/metrics_processing' require 'prometheus/client/helper/metrics_representation' module Prometheus module Client module Formats # Text format is human readable mainly used for manual inspection. module Text MEDIA_TYPE = 'text/plain'.freeze VERSION = '0.0.4'.freeze CONTENT_TYPE = "#{MEDIA_TYPE}; version=#{VERSION}".freeze class << self def marshal(registry) metrics = registry.metrics.map do |metric| samples = metric.values.flat_map do |label_set, value| representation(metric, label_set, value) end [metric.name, { type: metric.type, help: metric.docstring, samples: samples }] end Helper::MetricsRepresentation.to_text(metrics) end def marshal_multiprocess(path = Prometheus::Client.configuration.multiprocess_files_dir, use_rust: false) file_list = Dir.glob(File.join(path, '*.db')).sort .map {|f| Helper::PlainFile.new(f) } .map {|f| [f.filepath, f.multiprocess_mode.to_sym, f.type.to_sym, f.pid] } if use_rust && rust_impl_available? FastMmapedFileRs.to_metrics(file_list.to_a) else FastMmapedFile.to_metrics(file_list.to_a) end end def rust_impl_available? return @rust_available unless @rust_available.nil? check_for_rust end private def check_for_rust # This will be evaluated on each invocation even with `||=` if # `@rust_available` if false. Running a `require` statement is slow, # so the `rust_impl_available?` method memoizes the result, external # callers can only trigger this method a single time. @rust_available = begin require 'fast_mmaped_file_rs' true rescue LoadError Prometheus::Client.logger.info('FastMmapedFileRs unavailable') false end end def load_metrics(path) metrics = {} Dir.glob(File.join(path, '*.db')).sort.each do |f| Helper::PlainFile.new(f).to_metrics(metrics) end metrics end def representation(metric, label_set, value) labels = metric.base_labels.merge(label_set) if metric.type == :summary summary(metric.name, labels, value) elsif metric.type == :histogram histogram(metric.name, labels, value) else [[metric.name, labels, value.get]] end end def summary(name, set, value) rv = value.get.map do |q, v| [name, set.merge(quantile: q), v] end rv << ["#{name}_sum", set, value.get.sum] rv << ["#{name}_count", set, value.get.total] rv end def histogram(name, set, value) # |metric_name, labels, value| rv = value.get.map do |q, v| [name, set.merge(le: q), v] end rv << [name, set.merge(le: '+Inf'), value.get.total] rv << ["#{name}_sum", set, value.get.sum] rv << ["#{name}_count", set, value.get.total] rv end end end end end end