Module: Trailer::Concern

Defined in:
lib/trailer/concern.rb

Instance Method Summary collapse

Instance Method Details

#trace_class(resource = nil, **tags, &block) ⇒ Object

Traces the given block with optional resource and tags. It will generate an event name based on the calling class, and pass the information on to trace_event().

Parameters:

  • resource (ApplicationRecord, String) (defaults to: nil)
    • *Ideally just pass an ActiveRecord instance here.*

    The resource being operated on, or its name. Usually domain-specific, such as a model instance, query, etc (eg. current_user, ‘Article#submit’, ‘example.com/articles’).

  • tags

    Hash - Extra tags which should be tracked (eg. { method: ‘GET’ }).



70
71
72
73
74
# File 'lib/trailer/concern.rb', line 70

def trace_class(resource = nil, **tags, &block)
  trace_event(self.class.name, resource, **tags) do
    yield block
  end
end

#trace_event(event, resource = nil, **tags, &block) ⇒ Object

Traces the given block, with an event name, plus optional resource and tags.

Parameters:

  • event (String)
    • Describes the generic kind of operation being done (eg. ‘web_request’, or ‘parse_request’).

  • resource (ApplicationRecord, String) (defaults to: nil)
    • *Ideally just pass an ActiveRecord instance here.*

    The resource being operated on, or its name. Usually domain-specific, such as a model instance, query, etc (eg. current_user, ‘Article#submit’, ‘example.com/articles’).

  • tags

    Hash - Extra tags which should be tracked (eg. { method: ‘GET’ }).



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/trailer/concern.rb', line 14

def trace_event(event, resource = nil, **tags, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
  return yield block unless Trailer.enabled?

  event = Trailer::Utility.resource_name(event) unless event.is_a?(String) || event.is_a?(Symbol)

  unless resource.nil?
    resource_name   = resource if resource.is_a?(String) || resource.is_a?(Symbol)
    resource_name ||= Trailer::Utility.resource_name(resource)
    resource_name ||= 'unknown'

    # If column_names() is available, we are probably looking at an ActiveRecord instance.
    if resource.class.respond_to?(:column_names)
      resource.class.column_names.each do |field|
        tags[field] ||= resource.public_send(field) if field.match?(Trailer.config.auto_tag_fields)
      end
    elsif resource.respond_to?(:to_h)
      # This handles other types of data, such as GraphQL input objects.
      resource.to_h.transform_keys(&:to_sym).each do |key, value|
        tags[key] ||= value if key.match?(Trailer.config.auto_tag_fields) || Trailer.config.tag_fields.include?(key)
      end
    end

    # Tag fields that have been explicitly included.
    Trailer.config.tag_fields.each do |field|
      tags[field] ||= resource.public_send(field) if resource.respond_to?(field)
    end

    tags["#{resource_name}_id"] ||= resource.id if resource.respond_to?(:id)
  end

  # Record the ID of the current user, if configured.
  if Trailer.config.current_user_method && respond_to?(Trailer.config.current_user_method, true)
    user = send(Trailer.config.current_user_method)
    tags["#{Trailer.config.current_user_method}_id"] = user.id if user&.respond_to?(:id)
  end

  # Record how long the operation takes, in milliseconds.
  started_at      = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  result          = yield block
  tags[:duration] = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at) * 1_000).ceil

  # Put the keys in alphabetical order, with the event and resource first.
  sorted = { event: event, resource: resource_name }.merge(tags.sort_by { |key, _val| key.to_s }.to_h)
  sorted.transform_keys!(&:to_sym)
  RequestStore.store[:trailer].write(sorted)

  result
end

#trace_method(resource = nil, **tags, &block) ⇒ Object

Traces the given block with optional resource and tags. It will generate an event name based on the calling method and class, and pass the information on to trace_event().

Parameters:

  • resource (ApplicationRecord, String) (defaults to: nil)
    • *Ideally just pass an ActiveRecord instance here.*

    The resource being operated on, or its name. Usually domain-specific, such as a model instance, query, etc (eg. current_user, ‘Article#submit’, ‘example.com/articles’).

  • tags

    Hash - Extra tags which should be tracked (eg. { method: ‘GET’ }).



83
84
85
86
87
88
89
# File 'lib/trailer/concern.rb', line 83

def trace_method(resource = nil, **tags, &block)
  calling_klass  = self.class.name
  calling_method = caller(1..1).first[/`.*'/][1..-2]
  trace_event("#{calling_klass}##{calling_method}", resource, **tags) do
    yield block
  end
end