Loading lib/labkit/tracing/rails.rb +1 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ module Labkit module Rails autoload :ActionViewSubscriber, "labkit/tracing/rails/action_view_subscriber" autoload :ActiveRecordSubscriber, "labkit/tracing/rails/active_record_subscriber" autoload :ActiveSupportSubscriber, "labkit/tracing/rails/active_support_subscriber" autoload :RailsCommon, "labkit/tracing/rails/rails_common" end end Loading lib/labkit/tracing/rails/active_support_subscriber.rb 0 → 100644 +86 −0 Original line number Diff line number Diff line # frozen_string_literal: true module Labkit module Tracing module Rails # ActiveSupport bridges action active support notifications to # the distributed tracing subsystem class ActiveSupportSubscriber include RailsCommon COMPONENT_TAG = "ActiveSupport" CACHE_READ_TOPIC = "cache_read.active_support" CACHE_GENERATE_TOPIC = "cache_generate.active_support" CACHE_FETCH_HIT_TOPIC = "cache_fetch_hit.active_support" CACHE_WRITE_TOPIC = "cache_write.active_support" CACHE_DELETE_TOPIC = "cache_delete.active_support" # Instruments Rails ActiveSupport events for opentracing. # Returns a lambda, which, when called will unsubscribe from the notifications def self.instrument subscriber = new subscriptions = [ ActiveSupport::Notifications.subscribe(CACHE_READ_TOPIC) do |_, start, finish, _, payload| subscriber.notify_cache_read(start, finish, payload) end, ActiveSupport::Notifications.subscribe(CACHE_GENERATE_TOPIC) do |_, start, finish, _, payload| subscriber.notify_cache_generate(start, finish, payload) end, ActiveSupport::Notifications.subscribe(CACHE_FETCH_HIT_TOPIC) do |_, start, finish, _, payload| subscriber.notify_cache_fetch_hit(start, finish, payload) end, ActiveSupport::Notifications.subscribe(CACHE_WRITE_TOPIC) do |_, start, finish, _, payload| subscriber.notify_cache_write(start, finish, payload) end, ActiveSupport::Notifications.subscribe(CACHE_DELETE_TOPIC) do |_, start, finish, _, payload| subscriber.notify_cache_delete(start, finish, payload) end, ] create_unsubscriber subscriptions end # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html#active-support def notify_cache_read(start, finish, payload) generate_span_for_notification("cache_read", start, finish, payload, tags_for_cache_read(payload)) end def notify_cache_generate(start, finish, payload) generate_span_for_notification("cache_generate", start, finish, payload, tags_for_key(payload)) end def notify_cache_fetch_hit(start, finish, payload) generate_span_for_notification("cache_fetch_hit", start, finish, payload, tags_for_key(payload)) end def notify_cache_write(start, finish, payload) generate_span_for_notification("cache_write", start, finish, payload, tags_for_key(payload)) end def notify_cache_delete(start, finish, payload) generate_span_for_notification("cache_delete", start, finish, payload, tags_for_key(payload)) end private def tags_for_cache_read(payload) { "component" => COMPONENT_TAG, "cache.key" => payload[:key], "cache.hit" => payload[:hit], "cache.super_operation" => payload[:super_operation], } end def tags_for_key(payload) { "component" => COMPONENT_TAG, "cache.key" => payload[:key], } end end end end end spec/labkit/tracing/rails/active_support_subscriber_spec.rb 0 → 100644 +107 −0 Original line number Diff line number Diff line # frozen_string_literal: true describe Labkit::Tracing::Rails::ActiveSupportSubscriber do using RSpec::Parameterized::TableSyntax describe ".instrument" do it "is unsubscribeable" do unsubscribe = described_class.instrument expect(unsubscribe).not_to be_nil expect { unsubscribe.call }.not_to raise_error end end describe "#notify_cache_read" do subject { described_class.new } let(:start) { Time.now } let(:finish) { Time.now } where(:key, :hit, :super_operation) do nil | nil | nil 123 | nil | nil 123 | true | nil 123 | false | nil 123 | true | "fetch" end with_them do def payload { key: key, hit: hit, super_operation: super_operation } end def expected_tags { "component" => "ActiveSupport", "cache.key" => key, "cache.hit" => hit, "cache.super_operation" => super_operation, } end it "should notify the tracer when the hash contains null values" do expect(Labkit::Tracing::TracingUtils).to receive(:postnotify_span).with("cache_read", start, finish, tags: expected_tags, exception: nil) subject.notify_cache_read(start, finish, payload) end it "should notify the tracer when the payload is missing values" do expect(Labkit::Tracing::TracingUtils).to receive(:postnotify_span).with("cache_read", start, finish, tags: expected_tags, exception: nil) subject.notify_cache_read(start, finish, payload.compact) end it "should not throw exceptions when with the default tracer" do expect { subject.notify_cache_read(start, finish, payload) }.not_to raise_error end end end describe "#notify_*" do subject { described_class.new } let(:start) { Time.now } let(:finish) { Time.now } where(:method, :operation_name, :key) do :notify_cache_generate | "cache_generate" | nil :notify_cache_generate | "cache_generate" | 123 :notify_cache_fetch_hit | "cache_fetch_hit" | nil :notify_cache_fetch_hit | "cache_fetch_hit" | 123 :notify_cache_write | "cache_write" | nil :notify_cache_write | "cache_write" | 123 :notify_cache_delete | "cache_delete" | nil :notify_cache_delete | "cache_delete" | 123 end with_them do def payload { key: key } end def expected_tags { "component" => "ActiveSupport", "cache.key" => key, } end it "should notify the tracer when the hash contains null values" do expect(Labkit::Tracing::TracingUtils).to receive(:postnotify_span).with(operation_name, start, finish, tags: expected_tags, exception: nil) subject.method(method).call(start, finish, payload) end it "should notify the tracer when the payload is missing values" do expect(Labkit::Tracing::TracingUtils).to receive(:postnotify_span).with(operation_name, start, finish, tags: expected_tags, exception: nil) subject.method(method).call(start, finish, payload.compact) end it "should not throw exceptions when with the default tracer" do expect { subject.method(method).call(start, finish, payload) }.not_to raise_error end end end end Loading
lib/labkit/tracing/rails.rb +1 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ module Labkit module Rails autoload :ActionViewSubscriber, "labkit/tracing/rails/action_view_subscriber" autoload :ActiveRecordSubscriber, "labkit/tracing/rails/active_record_subscriber" autoload :ActiveSupportSubscriber, "labkit/tracing/rails/active_support_subscriber" autoload :RailsCommon, "labkit/tracing/rails/rails_common" end end Loading
lib/labkit/tracing/rails/active_support_subscriber.rb 0 → 100644 +86 −0 Original line number Diff line number Diff line # frozen_string_literal: true module Labkit module Tracing module Rails # ActiveSupport bridges action active support notifications to # the distributed tracing subsystem class ActiveSupportSubscriber include RailsCommon COMPONENT_TAG = "ActiveSupport" CACHE_READ_TOPIC = "cache_read.active_support" CACHE_GENERATE_TOPIC = "cache_generate.active_support" CACHE_FETCH_HIT_TOPIC = "cache_fetch_hit.active_support" CACHE_WRITE_TOPIC = "cache_write.active_support" CACHE_DELETE_TOPIC = "cache_delete.active_support" # Instruments Rails ActiveSupport events for opentracing. # Returns a lambda, which, when called will unsubscribe from the notifications def self.instrument subscriber = new subscriptions = [ ActiveSupport::Notifications.subscribe(CACHE_READ_TOPIC) do |_, start, finish, _, payload| subscriber.notify_cache_read(start, finish, payload) end, ActiveSupport::Notifications.subscribe(CACHE_GENERATE_TOPIC) do |_, start, finish, _, payload| subscriber.notify_cache_generate(start, finish, payload) end, ActiveSupport::Notifications.subscribe(CACHE_FETCH_HIT_TOPIC) do |_, start, finish, _, payload| subscriber.notify_cache_fetch_hit(start, finish, payload) end, ActiveSupport::Notifications.subscribe(CACHE_WRITE_TOPIC) do |_, start, finish, _, payload| subscriber.notify_cache_write(start, finish, payload) end, ActiveSupport::Notifications.subscribe(CACHE_DELETE_TOPIC) do |_, start, finish, _, payload| subscriber.notify_cache_delete(start, finish, payload) end, ] create_unsubscriber subscriptions end # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html#active-support def notify_cache_read(start, finish, payload) generate_span_for_notification("cache_read", start, finish, payload, tags_for_cache_read(payload)) end def notify_cache_generate(start, finish, payload) generate_span_for_notification("cache_generate", start, finish, payload, tags_for_key(payload)) end def notify_cache_fetch_hit(start, finish, payload) generate_span_for_notification("cache_fetch_hit", start, finish, payload, tags_for_key(payload)) end def notify_cache_write(start, finish, payload) generate_span_for_notification("cache_write", start, finish, payload, tags_for_key(payload)) end def notify_cache_delete(start, finish, payload) generate_span_for_notification("cache_delete", start, finish, payload, tags_for_key(payload)) end private def tags_for_cache_read(payload) { "component" => COMPONENT_TAG, "cache.key" => payload[:key], "cache.hit" => payload[:hit], "cache.super_operation" => payload[:super_operation], } end def tags_for_key(payload) { "component" => COMPONENT_TAG, "cache.key" => payload[:key], } end end end end end
spec/labkit/tracing/rails/active_support_subscriber_spec.rb 0 → 100644 +107 −0 Original line number Diff line number Diff line # frozen_string_literal: true describe Labkit::Tracing::Rails::ActiveSupportSubscriber do using RSpec::Parameterized::TableSyntax describe ".instrument" do it "is unsubscribeable" do unsubscribe = described_class.instrument expect(unsubscribe).not_to be_nil expect { unsubscribe.call }.not_to raise_error end end describe "#notify_cache_read" do subject { described_class.new } let(:start) { Time.now } let(:finish) { Time.now } where(:key, :hit, :super_operation) do nil | nil | nil 123 | nil | nil 123 | true | nil 123 | false | nil 123 | true | "fetch" end with_them do def payload { key: key, hit: hit, super_operation: super_operation } end def expected_tags { "component" => "ActiveSupport", "cache.key" => key, "cache.hit" => hit, "cache.super_operation" => super_operation, } end it "should notify the tracer when the hash contains null values" do expect(Labkit::Tracing::TracingUtils).to receive(:postnotify_span).with("cache_read", start, finish, tags: expected_tags, exception: nil) subject.notify_cache_read(start, finish, payload) end it "should notify the tracer when the payload is missing values" do expect(Labkit::Tracing::TracingUtils).to receive(:postnotify_span).with("cache_read", start, finish, tags: expected_tags, exception: nil) subject.notify_cache_read(start, finish, payload.compact) end it "should not throw exceptions when with the default tracer" do expect { subject.notify_cache_read(start, finish, payload) }.not_to raise_error end end end describe "#notify_*" do subject { described_class.new } let(:start) { Time.now } let(:finish) { Time.now } where(:method, :operation_name, :key) do :notify_cache_generate | "cache_generate" | nil :notify_cache_generate | "cache_generate" | 123 :notify_cache_fetch_hit | "cache_fetch_hit" | nil :notify_cache_fetch_hit | "cache_fetch_hit" | 123 :notify_cache_write | "cache_write" | nil :notify_cache_write | "cache_write" | 123 :notify_cache_delete | "cache_delete" | nil :notify_cache_delete | "cache_delete" | 123 end with_them do def payload { key: key } end def expected_tags { "component" => "ActiveSupport", "cache.key" => key, } end it "should notify the tracer when the hash contains null values" do expect(Labkit::Tracing::TracingUtils).to receive(:postnotify_span).with(operation_name, start, finish, tags: expected_tags, exception: nil) subject.method(method).call(start, finish, payload) end it "should notify the tracer when the payload is missing values" do expect(Labkit::Tracing::TracingUtils).to receive(:postnotify_span).with(operation_name, start, finish, tags: expected_tags, exception: nil) subject.method(method).call(start, finish, payload.compact) end it "should not throw exceptions when with the default tracer" do expect { subject.method(method).call(start, finish, payload) }.not_to raise_error end end end end