Skip to content

Commit

Permalink
DEV: Introduce syntax_tree for formatting (#329)
Browse files Browse the repository at this point in the history
  • Loading branch information
tgxworld authored Dec 5, 2024
1 parent 4e21b4c commit cf7bf84
Show file tree
Hide file tree
Showing 71 changed files with 1,500 additions and 1,222 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
strategy:
fail-fast: false
matrix:
ruby: ['3.1', '3.2', '3.3']
ruby: ["3.1", "3.2", "3.3"]
activerecord: [61, 70, 71]

steps:
Expand All @@ -42,6 +42,9 @@ jobs:
- name: Rubocop
run: bundle exec rubocop

- name: Syntax tree
run: bundle exec stree check Gemfile $(git ls-files '*.rb') $(git ls-files '*.rake') $(git ls-files '*.thor')

- name: Run tests
run: bundle exec rake

Expand Down
2 changes: 2 additions & 0 deletions .streerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--print-width=100
--plugins=plugin/trailing_comma,disable_ternary
23 changes: 12 additions & 11 deletions bench/bench.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# frozen_string_literal: true

require_relative '../lib/prometheus_exporter'
require_relative '../lib/prometheus_exporter/client'
require_relative '../lib/prometheus_exporter/server'
require_relative "../lib/prometheus_exporter"
require_relative "../lib/prometheus_exporter/client"
require_relative "../lib/prometheus_exporter/server"

# test how long it takes a custom collector to process 10k messages

Expand All @@ -26,18 +26,19 @@ def prometheus_metrics_text
@client = nil
@runs = 1000

done = lambda do
puts "Elapsed for 10k messages is #{Time.now - @start}"
if (@runs -= 1) > 0
@start = Time.now
10_000.times { @client.send_json(hello: "world") }
done =
lambda do
puts "Elapsed for 10k messages is #{Time.now - @start}"
if (@runs -= 1) > 0
@start = Time.now
10_000.times { @client.send_json(hello: "world") }
end
end
end

collector = Collector.new(done)
server = PrometheusExporter::Server::WebServer.new port: 12349, collector: collector
server = PrometheusExporter::Server::WebServer.new port: 12_349, collector: collector
server.start
@client = PrometheusExporter::Client.new port: 12349, max_queue_size: 100_000
@client = PrometheusExporter::Client.new port: 12_349, max_queue_size: 100_000

@start = Time.now
10_000.times { @client.send_json(hello: "world") }
Expand Down
4 changes: 1 addition & 3 deletions examples/custom_collector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ def process(obj)
end

def prometheus_metrics_text
@mutex.synchronize do
"#{@gauge1.to_prometheus_text}\n#{@gauge2.to_prometheus_text}"
end
@mutex.synchronize { "#{@gauge1.to_prometheus_text}\n#{@gauge2.to_prometheus_text}" }
end
end
34 changes: 6 additions & 28 deletions lib/prometheus_exporter/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@ def initialize(name:, help:, type:, client:, opts: nil)
end

def standard_values(value, keys, prometheus_exporter_action = nil)
values = {
type: @type,
help: @help,
name: @name,
keys: keys,
value: value
}
values = { type: @type, help: @help, name: @name, keys: keys, value: value }
values[
:prometheus_exporter_action
] = prometheus_exporter_action if prometheus_exporter_action
Expand Down Expand Up @@ -59,10 +53,7 @@ def self.default=(client)

def initialize(
host: ENV.fetch("PROMETHEUS_EXPORTER_HOST", "localhost"),
port: ENV.fetch(
"PROMETHEUS_EXPORTER_PORT",
PrometheusExporter::DEFAULT_PORT
),
port: ENV.fetch("PROMETHEUS_EXPORTER_PORT", PrometheusExporter::DEFAULT_PORT),
max_queue_size: nil,
thread_sleep: 0.5,
json_serializer: nil,
Expand All @@ -83,9 +74,7 @@ def initialize(
max_queue_size ||= MAX_QUEUE_SIZE
max_queue_size = max_queue_size.to_i

if max_queue_size <= 0
raise ArgumentError, "max_queue_size must be larger than 0"
end
raise ArgumentError, "max_queue_size must be larger than 0" if max_queue_size <= 0

@max_queue_size = max_queue_size
@host = host
Expand All @@ -94,8 +83,7 @@ def initialize(
@mutex = Mutex.new
@thread_sleep = thread_sleep

@json_serializer =
json_serializer == :oj ? PrometheusExporter::OjCompat : JSON
@json_serializer = json_serializer == :oj ? PrometheusExporter::OjCompat : JSON

@custom_labels = custom_labels
end
Expand All @@ -105,14 +93,7 @@ def custom_labels=(custom_labels)
end

def register(type, name, help, opts = nil)
metric =
RemoteMetric.new(
type: type,
name: name,
help: help,
client: self,
opts: opts
)
metric = RemoteMetric.new(type: type, name: name, help: help, client: self, opts: opts)
@metrics << metric
metric
end
Expand Down Expand Up @@ -262,10 +243,7 @@ def ensure_socket!
def wait_for_empty_queue_with_timeout(timeout_seconds)
start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
while @queue.length > 0
if start_time + timeout_seconds <
::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
break
end
break if start_time + timeout_seconds < ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
sleep(0.05)
end
end
Expand Down
28 changes: 20 additions & 8 deletions lib/prometheus_exporter/instrumentation/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
# collects stats from currently running process
module PrometheusExporter::Instrumentation
class ActiveRecord < PeriodicStats
ALLOWED_CONFIG_LABELS = %i(database username host port)
ALLOWED_CONFIG_LABELS = %i[database username host port]

def self.start(client: nil, frequency: 30, custom_labels: {}, config_labels: [])
client ||= PrometheusExporter::Client.default

# Not all rails versions support connection pool stats
unless ::ActiveRecord::Base.connection_pool.respond_to?(:stat)
client.logger.error("ActiveRecord connection pool stats not supported in your rails version")
client.logger.error(
"ActiveRecord connection pool stats not supported in your rails version",
)
return
end

Expand All @@ -29,7 +31,9 @@ def self.start(client: nil, frequency: 30, custom_labels: {}, config_labels: [])

def self.validate_config_labels(config_labels)
return if config_labels.size == 0
raise "Invalid Config Labels, available options #{ALLOWED_CONFIG_LABELS}" if (config_labels - ALLOWED_CONFIG_LABELS).size > 0
if (config_labels - ALLOWED_CONFIG_LABELS).size > 0
raise "Invalid Config Labels, available options #{ALLOWED_CONFIG_LABELS}"
end
end

def initialize(metric_labels, config_labels)
Expand All @@ -55,7 +59,7 @@ def collect_active_record_pool_stats(metrics)
pid: pid,
type: "active_record",
hostname: ::PrometheusExporter.hostname,
metric_labels: labels(pool)
metric_labels: labels(pool),
}
metric.merge!(pool.stat)
metrics << metric
Expand All @@ -66,12 +70,20 @@ def collect_active_record_pool_stats(metrics)

def labels(pool)
if ::ActiveRecord.version < Gem::Version.new("6.1.0.rc1")
@metric_labels.merge(pool_name: pool.spec.name).merge(pool.spec.config
.select { |k, v| @config_labels.include? k }
.map { |k, v| [k.to_s.dup.prepend("dbconfig_"), v] }.to_h)
@metric_labels.merge(pool_name: pool.spec.name).merge(
pool
.spec
.config
.select { |k, v| @config_labels.include? k }
.map { |k, v| [k.to_s.dup.prepend("dbconfig_"), v] }
.to_h,
)
else
@metric_labels.merge(pool_name: pool.db_config.name).merge(
@config_labels.each_with_object({}) { |l, acc| acc["dbconfig_#{l}"] = pool.db_config.public_send(l) })
@config_labels.each_with_object({}) do |l, acc|
acc["dbconfig_#{l}"] = pool.db_config.public_send(l)
end,
)
end
end
end
Expand Down
31 changes: 20 additions & 11 deletions lib/prometheus_exporter/instrumentation/delayed_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,33 @@

module PrometheusExporter::Instrumentation
class DelayedJob
JOB_CLASS_REGEXP = %r{job_class: ((\w+:{0,2})+)}.freeze
JOB_CLASS_REGEXP = /job_class: ((\w+:{0,2})+)/.freeze

class << self
def register_plugin(client: nil, include_module_name: false)
instrumenter = self.new(client: client)
return unless defined?(Delayed::Plugin)

plugin = Class.new(Delayed::Plugin) do
callbacks do |lifecycle|
lifecycle.around(:invoke_job) do |job, *args, &block|
max_attempts = Delayed::Worker.max_attempts
enqueued_count = Delayed::Job.where(queue: job.queue).count
pending_count = Delayed::Job.where(attempts: 0, locked_at: nil, queue: job.queue).count
instrumenter.call(job, max_attempts, enqueued_count, pending_count, include_module_name,
*args, &block)
plugin =
Class.new(Delayed::Plugin) do
callbacks do |lifecycle|
lifecycle.around(:invoke_job) do |job, *args, &block|
max_attempts = Delayed::Worker.max_attempts
enqueued_count = Delayed::Job.where(queue: job.queue).count
pending_count =
Delayed::Job.where(attempts: 0, locked_at: nil, queue: job.queue).count
instrumenter.call(
job,
max_attempts,
enqueued_count,
pending_count,
include_module_name,
*args,
&block
)
end
end
end
end

Delayed::Worker.plugins << plugin
end
Expand Down Expand Up @@ -50,7 +59,7 @@ def call(job, max_attempts, enqueued_count, pending_count, include_module_name,
attempts: attempts,
max_attempts: max_attempts,
enqueued: enqueued_count,
pending: pending_count
pending: pending_count,
)
end
end
Expand Down
6 changes: 2 additions & 4 deletions lib/prometheus_exporter/instrumentation/good_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ def self.start(client: nil, frequency: 30)
good_job_collector = new
client ||= PrometheusExporter::Client.default

worker_loop do
client.send_json(good_job_collector.collect)
end
worker_loop { client.send_json(good_job_collector.collect) }

super
end
Expand All @@ -23,7 +21,7 @@ def collect
running: ::GoodJob::Job.running.size,
finished: ::GoodJob::Job.finished.size,
succeeded: ::GoodJob::Job.succeeded.size,
discarded: ::GoodJob::Job.discarded.size
discarded: ::GoodJob::Job.discarded.size,
}
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/prometheus_exporter/instrumentation/hutch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def handle(message)
type: "hutch",
name: @klass.class.to_s,
success: success,
duration: duration
duration: duration,
)
end
end
Expand Down
24 changes: 12 additions & 12 deletions lib/prometheus_exporter/instrumentation/method_profiler.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# frozen_string_literal: true

