|
| 1 | +# Custom New Relic method tracers for hot request paths. |
| 2 | +# |
| 3 | +# High-traffic transactions (GET /search, GET .../classes/{cls}/tree) |
| 4 | +# spend most of their time in application code that the agent reports as |
| 5 | +# a single opaque "Sinatra::Application#GET (unknown)" segment. These |
| 6 | +# tracers split that block into named Custom/* child segments so |
| 7 | +# transaction traces and the breakdown table show where the time goes. |
| 8 | +# |
| 9 | +# To instrument another endpoint, add its module/class and methods to the |
| 10 | +# registry below; test/helpers/test_newrelic_method_tracers.rb consumes |
| 11 | +# the same registry, so new entries are covered automatically. |
| 12 | +# |
| 13 | +# Must be loaded after init.rb so all traced methods are already defined. |
| 14 | +# When the agent is disabled (development/test), the tracers are no-ops. |
| 15 | +# |
| 16 | +# Kill switch: set NEWRELIC_CUSTOM_TRACERS=off (and restart) to skip |
| 17 | +# registration entirely, e.g. to rule instrumentation out while |
| 18 | +# debugging. Requires a process restart to take effect either way. |
| 19 | +module NewRelicMethodTracers |
| 20 | + # Instance methods, keyed by module/class name. Methods inherited from |
| 21 | + # concerns or mixins (e.g. the tree methods, defined in an |
| 22 | + # ontologies_linked_data concern) can be traced here without touching |
| 23 | + # the defining repo. |
| 24 | + INSTANCE_METHODS = { |
| 25 | + # GET /search pipeline |
| 26 | + 'Sinatra::Helpers::SearchHelper' => %i[process_search get_term_search_query |
| 27 | + add_matched_fields filter_attrs_by_language], |
| 28 | + # App-wide: ontology access list load + response serialization entry |
| 29 | + 'Sinatra::Helpers::ApplicationHelper' => %i[restricted_ontologies reply], |
| 30 | + # GET /ontologies/{ontology}/classes/{cls}/tree pipeline |
| 31 | + 'LinkedData::Models::Class' => %i[tree tree_sorted paths_to_root] |
| 32 | + }.freeze |
| 33 | + |
| 34 | + # Class (singleton) methods, keyed by class name. |
| 35 | + CLASS_METHODS = { |
| 36 | + # Hypermedia links + JSON generation for every API response |
| 37 | + 'LinkedData::Serializer' => %i[build_response serialize], |
| 38 | + # Solr query execution incl. Ruby-side response parsing (the HTTP |
| 39 | + # call itself already appears as an External segment) |
| 40 | + 'LinkedData::Models::Class' => %i[search] |
| 41 | + }.freeze |
| 42 | + |
| 43 | + def self.register |
| 44 | + INSTANCE_METHODS.each do |const_name, methods| |
| 45 | + install(Object.const_get(const_name), const_name, methods) |
| 46 | + end |
| 47 | + |
| 48 | + CLASS_METHODS.each do |const_name, methods| |
| 49 | + install(Object.const_get(const_name).singleton_class, const_name, methods) |
| 50 | + end |
| 51 | + end |
| 52 | + |
| 53 | + def self.install(target, const_name, methods) |
| 54 | + target.include(::NewRelic::Agent::MethodTracer) |
| 55 | + |
| 56 | + methods.each do |method_name| |
| 57 | + target.send(:add_method_tracer, method_name, "Custom/#{const_name}/#{method_name}") |
| 58 | + end |
| 59 | + end |
| 60 | +end |
| 61 | + |
| 62 | +unless ENV['NEWRELIC_CUSTOM_TRACERS'] == 'off' |
| 63 | + require 'new_relic/agent/method_tracer' |
| 64 | + NewRelicMethodTracers.register |
| 65 | +end |
0 commit comments