tpt-rails 1.6.2 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7a7e431aaf9c9d3546eb414ab15564aba43048d9a3b64104671a1dd589bdc61f
4
- data.tar.gz: 4ecdc856396d0d987e8e847694534b620b5140a442714f5f6e7e236f2625f869
3
+ metadata.gz: a17270ceace03741bb34bcac74250dd4f1b60a478a7870dde68896624bb892ca
4
+ data.tar.gz: ee980279b3354726a5a5050560fad3e8c5ef9324409acbf011890a8300f66bd8
5
5
  SHA512:
6
- metadata.gz: 71faac471d35a3e67356427581afdac4f44fcb66c5840b9a8d06571b15e4e47672e36c252352787be31bd5da35e53d69eff3901c79a6c5685abaa49b0c575057
7
- data.tar.gz: 68670905648c6cb7456768e0805e04b4c904cd808ada80db3961a73ad35e961f0c51ed597c06b25d2b307fca91822b33998caead07b9b7bf998837d01a65f933
6
+ metadata.gz: aa83fa139ee86f016380076133d29d2d2406d4aea9da733dd4842bd617a8c16a0418618252c87f10f5e099161bbb249bbc64955fdea15e1d8901bb26c6e6f045
7
+ data.tar.gz: b3b46f7c49c6d7675a84fafa0088e03b0edea729e7d3b604b568c4f9e45108cd853f43fffc1cf32d51c7c17d5f30be224eed2ac7c83c20fb7a77908088c7e982
data/README.md CHANGED
@@ -16,7 +16,7 @@ rails generate tpt:rails:configuration
16
16
 
17
17
  ### Configuration
18
18
 
19
- Running `rails generate tpt_rails:configure` will generate `config/initializers/tpt_rails.rb`. You
19
+ Running `rails generate tpt:rails:configuration` will generate `config/initializers/tpt_rails.rb`. You
20
20
  can configure this gem and enable optional features in that file.
21
21
 
22
22
  See the documentation in [lib/tpt/rails.rb](lib/tpt/rails.rb).
@@ -74,25 +74,47 @@ See the documentation in [lib/tpt/rails.rb](lib/tpt/rails.rb).
74
74
  gem "aws-sdk-eventbridge", "~> 1.3.0"
75
75
  ```
76
76
 
77
- 2. In an initializer, pass in the `Datadog::Statsd` object you're using to the class method ::set_metrics.
78
- (Failure to do so will result in an error.) When testing, you can pass in a local Statsd, eg:
77
+ 2. Instantiate with
79
78
 
80
79
  ```ruby
