Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instrument Valkyrie via Datadog #880

Merged
merged 4 commits into from
Mar 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ source "https://rubygems.org"
gem "autoprefixer-rails"
gem "blacklight"
gem 'bunny'
gem 'ddtrace'
gem "devise-guests", git: "https://github.com/cbeer/devise-guests.git"
gem "flutie"
gem "honeybadger"
Expand Down Expand Up @@ -51,10 +52,6 @@ group :development, :staging do
gem "rack-mini-profiler", require: false
end

group :production do
gem 'ddtrace'
end

group :test do
gem 'chromedriver-helper'
gem "database_cleaner"
Expand Down
126 changes: 126 additions & 0 deletions app/adapters/instrumented_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# frozen_string_literal: true
class InstrumentedAdapter < SimpleDelegator
attr_reader :metadata_adapter, :tracer
delegate :query_service, :persister, :is_a?, :kind_of?, to: :metadata_adapter
def initialize(metadata_adapter:, tracer:)
super(metadata_adapter)
@metadata_adapter = metadata_adapter
@tracer = tracer
end

def persister
@persister ||= InstrumentedPersister.new(persister: metadata_adapter.persister, instrumented_adapter: self)
end

def query_service
@query_service ||= InstrumentedQueryService.new(query_service: metadata_adapter.query_service, instrumented_adapter: self)
end

class InstrumentedService < SimpleDelegator
attr_reader :instrumented_adapter
delegate :metadata_adapter, to: :instrumented_adapter
delegate :tracer, to: :instrumented_adapter
def trace(resource, _resource_describer = nil)
tracer.trace(span_name) do |span|
span.service = "valkyrie-#{metadata_adapter.class}"
span.span_type = Datadog::Ext::AppTypes::DB
span.resource = resource
yield(span)
end
end

def span_name
'valkyrie.persist'
end
end
class InstrumentedPersister < InstrumentedService
def initialize(persister:, instrumented_adapter:)
@instrumented_adapter = instrumented_adapter
super(persister)
end

def save(resource:)
trace('valkyrie.save') do |span|
__getobj__.save(resource: resource).tap do |output|
span.set_tag('param.resource', output.id.to_s)
end
end
end

def delete(resource:)
trace('valkyrie.delete') do |span|
span.set_tag('param.resource', resource.id.to_s)
__getobj__.delete(resource: resource)
end
end

def save_all(resources:)
trace('valkyrie.save_all') do |span|
__getobj__.save_all(resources: resources).tap do |output|
span.set_tag('param.resources', output.map { |x| x.id.to_s })
end
end
end
end
class InstrumentedQueryService < InstrumentedService
def initialize(query_service:, instrumented_adapter:)
@instrumented_adapter = instrumented_adapter
super(query_service)
end

def find_by(id:)
trace('valkyrie.find_by_id') do |span|
span.set_tag('param.id', id.to_s)
__getobj__.find_by(id: id)
end
end

def find_all
trace('valkyrie.find_all') do
__getobj__.find_all
end
end

def find_all_of_model(model:)
trace('valkyrie.find_all_of_model') do |span|
span.set_tag('param.model', model.to_s)
__getobj__.find_all_of_model(model: model)
end
end

def find_members(resource:, model: nil)
trace('valkyrie.find_members') do |span|
span.set_tag('param.model', model.to_s)
span.set_tag('param.resource', resource.id.to_s)
__getobj__.find_members(resource: resource, model: model)
end
end

def find_parents(resource:)
trace('valkyrie.find_parents') do |span|
span.set_tag('param.resource', resource.id.to_s)
__getobj__.find_parents(resource: resource)
end
end

def find_references_by(resource:, property:)
trace('valkyrie.find_references_by') do |span|
span.set_tag('param.resource', resource.id.to_s)
span.set_tag('param.property', property.to_s)
__getobj__.find_references_by(resource: resource, property: property)
end
end

def find_inverse_references_by(resource:, property:)
trace('valkyrie.find_inverse_references_by') do |span|
span.set_tag('param.resource', resource.id.to_s)
span.set_tag('param.property', property.to_s)
__getobj__.find_inverse_references_by(resource: resource, property: property)
end
end

def span_name
'valkyrie.query'
end
end
end
26 changes: 12 additions & 14 deletions config/initializers/datadog.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
# frozen_string_literal: true
if Rails.env.production?
require 'ddtrace'
Datadog.configure do |c|
# Rails
c.use :rails
Datadog.configure do |c|
c.tracer(enabled: false) unless Rails.env.production?
# Rails
c.use :rails

