airfoil 0.1.3 → 0.1.6

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: 147d3ae419196b330440e2a2c821668627eee5df6a7e9f4659fe2d399c944cf7
4
- data.tar.gz: 5ff9c18c639369e9ee451d6ce7d922ecf23cd174a687524eea518fb031221069
3
+ metadata.gz: f5d0cab534c94340e2f5ae6e1194dd0291afe19de6109ad79f27bbbea9519a8e
4
+ data.tar.gz: 9aa97b149fe14e60dc78991c840fc84ce76fe41445f9f39c69ce172664cc98f5
5
5
  SHA512:
6
- metadata.gz: 86246b400bb9a6b42a956f76062af1392e93514e7492f28f5a29d169f5307dac3fb9ac2dddf56467066a160ee9fb309b0468005454e1f6c179c014e8862618f9
7
- data.tar.gz: 4f71ed71afdaef2b7d720140301e67af1eb6376319d5937eee8d1d3e000e4a0e9990961c46b94d8dc74e4343fd6fec66b1c8ef6b4595e0470870d45e3f825231
6
+ metadata.gz: 58b9edadf1bf3574142c505021c817b2fb36af837f0d24b7afde4e195a2f43f6133ce430f6f64eb14d98c231520d07c9032b1cf0136820fe804f23ccd76d4ebb
7
+ data.tar.gz: be755c0312de69164538bfd26343a9250f0c64ce03ff65cad4a6e463c730e4ae4c3b8508e9a0b79393f2b59e484dd70b1aec2cf731a2496bafd6486a292f9fa8
data/README.md CHANGED
@@ -54,10 +54,41 @@ Existing middleware include:
54
54
 
55
55
  - `FunctionName` - dispatch any calls made to a specific Lambda function (by name) to a specified handler class
56
56
  - `LogEvent` - log AWS events in a pretty format
57
- - `SentryCatcher` - catch exceptions and report them to Sentry, including context
58
- - `SentryMonitoring` - instrument your function code for Sentry's performance monitoring
59
57
  - `SetRequestId` - set the `AWS_REQUEST_ID` environment variable for your function code
60
58
 
59
+
60
+ ## Additional Middleware
61
+ There are additional middleware available as separate gems that provide specific functionality. They must be explicitly added to your middleware stack in `create_stack`.
62
+
63
+ ### Sentry
64
+ Add the `airfoil-sentry` gem to your Gemfile.This provides three middlewares:
65
+
66
+ - `SentryCatcher` - catch exceptions and report them to Sentry, including context:
67
+ ```ruby
68
+ b.use Airfoil::Middleware::SentryCatcher
69
+ ```
70
+
71
+ - `SentryMonitoring` - instrument your function code for Sentry's performance monitoring
72
+ ```ruby
73
+ b.use Airfoil::Middleware::SentryMonitoring
74
+ ```
75
+
76
+ ### Datadog
77
+ Add the `airfoil-datadog` gem to your Gemfile. This provides a single middleware:
78
+
79
+ - `Datadog` - wire up the Datadog Lambda SDK and report traces to it
80
+ ```ruby
81
+ b.use Airfoil::Middleware::Datadog
82
+ ```
83
+
84
+ ### ActiveRecord
85
+ Add the `airfoil-activerecord` gem to your Gemfile. This provides a single middleware:
86
+
87
+ - `DatabaseConnection` - Check a connection in/out and enable the query cache per handler
88
+ ```ruby
89
+ b.use Airfoil::Middleware::DatabaseConnection
90
+ ```
91
+
61
92
  ## Development
62
93
 
63
94
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -1,33 +1,8 @@
1
1
  require "airfoil/cloudwatch_formatter"
2
- require "datadog/lambda"
3
2
 
4
3
  module Airfoil
5
4
  class Railtie < Rails::Railtie
6
5
  # Format logs for consistent parsing by Cloudwatch
7
6
  config.log_formatter = Airfoil::CloudwatchFormatter.new
8
- config.datadog_enabled = ENV.fetch("DATADOG_ENABLED", Rails.env.production?).to_s == "true"
9
-
10
- initializer "airfoil.datadog" do
11
- if Rails.configuration.datadog_enabled
12
- require "ddtrace/auto_instrument"
13
-
14
- ::Datadog::Lambda.configure_apm do |c|
15
- c.env = ENV.fetch("SENTRY_ENVIRONMENT", Rails.env).dasherize
16
- # downscasing first ensures we don't attempt to snake case things that don't already have dashes
17
- c.service = ENV.fetch("AWS_LAMBDA_FUNCTION_NAME", "brokersuite").downcase.underscore
18
-
19
- # Set trace rate via DD_TRACE_SAMPLE_RATE
20
- c.tracing.enabled = true
21
- c.tracing.instrument :aws
22
- c.tracing.instrument :faraday
23
- c.tracing.instrument :rest_client
24
- c.tracing.instrument :httpclient
25
- c.tracing.instrument :http
26
- c.tracing.instrument :rails
27
- end
28
-
29
- Rails.logger.debug "=====DATADOG LOADED (RAILTIE)====="
30
- end
31
- end
32
7
  end
