Skip to content

Commit

Permalink
Move handlers (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
JuanVqz authored Aug 9, 2023
1 parent e0574c4 commit 6c7b0a2
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 161 deletions.
167 changes: 6 additions & 161 deletions lib/signalman.rb
Original file line number Diff line number Diff line change
@@ -1,168 +1,13 @@
require "signalman/version"
require "signalman/engine"

module Signalman
class BaseHandler
attr_reader :current_time, :event

def self.call(event)
current_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
new(event, current_time).start
end

def initialize(event, current_time)
@event, @current_time = event, current_time
end

def start
process unless skip?
end

def process
create_event
end

def skip?
false
end

def create_event(payload = nil)
payload ||= event.payload

Event.create(
name: event.name,
started_at: started_at,
finished_at: finished_at,
duration: event.duration,
payload: payload
)
rescue ActiveRecord::StatementInvalid => e
Rails.logger.error "[Signalman] #{e.message}"
end

# Time measure since system boot with
# Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
def started_at
Time.current - ((current_time - event.time) / 1_000)
end

def finished_at
Time.current - ((current_time - event.end) / 1_000)
end
end

class ActionHandler < BaseHandler
def process
headers = {}
event.payload.fetch(:headers, {}).each do |name, value|
headers[name] = value if name.start_with?("HTTP")
headers[name] = value if ActionDispatch::Http::Headers::CGI_VARIABLES.include?(name)

[
"action_dispatch.request_id"
].each do |header_name|
headers[name] = value if name == header_name
end
end

create_event event.payload.slice(
:method,
:path,
:controller,
:action,
:params,
:format,
:status,
:db_runtime,
:view_runtime
).merge(headers: headers)
end

def skip?
event.payload[:controller].start_with?("Signalman::")
end
end

class ViewHandler < BaseHandler
def skip?
event.payload[:identifier].include?("app/views/signalman/")
end
end

class QueryHandler < BaseHandler
IGNORED_QUERIES = [
"SCHEMA",
"TRANSACTION",
"ActiveRecord::SchemaMigration",
"ActiveRecord::InternalMetadata",
/^Signalman/
]

# CREATE_TABLE queries have nil for `name`
def skip?
return if event.payload[:name].blank?
IGNORED_QUERIES.any? { |q| q.match? event.payload[:name] }
end

def process
create_event event.payload.except(:connection)
end
end

class MailHandler < BaseHandler
end

class JobHandler < BaseHandler
def process
job = event.payload[:job]
create_event(
class: job.class.name,
id: job.job_id,
enqueued_at: job.enqueued_at,
scheduled_at: scheduled_at(event),
queue_name: queue_name(event),
args: args_info(job)
)
end

# From ActiveJob::LogSubscriber
def queue_name(event)
# Rails 7.1 -> ActiveJob.adapter_name(event.payload[:adapter]) + "(#{event.payload[:job].queue_name})"
event.payload[:adapter].class.name.demodulize.remove("Adapter") + "(#{event.payload[:job].queue_name})"
end

def args_info(job)
if job.class.log_arguments? && job.arguments.any?
" with arguments: " +
job.arguments.map { |arg| format(arg).inspect }.join(", ")
else
""
end
end

def format(arg)
case arg
when Hash
arg.transform_values { |value| format(value) }
when Array
arg.map { |value| format(value) }
when GlobalID::Identification
begin
arg.to_global_id
rescue
arg
end
else
arg
end
end

def scheduled_at(event)
return unless event.payload[:job].scheduled_at
Time.at(event.payload[:job].scheduled_at).utc
end
end
require "signalman/action_handler"
require "signalman/job_handler"
require "signalman/mail_handler"
require "signalman/query_handler"
require "signalman/view_handler"

module Signalman
cattr_accessor :events, default: {
"process_action.action_controller" => {
handler: ActionHandler,
Expand Down
35 changes: 35 additions & 0 deletions lib/signalman/action_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require "signalman/base_handler"

module Signalman
class ActionHandler < BaseHandler
def process
headers = {}
event.payload.fetch(:headers, {}).each do |name, value|
headers[name] = value if name.start_with?("HTTP")
headers[name] = value if ActionDispatch::Http::Headers::CGI_VARIABLES.include?(name)

[
"action_dispatch.request_id"
].each do |header_name|
headers[name] = value if name == header_name
end
end

create_event event.payload.slice(
:method,
:path,
:controller,
:action,
:params,
:format,
:status,
:db_runtime,
:view_runtime
).merge(headers: headers)
end

def skip?
event.payload[:controller].start_with?("Signalman::")
end
end
end
50 changes: 50 additions & 0 deletions lib/signalman/base_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
module Signalman
class BaseHandler
attr_reader :current_time, :event

def self.call(event)
current_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
new(event, current_time).start
end

def initialize(event, current_time)
@event, @current_time = event, current_time
end

def start
process unless skip?
end

def process
create_event
end

def skip?
false
end

def create_event(payload = nil)
payload ||= event.payload

Event.create(
name: event.name,
started_at: started_at,
finished_at: finished_at,
duration: event.duration,
payload: payload
)
rescue ActiveRecord::StatementInvalid => e
Rails.logger.error "[Signalman] #{e.message}"
end

# Time measure since system boot with
# Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
def started_at
Time.current - ((current_time - event.time) / 1_000)
end

def finished_at
Time.current - ((current_time - event.end) / 1_000)
end
end
end
54 changes: 54 additions & 0 deletions lib/signalman/job_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require "signalman/base_handler"

module Signalman
class JobHandler < BaseHandler
def process
job = event.payload[:job]
create_event(
class: job.class.name,
id: job.job_id,
enqueued_at: job.enqueued_at,
scheduled_at: scheduled_at(event),
queue_name: queue_name(event),
args: args_info(job)
)
end

# From ActiveJob::LogSubscriber
def queue_name(event)
# Rails 7.1 -> ActiveJob.adapter_name(event.payload[:adapter]) + "(#{event.payload[:job].queue_name})"
event.payload[:adapter].class.name.demodulize.remove("Adapter") + "(#{event.payload[:job].queue_name})"
end

def args_info(job)
if job.class.log_arguments? && job.arguments.any?
" with arguments: " +
job.arguments.map { |arg| format(arg).inspect }.join(", ")
else
""
end
end

def format(arg)
case arg
when Hash
arg.transform_values { |value| format(value) }
when Array
arg.map { |value| format(value) }
when GlobalID::Identification
begin
arg.to_global_id
rescue
arg
end
else
arg
end
end

def scheduled_at(event)
return unless event.payload[:job].scheduled_at
Time.at(event.payload[:job].scheduled_at).utc
end
end
end
6 changes: 6 additions & 0 deletions lib/signalman/mail_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "signalman/base_handler"

module Signalman
class MailHandler < BaseHandler
end
end
23 changes: 23 additions & 0 deletions lib/signalman/query_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require "signalman/base_handler"

module Signalman
class QueryHandler < BaseHandler
IGNORED_QUERIES = [
"SCHEMA",
"TRANSACTION",
"ActiveRecord::SchemaMigration",
"ActiveRecord::InternalMetadata",
/^Signalman/
]

# CREATE_TABLE queries have nil for `name`
def skip?
return if event.payload[:name].blank?
IGNORED_QUERIES.any? { |q| q.match? event.payload[:name] }
end

def process
create_event event.payload.except(:connection)
end
end
end
9 changes: 9 additions & 0 deletions lib/signalman/view_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require "signalman/base_handler"

module Signalman
class ViewHandler < BaseHandler
def skip?
event.payload[:identifier].include?("app/views/signalman/")
end
end
end

0 comments on commit 6c7b0a2

Please sign in to comment.