# Redis
c.use :redis
# Redis
c.use :redis

# Net::HTTP
c.use :http
# Net::HTTP
c.use :http

# Sidekiq
c.use :sidekiq
# Sidekiq
c.use :sidekiq

# Faraday
c.use :faraday
end
# Faraday
c.use :faraday
end
36 changes: 21 additions & 15 deletions config/initializers/valkyrie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@
)

Valkyrie::MetadataAdapter.register(
Valkyrie::Persistence::Postgres::MetadataAdapter.new,
InstrumentedAdapter.new(
metadata_adapter: Valkyrie::Persistence::Postgres::MetadataAdapter.new,
tracer: Datadog.tracer
),
:postgres
)

Expand All @@ -76,20 +79,23 @@
)

Valkyrie::MetadataAdapter.register(
Valkyrie::Persistence::Solr::MetadataAdapter.new(
connection: Blacklight.default_index.connection,
resource_indexer: CompositeIndexer.new(
Valkyrie::Indexers::AccessControlsIndexer,
CollectionIndexer,
EphemeraBoxIndexer,
EphemeraFolderIndexer,
MemberOfIndexer,
FacetIndexer,
ProjectIndexer,
HumanReadableTypeIndexer,
SortingIndexer,
ImportedMetadataIndexer
)
InstrumentedAdapter.new(
metadata_adapter: Valkyrie::Persistence::Solr::MetadataAdapter.new(
connection: Blacklight.default_index.connection,
resource_indexer: CompositeIndexer.new(
Valkyrie::Indexers::AccessControlsIndexer,
CollectionIndexer,
EphemeraBoxIndexer,
EphemeraFolderIndexer,
MemberOfIndexer,
FacetIndexer,
ProjectIndexer,
HumanReadableTypeIndexer,
SortingIndexer,
ImportedMetadataIndexer
)
),
tracer: Datadog.tracer
),
:index_solr
)
Expand Down
52 changes: 52 additions & 0 deletions spec/adapters/instrumented_adapter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# frozen_string_literal: true
require 'rails_helper'
require 'valkyrie/specs/shared_specs'

RSpec.describe InstrumentedAdapter do
let(:adapter) do
described_class.new(metadata_adapter: Valkyrie::MetadataAdapter.find(:indexing_persister), tracer: tracer)
end
let(:query_service) { adapter.query_service }
let(:persister) { adapter.persister }
let(:index_solr) { Valkyrie::MetadataAdapter.find(:index_solr) }
let(:tracer) { Datadog.tracer }
it_behaves_like "a Valkyrie::Persister"

describe "saving" do
let(:tracer) { tracer_stub }
let(:tracer_stub) { instance_double(Datadog::Tracer) }
let(:span) { instance_double(Datadog::Span) }
before do
allow(tracer).to receive(:trace).and_yield(span)
allow(span).to receive(:service=)
allow(span).to receive(:span_type=)
allow(span).to receive(:resource=)
allow(span).to receive(:set_tag)
end
it "instruments information to datadog" do
resource = ScannedResource.new
output = adapter.persister.save(resource: resource)
adapter.persister.save_all(resources: [output])
adapter.query_service.find_by(id: output.id)
adapter.query_service.find_all
adapter.query_service.find_members(resource: resource)
adapter.query_service.find_parents(resource: resource)
adapter.query_service.find_references_by(resource: resource, property: :member_ids)
adapter.query_service.find_inverse_references_by(resource: resource, property: :member_ids)
adapter.query_service.find_all_of_model(model: resource.class)
adapter.persister.delete(resource: output)
expect(tracer).to have_received(:trace).with("valkyrie.query").exactly(7).times
expect(tracer).to have_received(:trace).with("valkyrie.persist").exactly(3).times
expect(span).to have_received(:resource=).with("valkyrie.save")
expect(span).to have_received(:resource=).with("valkyrie.save_all")
expect(span).to have_received(:resource=).with("valkyrie.find_by_id")
expect(span).to have_received(:resource=).with("valkyrie.delete")
expect(span).to have_received(:resource=).with("valkyrie.find_all")
expect(span).to have_received(:resource=).with("valkyrie.find_members")
expect(span).to have_received(:resource=).with("valkyrie.find_parents")
expect(span).to have_received(:resource=).with("valkyrie.find_references_by")
expect(span).to have_received(:resource=).with("valkyrie.find_inverse_references_by")
expect(span).to have_received(:resource=).with("valkyrie.find_all_of_model")
end
end
end