33
8
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Airfoil
4
- VERSION = '0.1.3'
4
+ VERSION = '0.1.6'
5
5
  end
data/lib/airfoil.rb CHANGED
@@ -3,38 +3,35 @@
3
3
  require "middleware"
4
4
 
5
5
  require_relative "airfoil/version"
6
- require_relative "airfoil/middleware/database"
7
- require_relative "airfoil/middleware/datadog"
8
6
  require_relative "airfoil/middleware/function_name"
9
7
  require_relative "airfoil/middleware/log_event"
10
8
  require_relative "airfoil/middleware/logger_tagging"
11
- require_relative "airfoil/middleware/sentry_catcher"
12
- require_relative "airfoil/middleware/sentry_monitoring"
13
9
  require_relative "airfoil/middleware/set_request_id"
14
- require_relative "airfoil/middleware/step_function"
15
10
  require_relative "airfoil/logger_patch"
16
11
  require_relative "airfoil/railtie" if defined?(Rails::Railtie)
17
12
 
18
13
  module Airfoil
19
14
  class << self
20
- def create_stack
15
+ def create_stack(logger)
21
16
  # ensure that STDOUT streams are synchronous so we don't lose logs
22
17
  $stdout.sync = true
23
18
 
24
19
  Signal.trap("TERM") do
25
20
  # We can't use the Rails logger here as the logger is not available in the trap context
26
- puts "Received SIGTERM, shutting down gracefully..." # rubocop:disable Rails/Output
21
+ puts "Received SIGTERM, shutting down gracefully..."
27
22
  end
28
23
 
24
+ logger ||= defined?(::Rails) ? Rails.logger : Logger.new($stdout, level: (ENV["LOG_LEVEL"] || :info).to_sym)
25
+
29
26
  ::Middleware::Builder.new { |b|
30
- b.use Middleware::LoggerTagging, Rails.logger
27
+ if defined?(::Rails)
28
+ b.use Middleware::LoggerTagging, logger
29
+ end
31
30
  b.use Middleware::SetRequestId
32
- b.use Middleware::Datadog
33
- b.use Middleware::SentryCatcher, Rails.logger
34
- b.use Middleware::SentryMonitoring
35
- b.use Middleware::LogEvent, Rails.logger
31
+ # This is causing infinite recursion for some reason
32
+ # b.use Middleware::LogEvent, logger
36
33
  yield b
37
- }.inject_logger(Rails.logger)
34
+ }.inject_logger(logger)
38
35
  end
39
36
  end
40
37
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airfoil
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Highwing Engineering
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-10 00:00:00.000000000 Z
11
+ date: 2024-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: datadog-lambda
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: dry-monads
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -44,14 +30,14 @@ dependencies:
44
30
  requirements:
45
31
  - - "~>"
46
32
  - !ruby/object:Gem::Version
47
- version: 0.4.2
33
+ version: 0.4.3
48
34
  type: :runtime
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
38
  - - "~>"
53
39
  - !ruby/object:Gem::Version
54
- version: 0.4.2
40
+ version: 0.4.3
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: railties
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,20 +52,6 @@ dependencies:
66
52
  - - ">="
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: sentry-ruby
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
55
  - !ruby/object:Gem::Dependency
84
56
  name: aws_lambda_ric
85
57
  requirement: !ruby/object:Gem::Requirement
@@ -134,15 +106,10 @@ files:
134
106
  - lib/airfoil/cloudwatch_formatter.rb
135
107
  - lib/airfoil/logger_patch.rb
136
108
  - lib/airfoil/middleware/base.rb
137
- - lib/airfoil/middleware/database.rb
138
- - lib/airfoil/middleware/datadog.rb
139
109
  - lib/airfoil/middleware/function_name.rb
140
110
  - lib/airfoil/middleware/log_event.rb
141
111
  - lib/airfoil/middleware/logger_tagging.rb
142
- - lib/airfoil/middleware/sentry_catcher.rb
143
- - lib/airfoil/middleware/sentry_monitoring.rb
144
112
  - lib/airfoil/middleware/set_request_id.rb
145
- - lib/airfoil/middleware/step_function.rb
146
113
  - lib/airfoil/railtie.rb
147
114
  - lib/airfoil/version.rb
148
115
  homepage:
@@ -163,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
163
130
  - !ruby/object:Gem::Version
164
131
  version: '0'
165
132
  requirements: []
166
- rubygems_version: 3.4.17
133
+ rubygems_version: 3.4.6
167
134
  signing_key:
