airfoil 0.1.3 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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