Skip to content

Commit

Permalink
Instrument ownership gem
Browse files Browse the repository at this point in the history
Add an instrumentation for the `ownership` gem. When a transaction
is created, if an owner has been set in the gem, use the name of
the owner as the namespace for the transaction. Do the same when an
owner is set during an active transaction.

If more than one owner is set during a transaction, the namespace
will be that of the last owner that was set.
  • Loading branch information
unflxw committed Jan 9, 2025
1 parent 78858f2 commit ce2844a
Show file tree
Hide file tree
Showing 9 changed files with 495 additions and 1 deletion.
164 changes: 163 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# This is a generated file by the `rake build_matrix:github:generate` task.
# See `build_matrix.yml` for the build matrix.
# Generate this file with `rake build_matrix:github:generate`.
# Generated job count: 151
# Generated job count: 157
---
name: Ruby gem CI
'on':
Expand Down Expand Up @@ -318,6 +318,33 @@ jobs:
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/http5.gemfile
ruby_3-4-1__ownership_ubuntu-latest:
name: Ruby 3.4.1 - ownership
needs: ruby_3-4-1_ubuntu-latest
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Install Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.4.1
bundler-cache: true
- name: Install gem extension
run: "./script/bundler_wrapper exec rake extension:install"
- name: Print extension install report
run: "[ -e ext/install.report ] && cat ext/install.report || echo 'No ext/install.report
file found'"
- name: Print Makefile log file
run: "[ -f ext/mkmf.log ] && cat ext/mkmf.log || echo 'No ext/mkmf.log file
found'"
- name: Run tests
run: "./script/bundler_wrapper exec rake test"
env:
RAILS_ENV: test
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/ownership.gemfile
ruby_3-4-1__padrino_ubuntu-latest:
name: Ruby 3.4.1 - padrino
needs: ruby_3-4-1_ubuntu-latest
Expand Down Expand Up @@ -970,6 +997,33 @@ jobs:
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/http5.gemfile
ruby_3-3-4__ownership_ubuntu-latest:
name: Ruby 3.3.4 - ownership
needs: ruby_3-3-4_ubuntu-latest
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Install Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3.4
bundler-cache: true
- name: Install gem extension
run: "./script/bundler_wrapper exec rake extension:install"
- name: Print extension install report
run: "[ -e ext/install.report ] && cat ext/install.report || echo 'No ext/install.report
file found'"
- name: Print Makefile log file
run: "[ -f ext/mkmf.log ] && cat ext/mkmf.log || echo 'No ext/mkmf.log file
found'"
- name: Run tests
run: "./script/bundler_wrapper exec rake test"
env:
RAILS_ENV: test
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/ownership.gemfile
ruby_3-3-4__padrino_ubuntu-latest:
name: Ruby 3.3.4 - padrino
needs: ruby_3-3-4_ubuntu-latest
Expand Down Expand Up @@ -1649,6 +1703,33 @@ jobs:
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/http5.gemfile
ruby_3-2-5__ownership_ubuntu-latest:
name: Ruby 3.2.5 - ownership
needs: ruby_3-2-5_ubuntu-latest
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Install Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.2.5
bundler-cache: true
- name: Install gem extension
run: "./script/bundler_wrapper exec rake extension:install"
- name: Print extension install report
run: "[ -e ext/install.report ] && cat ext/install.report || echo 'No ext/install.report
file found'"
- name: Print Makefile log file
run: "[ -f ext/mkmf.log ] && cat ext/mkmf.log || echo 'No ext/mkmf.log file
found'"
- name: Run tests
run: "./script/bundler_wrapper exec rake test"
env:
RAILS_ENV: test
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/ownership.gemfile
ruby_3-2-5__padrino_ubuntu-latest:
name: Ruby 3.2.5 - padrino
needs: ruby_3-2-5_ubuntu-latest
Expand Down Expand Up @@ -2328,6 +2409,33 @@ jobs:
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/http5.gemfile
ruby_3-1-6__ownership_ubuntu-latest:
name: Ruby 3.1.6 - ownership
needs: ruby_3-1-6_ubuntu-latest
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Install Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.1.6
bundler-cache: true
- name: Install gem extension
run: "./script/bundler_wrapper exec rake extension:install"
- name: Print extension install report
run: "[ -e ext/install.report ] && cat ext/install.report || echo 'No ext/install.report
file found'"
- name: Print Makefile log file
run: "[ -f ext/mkmf.log ] && cat ext/mkmf.log || echo 'No ext/mkmf.log file
found'"
- name: Run tests
run: "./script/bundler_wrapper exec rake test"
env:
RAILS_ENV: test
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/ownership.gemfile
ruby_3-1-6__padrino_ubuntu-latest:
name: Ruby 3.1.6 - padrino
needs: ruby_3-1-6_ubuntu-latest
Expand Down Expand Up @@ -2953,6 +3061,33 @@ jobs:
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/http5.gemfile
ruby_3-0-7__ownership_ubuntu-latest:
name: Ruby 3.0.7 - ownership
needs: ruby_3-0-7_ubuntu-latest
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Install Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.0.7
bundler-cache: true
- name: Install gem extension
run: "./script/bundler_wrapper exec rake extension:install"
- name: Print extension install report
run: "[ -e ext/install.report ] && cat ext/install.report || echo 'No ext/install.report
file found'"
- name: Print Makefile log file
run: "[ -f ext/mkmf.log ] && cat ext/mkmf.log || echo 'No ext/mkmf.log file
found'"
- name: Run tests
run: "./script/bundler_wrapper exec rake test"
env:
RAILS_ENV: test
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/ownership.gemfile
ruby_3-0-7__padrino_ubuntu-latest:
name: Ruby 3.0.7 - padrino
needs: ruby_3-0-7_ubuntu-latest
Expand Down Expand Up @@ -3497,6 +3632,33 @@ jobs:
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/http5.gemfile
ruby_2-7-8__ownership_ubuntu-latest:
name: Ruby 2.7.8 - ownership
needs: ruby_2-7-8_ubuntu-latest
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Install Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7.8
bundler-cache: true
- name: Install gem extension
run: "./script/bundler_wrapper exec rake extension:install"
- name: Print extension install report
run: "[ -e ext/install.report ] && cat ext/install.report || echo 'No ext/install.report
file found'"
- name: Print Makefile log file
run: "[ -f ext/mkmf.log ] && cat ext/mkmf.log || echo 'No ext/mkmf.log file
found'"
- name: Run tests
run: "./script/bundler_wrapper exec rake test"
env:
RAILS_ENV: test
JRUBY_OPTS: ''
COV: '1'
BUNDLE_GEMFILE: gemfiles/ownership.gemfile
ruby_2-7-8__padrino_ubuntu-latest:
name: Ruby 2.7.8 - padrino
needs: ruby_2-7-8_ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions build_matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ matrix:
- "3.2.5"
- "3.1.6"
- gem: "http5"
- gem: "ownership"
- gem: "padrino"
- gem: "psych-3"
only:
Expand Down
5 changes: 5 additions & 0 deletions gemfiles/ownership.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source 'https://rubygems.org'