168
135
  specification_version: 4
169
136
  summary: Enough structure to get our Lambda handlers in the air
@@ -1,17 +0,0 @@
1
- require "airfoil/middleware/base"
2
-
3
- module Airfoil
4
- module Middleware
5
- class Database < Airfoil::Middleware::Base
6
- def call(env)
7
- # TODO: This explicitly makes a connection, which we may want to re-evaluate at some point
8
- ActiveRecord::Base.connection_pool.with_connection do |conn|
9
- conn.enable_query_cache!
10
- @app.call(env)
11
- ensure
12
- conn.disable_query_cache!
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,23 +0,0 @@
1
- require "datadog/lambda"
2
- require "datadog/tracing"
3
- require "airfoil/middleware/base"
4
-
5
- module Airfoil
6
- module Middleware
7
- class Datadog < Base
8
- # See the Airfoil railtie for config loaded at Rails load-time
9
- # Note: Rails loads prior to Airfoil because of the inclusion of `require_relative "config/environment"`
10
- # in the engine lambda handler
11
- def call(env)
12
- event, context = env.values_at(:event, :context)
13
-
14
- ::Datadog::Lambda.wrap(event, context) do
15
- @app.call(env)
16
- rescue => err
17
- ::Datadog::Tracing.active_span&.set_error(err)
18
- raise err
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,40 +0,0 @@
1
- require "sentry-ruby"
2
- require "airfoil/middleware/base"
3
-
4
- module Airfoil
5
- module Middleware
6
- class SentryCatcher < Base
7
- def initialize(app, logger)
8
- super(app)
9
- @logger = logger
10
- end
11
-
12
- def call(env)
13
- @app.call(env)
14
- rescue => err
15
- Sentry.with_scope do |scope|
16
- context = env[:context]
17
- event = env[:event]
18
-
19
- scope.set_extras(
20
- function_name: context.function_name,
21
- function_version: context.function_version,
22
- invoked_function_arn: context.invoked_function_arn,
23
- memory_limit_in_mb: context.memory_limit_in_mb,
24
- aws_request_id: context.aws_request_id,
25
- log_group_name: context.log_group_name,
26
- log_stream_name: context.log_stream_name,
27
- identity: context.identity,
28
- event: event
29
- )
30
-
31
- Sentry.capture_exception(err)
32
- @logger.error(err)
33
- raise err
34
- end
35
- end
36
- end
37
-
38
- class RequestError < StandardError; end
39
- end
40
- end
@@ -1,42 +0,0 @@
1
- require "sentry-ruby"
2
- require "airfoil/middleware/base"
3
-
4
- module Airfoil
5
- module Middleware
6
- class SentryMonitoring < Base
7
- def call(env)
8
- event, context = env.values_at(:event, :context)
9
- sentry_trace_id = get_first_instance(event, "sentry_trace_id")
10
- identity = get_first_instance(event, "identity")
11
-
12
- options = {name: context.function_name, op: "handler"}
13
- options[:transaction] = Sentry::Transaction.from_sentry_trace(sentry_trace_id, **options) if sentry_trace_id.present?
14
-
15
- Sentry.set_user(username: identity.dig("username"), ip_address: identity.dig("source_ip", 0)) if identity.present?
16
- transaction = Sentry.start_transaction(**options)
17
- # Add transaction to the global scope so it is accessible throughout the app
18
- Sentry.get_current_hub&.configure_scope do |scope|
19
- scope.set_span(transaction)
20
- end
21
-
22
- result = @app.call(env)
23
- transaction.finish if transaction.present?
24
-
25
- result
26
- end
27
-
28
- private
29
-
30
- def get_first_instance(event, key)
31
- case event
32
- in [e, *rest]
33
- e.dig(key)
34
- in Hash
35
- event.dig(key)
36
- else
37
- nil
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,37 +0,0 @@
1
- require_relative "function_name"
2
-
3
- module Airfoil
4
- module Middleware
5
- class StepFunction < FunctionName
6
- def initialize(app, handler_class, *function_names_to_match, retried_exceptions: [])
7
- super(app, handler_class, *function_names_to_match)
8
- @retried_exceptions = retried_exceptions.map(&:to_s)
9
- end
10
-
11
- def call(env)
12
- context = env[:context]
13
-
14
- ignore_exceptions(context) do
15
- super
16
- end
17
- end
18
-
19
- def ignore_exceptions(context)
20
- disable_exceptions
21
- result = yield
22
- enable_exceptions
23
-
24
- result
25
- end
26
-
27
- def disable_exceptions
28
- @before = Sentry.configuration.excluded_exceptions
29
- Sentry.configuration.excluded_exceptions += @retried_exceptions
30
- end
31
-
32
- def enable_exceptions
33
- Sentry.configuration.excluded_exceptions = @before
34
- end
35
- end
36
- end
37
- end