Skip to content

Commit e721aba

Browse files
authored
Merge pull request #4459 from DataDog/appsec-56614-track-triggered-instrumentation-events
[APPSEC-56614] Add Instrumentation::Gateway#pushed? method
2 parents 2f427f8 + 241d169 commit e721aba

File tree

5 files changed

+75
-35
lines changed

5 files changed

+75
-35
lines changed

lib/datadog/appsec/instrumentation/gateway.rb

+17-22
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,29 @@
11
# frozen_string_literal: true
22

3+
require_relative 'gateway/middleware'
4+
35
module Datadog
46
module AppSec
57
# Instrumentation for AppSec
68
module Instrumentation
79
# Instrumentation gateway implementation
810
class Gateway
9-
# Instrumentation gateway middleware
10-
class Middleware
11-
attr_reader :key, :block
12-
13-
def initialize(key, &block)
14-
@key = key
15-
@block = block
16-
end
17-
18-
def call(stack, env)
19-
@block.call(stack, env)
20-
end
21-
end
22-
23-
private_constant :Middleware
24-
2511
def initialize
2612
@middlewares = Hash.new { |h, k| h[k] = [] }
13+
@pushed_events = {}
2714
end
2815

16+
# NOTE: Be careful with pushed names because every pushed event name
17+
# is recorded in order to provide an ability to any subscriber
18+
# to check wether an arbitrary event had happened.
19+
#
20+
# WARNING: If we start pushing generated names we should consider
21+
# limiting the storage of pushed names.
2922
def push(name, env, &block)
30-
block ||= -> {}
23+
@pushed_events[name] = true
3124

32-
middlewares_for_name = middlewares[name]
25+
block ||= -> {}
26+
middlewares_for_name = @middlewares[name]
3327

3428
return [block.call, nil] if middlewares_for_name.empty?
3529

@@ -48,14 +42,15 @@ def push(name, env, &block)
4842
end
4943

5044
def watch(name, key, &block)
51-
@middlewares[name] << Middleware.new(key, &block) unless middlewares[name].any? { |m| m.key == key }
45+
@middlewares[name] << Middleware.new(key, &block) unless @middlewares[name].any? { |m| m.key == key }
5246
end
5347

54-
private
55-
56-
attr_reader :middlewares
48+
def pushed?(name)
49+
@pushed_events.key?(name)
50+
end
5751
end
5852

53+
# NOTE: This left as-is and will be depricated soon.
5954
def self.gateway
6055
@gateway ||= Gateway.new # TODO: not thread safe
6156
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# frozen_string_literal: true
2+
3+
module Datadog
4+
module AppSec
5+
module Instrumentation
6+
class Gateway
7+
# NOTE: This class extracted as-is and will be deprecated
8+
# Instrumentation gateway middleware
9+
class Middleware
10+
attr_reader :key, :block
11+
12+
def initialize(key, &block)
13+
@key = key
14+
@block = block
15+
end
16+
17+
def call(stack, env)
18+
@block.call(stack, env)
19+
end
20+
end
21+
end
22+
end
23+
end
24+
end

sig/datadog/appsec/instrumentation/gateway.rbs

+3-12
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,17 @@ module Datadog
77
type final_call = ^() -> final_call_result
88
type stack = ::Proc
99

10-
# TODO: this should be a struct
1110
type stack_result = ::Array[nil | middleware_result | final_call_result]
1211

13-
class Middleware
14-
attr_reader key: ::Symbol
15-
attr_reader block: ::Proc
16-
17-
def initialize: (::Symbol key) { (stack next, Instrumentation::Gateway::Argument env) -> stack_result } -> void
18-
def call: (stack next, Gateway::Argument? env) -> stack_result
19-
end
20-
2112
@middlewares: ::Hash[::String, ::Array[Middleware]]
2213

2314
def initialize: () -> void
15+
2416
def push: (::String name, Gateway::Argument env) ?{ () -> final_call_result } -> stack_result
25-
def watch: (::String name, ::Symbol key) { (stack next, Gateway::Argument env) -> stack_result } -> void
2617

27-
private
18+
def watch: (::String name, ::Symbol key) { (stack next, Gateway::Argument env) -> stack_result } -> void
2819

29-
attr_reader middlewares: ::Hash[::String, ::Array[Middleware]]
20+
def pushed?: (::String name) -> bool
3021
end
3122

3223
self.@gateway: Gateway
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module Datadog
2+
module AppSec
3+
module Instrumentation
4+
class Gateway
5+
class Middleware
6+
attr_reader key: ::Symbol
7+
attr_reader block: ::Proc
8+
9+
def initialize: (::Symbol key) { (Gateway::stack next, Gateway::Argument env) -> stack_result } -> void
10+
def call: (Gateway::stack next, Gateway::Argument? env) -> stack_result
11+
end
12+
end
13+
end
14+
end
15+
end

spec/datadog/appsec/instrumentation/gateway_spec.rb

+16-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
RSpec.describe Datadog::AppSec::Instrumentation::Gateway do
77
subject(:gateway) { described_class.new }
8-
let(:middlewares) { gateway.send(:middlewares) }
8+
let(:middlewares) { gateway.instance_variable_get(:@middlewares) }
99

1010
describe '#watch' do
1111
it 'stores middleware' do
@@ -81,4 +81,19 @@
8181
expect(env_2).to eq({ a: :b, c: :d })
8282
end
8383
end
84+
85+
describe '#pushed?' do
86+
it { expect(gateway.pushed?('event.0')).to be(false) }
87+
88+
it 'returns true if event was pushed' do
89+
expect { gateway.push('event.1', {}) }.to change { gateway.pushed?('event.1') }
90+
.from(false).to(true)
91+
92+
expect { gateway.push('event.2', {}) }.to change { gateway.pushed?('event.2') }
93+
.from(false).to(true)
94+
95+
expect { gateway.push('event.2', {}) }.not_to change { gateway.pushed?('event.2') }
96+
.from(true)
97+
end
98+
end
8499
end

0 commit comments

Comments
 (0)