gem 'ownership'

gemspec :path => '../'
1 change: 1 addition & 0 deletions lib/appsignal/hooks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def truncate(text)
require "appsignal/hooks/http"
require "appsignal/hooks/mri"
require "appsignal/hooks/net_http"
require "appsignal/hooks/ownership"
require "appsignal/hooks/passenger"
require "appsignal/hooks/puma"
require "appsignal/hooks/rake"
Expand Down
50 changes: 50 additions & 0 deletions lib/appsignal/hooks/ownership.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

module Appsignal
class Hooks
# @api private
class OwnershipHook < Appsignal::Hooks::Hook
register :ownership

def dependencies_present?
defined?(::Ownership) &&
Gem::Version.new(::Ownership::VERSION) >= Gem::Version.new("0.2.0") &&
Appsignal.config &&
Appsignal.config[:instrument_ownership]
end

def install
require "appsignal/integrations/ownership"

# If a transaction is created in a code context that has an owner,
# set the namespace of the transaction to the owner.
Appsignal::Transaction.after_create <<
Appsignal::Integrations::OwnershipIntegrationHelper.method(:after_create)

# Ensure the method is only added once.
Appsignal::Transaction.after_create.uniq!

# If an error was reported in a code context that has an owner,
# set the namespace of the transaction to the owner.
# In some circumstances, this will be more accurate than the last owner
# that was set for the transaction, which is what would otherwise be
# reported.
Appsignal::Transaction.before_complete <<
Appsignal::Integrations::OwnershipIntegrationHelper.method(:before_complete)

# Ensure the method is only added once.
Appsignal::Transaction.before_complete.uniq!

# If an owner is set in a code context that has an active transaction,
# set the namespace of the transaction to the owner.
unless ::Ownership.singleton_class.included_modules.include?(
Appsignal::Integrations::OwnershipIntegration
)
::Ownership.singleton_class.prepend Appsignal::Integrations::OwnershipIntegration
end

Appsignal::Environment.report_enabled("ownership")
end
end
end
end
42 changes: 42 additions & 0 deletions lib/appsignal/integrations/ownership.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true

module Appsignal
module Integrations
# @api private
module OwnershipIntegration
# Implement the `around_change` logic by monkey-patching the reader,
# instead of by using the `around_change=` writer. This allows customers
# to use the `around_change=` writer in their own code without
# accidentally overriding AppSignal's instrumentation.
def around_change
proc do |owner, block|
OwnershipIntegrationHelper.set(Appsignal::Transaction.current, owner)

original = super

if original
original.call(owner, block)
else
block.call
end
end
end
end

module OwnershipIntegrationHelper
class << self
def set(transaction, owner)
transaction.set_namespace(owner) unless owner.nil?
end

def after_create(transaction)
set(transaction, ::Ownership.owner)
end

def before_complete(transaction, error)
set(transaction, error.owner) if error.respond_to?(:owner)
end
end
end
end
end
Loading

0 comments on commit ce2844a

Please sign in to comment.