Skip to content

Commit de91025

Browse files
committed
Automatically patch Rack::Builder
* in tests, keep an unpatched ('untainted') version of Rack::Builder, restore before and after each test * fix: ruby2.4: private method `define_method' called
1 parent 87e74b8 commit de91025

File tree

7 files changed

+100
-8
lines changed

7 files changed

+100
-8
lines changed

adapters/rack/example/trace_demonstration.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@
1515

1616
# setup fake rack application:
1717
builder = Rack::Builder.app do
18-
# integration should be automatic in web frameworks (like rails),
19-
# but for a plain Rack application, enable it in your config.ru, e.g.,
20-
use OpenTelemetry::Adapters::Rack::Middlewares::TracerMiddleware
21-
2218
app = ->(_env) { [200, { 'Content-Type' => 'text/plain' }, ['All responses are OK']] }
2319
run app
2420
end

adapters/rack/example/trace_demonstration2.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
app = ->(_env) { [200, { 'Content-Type' => 'text/plain' }, ['All responses are OK']] }
1515
builder.run app
1616

17-
1817
# demonstrate integration using config[:application] instead of 'builder.use':
1918
OpenTelemetry::SDK.configure do |c|
2019
c.use 'OpenTelemetry::Adapters::Rack', retain_middleware_names: true,

adapters/rack/lib/opentelemetry/adapters/rack/adapter.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,14 @@ class Adapter < OpenTelemetry::Instrumentation::Adapter
1414
require_dependencies
1515

1616
retain_middleware_names if config[:retain_middleware_names]
17-
config[:application]&.use Middlewares::TracerMiddleware
17+
18+
if (app = config[:application])
19+
app.use Middlewares::TracerMiddleware
20+
else
21+
# monkey patch Rack::Builder:
22+
require_relative 'patches/rack_builder'
23+
::Rack::Builder.prepend Rack::Patches::RackBuilder
24+
end
1825
end
1926

2027
present do
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
# Copyright 2020 OpenTelemetry Authors
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
require 'rack/builder'
8+
9+
module OpenTelemetry
10+
module Adapters
11+
module Rack
12+
module Patches
13+
# Allows Rack::Builder to use middleware by default
14+
module RackBuilder
15+
def self.prepended(base)
16+
old_initialize = base.instance_method(:initialize)
17+
18+
# NOTE: define_method is private in ruby-2.4:
19+
base.send(:define_method, :initialize) do |*args, &block|
20+
# pass original args to 'super':
21+
old_initialize.bind(self).call(args, &block)
22+
23+
# add tracer middleware to default stack, once:
24+
use Middlewares::TracerMiddleware if @use.empty?
25+
end
26+
end
27+
end
28+
end
29+
end
30+
end
31+
end
32+
33+
require_relative '../middlewares/tracer_middleware'

adapters/rack/test/opentelemetry/adapters/rack/middlewares/tracer_middleware_test.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,8 @@
4040
# clear out cached config:
4141
described_class.send(:clear_cached_config)
4242

43-
# integrate tracer middleware:
43+
# tracer middleware (automatically integrated):
4444
rack_builder.run app
45-
rack_builder.use described_class
4645
end
4746

4847
after do
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
# Copyright 2020 OpenTelemetry Authors
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
require 'test_helper'
8+
9+
require_relative '../../../../../lib/opentelemetry/adapters/rack'
10+
require_relative '../../../../../lib/opentelemetry/adapters/rack/patches/rack_builder'
11+
12+
describe OpenTelemetry::Adapters::Rack::Patches::RackBuilder do
13+
let(:adapter_module) { OpenTelemetry::Adapters::Rack }
14+
let(:adapter_class) { adapter_module::Adapter }
15+
let(:adapter) { adapter_class.instance }
16+
17+
let(:config) { {} }
18+
19+
before do
20+
# allow for adapter re-installation:
21+
adapter.instance_variable_set('@installed', false)
22+
end
23+
24+
describe 'default installation' do
25+
it 'adds middleware to default stack' do
26+
_(::Rack::Builder.new.instance_variable_get(:@use).length).must_equal 0
27+
28+
adapter.install(config)
29+
30+
_(::Rack::Builder.new.instance_variable_get(:@use).length).must_equal 1
31+
end
32+
end
33+
end

adapters/rack/test/test_helper.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,28 @@
2020
end
2121

2222
EXPORTER = exporter
23+
24+
### "un-patch" Rack::Builder:
25+
#
26+
require 'rack/builder'
27+
UNTAINTED_RACK_BUILDER = ::Rack::Builder.dup
28+
29+
module SafeRackBuilder
30+
def after_setup
31+
super
32+
::Rack.send(:remove_const, :Builder)
33+
::Rack.const_set(:Builder, UNTAINTED_RACK_BUILDER.dup)
34+
end
35+
36+
def after_teardown
37+
super
38+
Rack.send(:remove_const, :Builder)
39+
Rack.const_set(:Builder, UNTAINTED_RACK_BUILDER.dup)
40+
end
41+
end
42+
43+
module Minitest
44+
class Test
45+
include SafeRackBuilder
46+
end
47+
end

0 commit comments

Comments
 (0)