Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Sinatra instrumentation causing boot loop #1105

Merged
merged 1 commit into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changesets/don-t-start-for-sinatra-if-already-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
bump: patch
type: fix
---

Fix issue with AppSignal getting stuck in a boot loop when loading the Sinatra integration with: `require "appsignal/integrations/sinatra"`
This could happen in nested applications, like a Sinatra app in a Rails app. It will now use the first config AppSignal starts with.
16 changes: 9 additions & 7 deletions lib/appsignal/integrations/sinatra.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@

Appsignal.internal_logger.debug("Loading Sinatra (#{Sinatra::VERSION}) integration")

app_settings = ::Sinatra::Application.settings
Appsignal.config = Appsignal::Config.new(
app_settings.root || Dir.pwd,
app_settings.environment
)
unless Appsignal.active?
app_settings = ::Sinatra::Application.settings
Appsignal.config = Appsignal::Config.new(
app_settings.root || Dir.pwd,
app_settings.environment
)

Appsignal.start_logger
Appsignal.start
Appsignal.start_logger
Appsignal.start
end

::Sinatra::Base.use(Appsignal::Rack::SinatraBaseInstrumentation) if Appsignal.active?
90 changes: 57 additions & 33 deletions spec/lib/appsignal/integrations/sinatra_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,59 +13,83 @@ def uninstall_sinatra_integration
end

describe "Sinatra integration" do
before { allow(Appsignal).to receive(:active?).and_return(true) }
before do
Appsignal.config = nil
end
after { uninstall_sinatra_integration }

context "Appsignal.internal_logger" do
subject { Appsignal.internal_logger }
context "when active" do
before { allow(Appsignal).to receive(:active?).and_return(true) }

it "does not start AppSignal again" do
expect(Appsignal::Config).to_not receive(:new)
expect(Appsignal).to_not receive(:start)
expect(Appsignal).to_not receive(:start_logger)
install_sinatra_integration
end

it "sets a logger" do
it "adds the instrumentation middleware to Sinatra::Base" do
install_sinatra_integration
is_expected.to be_a Logger
expect(Sinatra::Base.middleware.to_a).to include(
[Appsignal::Rack::SinatraBaseInstrumentation, [], nil]
)
end
end

describe "middleware" do
context "when AppSignal is not active" do
before { allow(Appsignal).to receive(:active?).and_return(false) }
context "when not active" do
context "Appsignal.internal_logger" do
subject { Appsignal.internal_logger }

it "does not add the instrumentation middleware to Sinatra::Base" do
it "sets a logger" do
install_sinatra_integration
expect(Sinatra::Base.middleware.to_a).to_not include(
[Appsignal::Rack::SinatraBaseInstrumentation, [], nil]
)
is_expected.to be_a Logger
end
end

context "when AppSignal is active" do
it "adds the instrumentation middleware to Sinatra::Base" do
install_sinatra_integration
expect(Sinatra::Base.middleware.to_a).to include(
[Appsignal::Rack::SinatraBaseInstrumentation, [], nil]
)
describe "middleware" do
context "when AppSignal is not active" do
it "does not add the instrumentation middleware to Sinatra::Base" do
install_sinatra_integration
expect(Sinatra::Base.middleware.to_a).to_not include(
[Appsignal::Rack::SinatraBaseInstrumentation, [], nil]
)
end
end
end
end

describe "environment" do
subject { Appsignal.config.env }

context "without APPSIGNAL_APP_ENV" do
before { install_sinatra_integration }
context "when the new AppSignal config is active" do
it "adds the instrumentation middleware to Sinatra::Base" do
ENV["APPSIGNAL_APP_NAME"] = "My Sinatra app name"
ENV["APPSIGNAL_APP_ENV"] = "test"
ENV["APPSIGNAL_PUSH_API_KEY"] = "my-key"

it "uses the app environment" do
expect(subject).to eq("test")
install_sinatra_integration
expect(Sinatra::Base.middleware.to_a).to include(
[Appsignal::Rack::SinatraBaseInstrumentation, [], nil]
)
end
end
end

context "with APPSIGNAL_APP_ENV" do
before do
ENV["APPSIGNAL_APP_ENV"] = "env-staging"
install_sinatra_integration
describe "environment" do
subject { Appsignal.config.env }

context "without APPSIGNAL_APP_ENV" do
before { install_sinatra_integration }

it "uses the app environment" do
expect(subject).to eq("test")
end
end

it "uses the environment variable" do
expect(subject).to eq("env-staging")
context "with APPSIGNAL_APP_ENV" do
before do
ENV["APPSIGNAL_APP_ENV"] = "env-staging"
install_sinatra_integration
end

it "uses the environment variable" do
expect(subject).to eq("env-staging")
end
end
end
end
Expand Down