Module: TingYun::Instrumentation::Support::MethodInstrumentation::ClassMethods

Defined in:
lib/ting_yun/instrumentation/support/method_instrumentation.rb

Constant Summary collapse

DEFAULT_SETTINGS =
{:scope => true, :metric => true, :before_code => "", :after_code => "" }.freeze

Instance Method Summary collapse

Instance Method Details

#add_method_tracer(method_name, metric_name = nil, opt = {}) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/ting_yun/instrumentation/support/method_instrumentation.rb', line 183

def add_method_tracer(method_name, metric_name = nil, opt={})
  return unless method_exists?(method_name)
  metric_name ||= default_metric_name(method_name)
  return if traced_method_exists?(method_name, metric_name)

  traced_method = tingyun_eval(method_name, metric_name,opt)

  visibility = TingYun::Helper.instance_method_visibility self, method_name
  class_eval traced_method, __FILE__, __LINE__

  alias_method define_untrace_method_name(method_name, metric_name), method_name
  alias_method method_name, define_trace_method_name(method_name, metric_name)
  send visibility, method_name
  send visibility, define_trace_method_name(method_name, metric_name)
  ::TingYun::Agent.logger.debug("Traced method: class = #{self.name},"+
                                    "method = #{method_name}, "+
                                    "metric = '#{metric_name}'")
end

#default_metric_name(method_name) ⇒ Object

Example:

Foo.default_metric_name('bar') #=> "tingyun/#{Foo.name}/bar"


63
64
65
# File 'lib/ting_yun/instrumentation/support/method_instrumentation.rb', line 63

def default_metric_name(method_name)
  "tingyun/#{self.name}/#{method_name.to_s}"
end

#define_method_with_scope(method_name, metric_name, options) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ting_yun/instrumentation/support/method_instrumentation.rb', line 100

def define_method_with_scope(method_name,metric_name,options)
  "def #{define_trace_method_name(method_name,metric_name)}(*args, &block)
      #{options[:before_code]}

      result = ::TingYun::Agent::MethodTracerHelpers.trace_execution_scoped(\"#{metric_name}\",
              :metric => #{options[:metric]}) do
        #{define_untrace_method_name(method_name, metric_name)}(*args, &block)
      end
      #{options[:after_code]}
      result
   end"
end

#define_method_without_scope(method_name, metric_name, options) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/ting_yun/instrumentation/support/method_instrumentation.rb', line 113

def define_method_without_scope(method_name,metric_name,options)
  "def #{define_trace_method_name(method_name,metric_name)}(*args, &block)
      return #{define_untrace_method_name(method_name, metric_name)}(*args, &block) unless TingYun::Agent::TransactionState.tl_get.execution_traced?\n
  #{options[:before_code]}
      t0 = Time.now
      begin
        #{define_untrace_method_name(method_name, metric_name)}(*args, &block)\n
      ensure
        duration = (Time.now - t0).to_f
        ::TingYun::Agent.record_metric(\"#{metric_name}\", duration)
        #{options[:after_code]}
      end
   end"
end

#method_exists?(method_name) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
58
59
# File 'lib/ting_yun/instrumentation/support/method_instrumentation.rb', line 55

def method_exists?(method_name)
  exists = method_defined?(method_name) || private_method_defined?(method_name)
  ::TingYun::Agent.logger.error("Did not trace #{self.name}##{method_name} because that method does not exist") unless exists
  exists
end

#tingyun_eval(method_name, metric_name, options) ⇒ Object



78
79
80
81
82
83
84
85
# File 'lib/ting_yun/instrumentation/support/method_instrumentation.rb', line 78

def tingyun_eval(method_name, metric_name, options)
  options = validate_options(method_name, options)
  if options[:scope]
    define_method_with_scope(method_name, metric_name, options)
  else
    define_method_without_scope(method_name,metric_name, options)
  end
end

#traced_method_exists?(method_name, metric_name) ⇒ Boolean

Checks to see if we have already traced a method with a given metric by checking to see if the traced method exists. Warns the user if methods are being double-traced to help with debugging custom instrumentation.

Returns:

  • (Boolean)


72
73
74
75
76
# File 'lib/ting_yun/instrumentation/support/method_instrumentation.rb', line 72

def traced_method_exists?(method_name, metric_name)
  exists = method_defined?(define_trace_method_name(method_name, metric_name))
  ::TingYun::Agent.logger.error("Attempt to trace a method twice with the same metric: Method = #{method_name}, Metric Name = #{metric_name}") if exists
  exists
end

#validate_options(method_name, options) ⇒ Object



89
90
91
92
93
94
95
96
97
98
# File 'lib/ting_yun/instrumentation/support/method_instrumentation.rb', line 89

def validate_options(method_name, options)
  unless options.is_a?(Hash)
    raise TypeError.new("Error adding method tracer to #{method_name}: provided options must be a Hash")
  end
  options = DEFAULT_SETTINGS.merge(options)
  unless options[:scope] || options[:metric]
    raise "Can't add a tracer where push_scope is false and metric is false"
  end
  options
end