81
- Tpt::Rails::EventBridgePublisher.set_metrics(
82
- Datadog::Statsd.new('localhost', 8125)
83
- )
80
+ Tpt::Rails::EventBridgePublisher.new
84
81
  ```
85
82
 
86
83
  3. By default (#new with no arguments) EventBridgePublisher will try to use the following environment
87
84
  variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `TPT_EVENT_SOURCE`, `TPT_SHARED_EVENT_BUS_NAME`.
88
85
 
89
86
  Additional configuration can be set as part of the constructor;
90
- [see event_bridge_publisher.rb implementation](https://github.com/TeachersPayTeachers/tpt-rails/blob/ad768d3bac0c8bd28e60a48a89aed36f01c4e17b/app/models/tpt/rails/event_bridge_publisher.rb) for more details.
87
+ [see event_bridge_publisher.rb implementation](https://github.com/TeachersPayTeachers/tpt-rails/blob/master/app/models/tpt/rails/event_bridge_publisher.rb) for more details.
91
88
 
92
89
  4. Create events by instantiating or inheriting from `Tpt::Rails::ApplicationEvent`. Event types are derived from the text before
93
90
  "Event", so ResourceEvent has the event_type "Resource". Pass in an event or an array of events to EventBridgePublisher#publish
94
91
  and they will be published immediately. Large arrays will be batched (default 10 per batch).
95
92
 
93
+ 5. EventBridgePublisher uses Tpt::Rails.statsd as its datadog instance by default. If you want to change that behavior, call `Tpt::Rails::EventBridgePublisher.set_metrics`
94
+ with the statsd you want to use inside an initializer, as part of a `reloader.to_prepare` call:
95
+
96
+ ```ruby
97
+ Rails.application.reloader.to_prepare do
98
+ Tpt::Rails::EventBridgePublisher.set_metrics(
99
+ # your statsd here
100
+ )
101
+ end
102
+ ```
103
+
104
+ You can also do this when testing by using the default test publisher (see below).
105
+
106
+ ### EventBridge Testing
107
+
108
+ 1. To create a ready-made test publisher, use
109
+
110
+ ```ruby
111
+ Tpt::Rails::EventBridgeTestHelper.publisher
112
+ ```
113
+
114
+ This method accepts two parameters, batch_size and stub_responses. [See implementation docs](https://github.com/TeachersPayTeachers/tpt-rails/blob/master/app/helpers/tpt/rails/event_bridge_test_helper.rb) for more details.
115
+
116
+ 2. The test publisher overwrites statsd that EventBridgePublisher uses to be a dummy statsd when called.
117
+
96
118
  ### Error reporting (e.g. Bugsnag/Rollbar)
97
119
 
98
120
  If you configure `rollbar_access_token` & `rollbar_enabled`, or `bugsnag_api_key` then your project
@@ -0,0 +1,27 @@
1
+ module Tpt::Rails
2
+ module EventBridgeTestHelper
3
+ ###
4
+ # @description: Instantiates an EventBridgePublisher ready for testing. AWS and DataDog info is faked. Note that this sets the
5
+ # metrics object for the class to be a stub. The AWS EventBridge gem will never actually be called as the gem's
6
+ # #put_events method is replaced with a stub.
7
+ # @param {batch_size}: The number of events to send per batch.
8
+ # @param {stub_responses}: Responses to stub, eg. { put_events: { failed_entry_count: 0, entries: [{ event_id: "1" }, { event_id: "2" }] } }
9
+ # @return {EventBridgePublisher}: The EventBridgePublisher object.
10
+ ###
11
+ def self.publisher(batch_size: 10, stub_responses: {})
12
+ Tpt::Rails::EventBridgePublisher.set_metrics(
13
+ Datadog::Statsd.new('localhost', 8125)
14
+ )
15
+
16
+ Tpt::Rails::EventBridgePublisher.new(
17
+ event_source: ENV.fetch('TPT_EVENT_SOURCE', 'test-source'),
18
+ batch_size: batch_size,
19
+ client_options: {
20
+ access_key_id: '1234',
21
+ secret_access_key: 'abcd',
22
+ stub_responses: stub_responses
23
+ }
24
+ )
25
+ end
26
+ end
27
+ end
@@ -3,6 +3,7 @@ module Tpt::Rails
3
3
  class NoEntriesInResponseData < StandardError; end
4
4
 
5
5
  attr_accessor :batch_size
6
+ attr_reader :client
6
7
 
7
8
  def initialize(
8
9
  event_bus_name: default_event_bus_name,
@@ -32,7 +33,7 @@ module Tpt::Rails
32
33
 
33
34
  private
34
35
 
35
- attr_reader :client, :event_bus_name, :event_source
36
+ attr_reader :event_bus_name, :event_source
36
37
 
37
38
  def publish_batch(events)
38
39
  metrics.time('tpt.event_bridge.publish_batch') do
@@ -137,8 +138,9 @@ module Tpt::Rails
137
138
  end
138
139
 
139
140
  def metrics
140
- raise "metrics object not set; use EventBridgePublisher#set_metrics" unless @@statsd
141
+ @@statsd ||= Tpt::Rails.statsd
141
142
 
143
+ raise "metrics object not set and no default found; use EventBridgePublisher#set_metrics" unless @@statsd
142
144
  @@statsd
143
145
  end
144
146
  end
@@ -11,4 +11,34 @@ Tpt::Rails.configure do |config|
11
11
 
12
12
  config.datadog_statsd_url = ENV["DOGSTATSD_URL"].presence
13
13
  config.datadog_trace_url = ENV["DATADOG_TRACE_URL"].presence
14
+
15
+ # Setup for Statsd
16
+ #
17
+ # Either by setting a statsd url (a nil url will create a dummy statsd object):
18
+ # config.datadog_statsd_url = "statsd://localhost:1234"
19
+ #
20
+ # Or by setting a custom statsd setup lambda (which should return a statsd object):
21
+ # config.datadog_statsd_setup = -> {
22
+ # Tpt::Rails::DatadogFactory.make(
23
+ # statsd_url: "statsd://localhost:3000",
24
+ # )
25
+ # }
26
+ #
27
+ # See documentation in tpt-rails for all the options available on the make method
28
+
29
+ # Setup for Tracing
30
+ #
31
+ # To disable tracing (you should disable tracing in most environments):
32
+ # config.datadog_disable_trace = true
33
+ #
34
+ # To use default tracing options and just set url:
35
+ # config.datadog_trace_url = "datadog://localhost:1234"
36
+ #
37
+ # Or for full customization:
38
+ # Tpt::Rails::DatadogFactory.configure_tracing(
39
+ # trace_url: "datadog://localhost:1234",
40
+ # environment: "my_env",
41
+ # trace_tags: ["mytag1:hello", "mytag2:goodbye"],
42
+ # trace_debug: true
43
+ # )
14
44
  end
@@ -1,8 +1,14 @@
1
- require 'tpt/rails/internal/datadog'
1
+ require 'tpt/rails/datadog_factory'
2
2
  require 'tpt/rails/internal/error_reporter'
3
3
  require 'tpt/rails/internal/health_checks'
4
4
 
5
5
  class Tpt::Rails::Config
6
+ class MustBeCallableError < StandardError
7
+ def initialize(msg)
8
+ super(msg)
9
+ end
10
+ end
11
+
6
12
  #
7
13
  # You can set the following configs in your `Tpt::Rails.configure do |config|` block:
8
14
  #
@@ -13,16 +19,22 @@ class Tpt::Rails::Config
13
19
  attr_accessor :app_name
14
20
  # A project-specific api key from Bugsnag
15
21
  attr_accessor :bugsnag_api_key
16
- # Set this in the form of: statsd://[host]:[port]'
22
+ # Set this in the form of: statsd://[host]:[port]
17
23
  attr_accessor :datadog_statsd_url
18
- # Set this in the form of: datadog://[host]:[port]'
24
+ # Set this in the form of: datadog://[host]:[port]
19
25
  attr_accessor :datadog_trace_url
26
+ # Set to true to disable tracing
27
+ attr_accessor :datadog_disable_trace
20
28
  # Set this in the form of: redis://:[password]@[hostname]:[port]/[db]
21
29
  attr_accessor :redis_url
22
30
  # A project-specific access token from rollbar
23
31
  attr_accessor :rollbar_access_token
24
32
  # Allow enabling/disabling Rollbar. Defaults to false.
25
33
  attr_accessor :rollbar_enabled
34
+ # Allows running a custom lambda to setup datadog statsd in configuration
35
+ attr_accessor :datadog_statsd_setup
36
+ # Allows running a custom lambda to setup datadog tracing in configuration
37
+ attr_accessor :datadog_trace_setup
26
38
 
27
39
  # Add a health check to the endpoint provided at `/internal/health-check` by
28
40
  # Tpt::Rails::HealthChecksController.
@@ -56,10 +68,37 @@ class Tpt::Rails::Config
56
68
  Redis.current = Redis.new(url: redis_url, driver: :hiredis)
57
69
  end
58
70
 
59
- @datadog = Tpt::Rails::Internal::Datadog.new(
60
- statsd_url: datadog_statsd_url,
61
- trace_url: datadog_trace_url,
62
- )
71
+ if !datadog_statsd_setup.nil?
72
+ if datadog_statsd_setup.respond_to?(:call)
73
+ @statsd = datadog_statsd_setup.call
74
+ datadog_statsd_setup = nil
75
+
76
+ unless @statsd.class == Datadog::Statsd
77
+ raise "datadog_statsd_setup MUST return a #{Datadog::Statsd.to_s} object! Instead, returned a #{@statsd.class}"
78
+ end
79
+ else
80
+ msg = "datadog_statsd_setup must be nil or callable. You should provide a lambda that returns a statsd object, probably from calling Tpt::Rails::DatadogFactory.make"
81
+ raise(MustBeCallableError.new(msg))
82
+ end
83
+ else
84
+ @statsd = Tpt::Rails::DatadogFactory.make(
85
+ statsd_url: datadog_statsd_url,
86
+ )
87
+ end
88
+
89
+ if datadog_disable_trace
90
+ Tpt::Rails::DatadogFactory.disable_tracing
91
+ elsif !datadog_trace_setup.nil?
92
+ if datadog_trace_setup.respond_to?(:call)
93
+ datadog_trace_setup.call
94
+ datadog_trace_setup = nil
95
+ else
96
+ msg = "datadog_trace_setup must be nil or callable. You should provide a lambda which calls Tpt::Rails::DatadogFactory.configure_tracing"
97
+ raise(MustBeCallableError.new(msg))
98
+ end
99
+ elsif datadog_trace_url
100
+ Tpt::Rails::DatadogFactory.configure_tracing(trace_url: datadog_trace_url)
101
+ end
63
102
 
64
103
  @health_checks.setup
65
104
 
@@ -71,7 +110,7 @@ class Tpt::Rails::Config
71
110
  end
72
111
 
73
112
  def statsd # :nodoc:
74
- @datadog.statsd
113
+ @statsd
75
114
  end
76
115
 
77
116
  def report(error) # :nodoc:
@@ -0,0 +1,116 @@
1
+ #
2
+ # Configures Datadog metrics and tracing
3
+ #
4
+
5
+ require 'datadog/statsd'
6
+ require 'ddtrace'
7
+
8
+ class Tpt::Rails::DatadogFactory
9
+ class DatadogFactoryNotConfigured < StandardError
10
+ def initialize(msg)
11
+ super(msg)
12
+ end
13
+ end
14
+
15
+ DEFAULT_STATSD_PORT = 8125
16
+ DEFAULT_TRACE_PORT = 8126
17
+
18
+ private_class_method :new
19
+
20
+ class << self
21
+ ###
22
+ # @description: Instantiates a datadog statsd instance. Note: has side effects, as it configures tracing.
23
+ # @param {statsd_url}: The url to sends stats to; if nil, a dummy url is used. Form: statsd://[host]:[port]
24
+ # @param {environment}: Wrapped in "env:#{environment}" and added to tags; if nil, Tpt::Rails.app_env is used;
25
+ # If using eg. reporting env this is where you put it
26
+ # @param {statsd_tags}: Set your own tags. If nil, default tags are used.
27
+ # If missing, no env tag is supplied, a default (optionally using environment param) is pushed into it.
28
+ # tpt-rails version is always pushed into it.
29
+ # @return {Datadog::Statsd}
30
+ ###
31
+ def make(statsd_url: nil, environment: nil, statsd_tags: nil)
32
+ if !Tpt::Rails::configured?
33
+ msg = "Tpt::Rails is not configured. Either run make after configuration, or set a lamda for config.datadog_statsd_setup which will defer setup."
34
+ raise(DatadogFactoryNotConfigured.new(msg))
35
+ end
36
+
37
+ statsd_tags = Array.wrap(statsd_tags)
38
+
39
+ # Fall back to a dummy client so callers don't have to worry about null checking the client
40
+ url = statsd_url || 'statsd://localhost'
41
+ uri = URI.parse(url)
42
+
43
+ tags = statsd_tags.nil? ? [] : statsd_tags
44
+ tags << "env:#{to_env(environment)}" unless tags.map { |t| t.split(':')[0] }.include?("env")
45
+ tags << "tpt-rails_release_version:#{Tpt::Rails.release_version}" if Tpt::Rails.release_version
46
+
47
+ ::Datadog::Statsd.new(
48
+ uri.host,
49
+ uri.port || DEFAULT_STATSD_PORT,
50
+ namespace: Tpt::Rails.app_name,
51
+ tags: tags,
52
+ )
53
+ end
54
+
55
+ def make_dummy
56
+ make
57
+ end
58
+
59
+ # @description: Configure tracing. Just passing trace_url: is enough for a basic config.
60
+ # @param {trace_url}: The url to send traces to; if nil, tracing is disabled. Form: datadog://[host]:[port]
61
+ # @param {trace_tags}: Set your own trace tags. If missing, default tags are used (optionally using environment param).
62
+ # @param {trace_debug}: boolean; passed to c.tracer enabled
63
+ # @param {&block}: Pass to set custom configuration for tracing as part of a .configure call.
64
+ # Accepts one parameter that is the configuration object.
65
+ def configure_tracing(trace_url: nil, environment:nil, trace_tags: nil, trace_debug: false)
66
+ if !Tpt::Rails::configured?
67
+ msg = "Tpt::Rails is not configured. Either run configure_tracing after configuration, or set a lamda for config.datadog_trace_setup which will defer setup."
68
+ raise(DatadogFactoryNotConfigured.new(msg))
69
+ end
70
+
71
+ uri = URI.parse(trace_url)
72
+ tags = { 'env' => to_env(environment) }
73
+ tags["tpt_release_version"] = Tpt::Rails.release_version if Tpt::Rails.release_version
74
+
75
+ ::Datadog.configure do |c|
76
+ # This will activate auto-instrumentation for Rails
77
+ c.use :rails, {
78
+ analytics_enabled: true,
79
+ service_name: Tpt::Rails.app_name,
80
+ }
81
+
82
+ c.tracer(
83
+ enabled: true,
84
+ debug: trace_debug,
85
+ hostname: uri.host,
86
+ port: uri.port || DEFAULT_TRACE_PORT,
87
+ tags: tags,
88
+ )
89
+
90
+ c.logger.level = ::Logger::WARN
91
+
92
+ yield(c) if block_given?
93
+ end
94
+
95
+ ::Datadog::Pipeline.before_flush(
96
+ ::Datadog::Pipeline::SpanFilter.new { |span|
97
+ span.resource =~ /TptRails::HealthChecksController/
98
+ },
99
+ )
100
+ end
101
+
102
+ def disable_tracing
103
+ ::Datadog.configure { |c| c.tracer(enabled: false) }
104
+ end
105
+
106
+ private
107
+
108
+ def to_env(environment)
109
+ if environment.nil?
110
+ Tpt::Rails.app_env
111
+ else
112
+ environment
113
+ end
114
+ end
115
+ end
116
+ end
@@ -1,6 +1,6 @@
1
1
  module Tpt
2
2
  module Rails
3
3
  # Do not change this manually. Our tooling will do it automatically.
4
- VERSION = '1.6.2'
4
+ VERSION = '1.7.1'
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tpt-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.2
4
+ version: 1.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - TpT
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-05 00:00:00.000000000 Z
11
+ date: 2022-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -114,6 +114,7 @@ files:
114
114
  - app/controllers/tpt/rails/error_tests_controller.rb
115
115
  - app/controllers/tpt/rails/health_checks_controller.rb
116
116
  - app/helpers/tpt/rails/application_helper.rb
117
+ - app/helpers/tpt/rails/event_bridge_test_helper.rb
117
118
  - app/jobs/tpt/rails/application_job.rb
118
119
  - app/mailers/tpt/rails/application_mailer.rb
119
120
  - app/models/tpt/rails/application_event.rb
@@ -147,9 +148,9 @@ files:
147
148
  - lib/generators/tpt/rails/postman/postman.yaml.tt
148
149
  - lib/tpt/rails.rb
149
150
  - lib/tpt/rails/config.rb
151
+ - lib/tpt/rails/datadog_factory.rb
150
152
  - lib/tpt/rails/engine.rb
151
153
  - lib/tpt/rails/internal.rb
152
- - lib/tpt/rails/internal/datadog.rb
153
154
  - lib/tpt/rails/internal/error_reporter.rb
154
155
  - lib/tpt/rails/internal/health_checks.rb
155
156
  - lib/tpt/rails/puma_stats_collector.rb
@@ -1,71 +0,0 @@
1
- #
2
- # Configures Datadog metrics and tracing, based on Tpt::Rails.config
3
- #
4
-
5
- require 'datadog/statsd'
6
- require 'ddtrace'
7
-
8
- class Tpt::Rails::Internal::Datadog # :nodoc:
9
- DEFAULT_STATSD_PORT = 8125
10
- DEFAULT_TRACE_PORT = 8126
11
-
12
- attr_reader :statsd
13
-
14
- def initialize(statsd_url: nil, trace_url: nil)
15
- @statsd_url = statsd_url
16
- @trace_url = trace_url
17
-
18
- @statsd = create_statsd
19
-
20
- if @trace_url
21
- configure_tracing
22
- end
23
- end
24
-
25
- private
26
-
27
- def create_statsd
28
- # Fall back to a dummy client so callers don't have to worry about null checking the client
29
- url = @statsd_url || 'statsd://localhost'
30
- uri = URI.parse(url)
31
-
32
- tags = ["env:#{Tpt::Rails.app_env}"]
33
- tags << ["tpt_release_version:#{Tpt::Rails.release_version}"] if Tpt::Rails.release_version
34
-
35
- ::Datadog::Statsd.new(
36
- uri.host,
37
- uri.port || DEFAULT_STATSD_PORT,
38
- namespace: Tpt::Rails.app_name,
39
- tags: tags,
40
- )
41
- end
42
-
43
- def configure_tracing
44
- uri = URI.parse(@trace_url)
45
- tags = { 'env' => Tpt::Rails.app_env }
46
- tags["tpt_release_version"] = Tpt::Rails.release_version if Tpt::Rails.release_version
47
-
48
- ::Datadog.configure do |c|
49
- # This will activate auto-instrumentation for Rails
50
- c.use :rails, {
51
- analytics_enabled: true,
52
- service_name: Tpt::Rails.app_name,
53
- }
54
-
55
- c.tracer(
56
- enabled: true,
57
- hostname: uri.host,
58
- port: uri.port || DEFAULT_TRACE_PORT,
59
- tags: tags,
60
- )
61
-
62
- c.logger.level = ::Logger::WARN
63
- end
64
-
65
- ::Datadog::Pipeline.before_flush(
66
- ::Datadog::Pipeline::SpanFilter.new { |span|
67
- span.resource =~ /TptRails::HealthChecksController/
68
- },
69
- )
70
- end
71
- end