# see https://samsaffron.com/archive/2017/10/18/fastest-way-to-profile-a-method-in-ruby
module PrometheusExporter::Instrumentation; end
module PrometheusExporter::Instrumentation
end

class PrometheusExporter::Instrumentation::MethodProfiler
def self.patch(klass, methods, name, instrument:)
Expand All @@ -21,9 +22,8 @@ def self.transfer
end

def self.start(transfer = nil)
Thread.current[:_method_profiler] = transfer || {
__start: Process.clock_gettime(Process::CLOCK_MONOTONIC)
}
Thread.current[:_method_profiler] = transfer ||
{ __start: Process.clock_gettime(Process::CLOCK_MONOTONIC) }
end

def self.clear
Expand All @@ -42,8 +42,8 @@ def self.stop

def self.define_methods_on_module(klass, methods, name)
patch_source_line = __LINE__ + 3
patches = methods.map do |method_name|
<<~RUBY

patches = methods.map { |method_name| <<~RUBY }.join("\n")
def #{method_name}(...)
unless prof = Thread.current[:_method_profiler]
return super
Expand All @@ -58,9 +58,8 @@ def #{method_name}(...)
end
end
RUBY
end.join("\n")

klass.module_eval patches, __FILE__, patch_source_line
klass.module_eval(patches, __FILE__, patch_source_line)
end

def self.patch_using_prepend(klass, methods, name)
Expand All @@ -71,14 +70,16 @@ def self.patch_using_prepend(klass, methods, name)

def self.patch_using_alias_method(klass, methods, name)
patch_source_line = __LINE__ + 3
patches = methods.map do |method_name|
<<~RUBY

patches = methods.map { |method_name| <<~RUBY }.join("\n")
unless defined?(#{method_name}__mp_unpatched)
alias_method :#{method_name}__mp_unpatched, :#{method_name}
def #{method_name}(...)
unless prof = Thread.current[:_method_profiler]
return #{method_name}__mp_unpatched(...)
end
begin
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
#{method_name}__mp_unpatched(...)
Expand All @@ -90,8 +91,7 @@ def #{method_name}(...)
end
end
RUBY
end.join("\n")

klass.class_eval patches, __FILE__, patch_source_line
klass.class_eval(patches, __FILE__, patch_source_line)
end
end
Loading

0 comments on commit cf7bf84

Please sign in to comment.