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 +4 -4
- data/README.md +33 -2
- data/lib/airfoil/railtie.rb +0 -25
- data/lib/airfoil/version.rb +1 -1
- data/lib/airfoil.rb +10 -13
- metadata +5 -38
- data/lib/airfoil/middleware/database.rb +0 -17
- data/lib/airfoil/middleware/datadog.rb +0 -23
- data/lib/airfoil/middleware/sentry_catcher.rb +0 -40
- data/lib/airfoil/middleware/sentry_monitoring.rb +0 -42
- data/lib/airfoil/middleware/step_function.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5d0cab534c94340e2f5ae6e1194dd0291afe19de6109ad79f27bbbea9519a8e
|
4
|
+
data.tar.gz: 9aa97b149fe14e60dc78991c840fc84ce76fe41445f9f39c69ce172664cc98f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
data/lib/airfoil/railtie.rb
CHANGED
@@ -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
|
data/lib/airfoil/version.rb
CHANGED
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..."
|
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
|
-
|
27
|
+
if defined?(::Rails)
|
28
|
+
b.use Middleware::LoggerTagging, logger
|
29
|
+
end
|
31
30
|
b.use Middleware::SetRequestId
|
32
|
-
|
33
|
-
b.use Middleware::
|
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(
|
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.
|
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:
|
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.
|
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.
|
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.
|
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
|