Warn instead of failing on a blank source token, and when the Better Stack logger isn't used - #63
Merged
Merged
Conversation
A nil or empty token makes create_default_logger raise while the app boots, which breaks e.g. assets:precompile in a Docker build without the token. And when config.logger is set again after config/application.rb, as the generated production.rb does on Rails 7.1 and newer, nothing tells the app that its logs no longer reach Better Stack. The boot cases run in subprocesses, since booting patches Rails classes for the whole process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Logtail:" also matches "Logtail::Logger" inside the warnings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Stack logger isn't used create_default_logger with a nil or blank token prints a warning and returns the STDOUT logger it uses in the test environment and with LOGTAIL_SKIP_LOGS, so the app still boots. Once the app has booted, the Railtie warns when create_default_logger built a Better Stack logger but Rails.logger neither is a Logtail::Logger nor broadcasts to one, which is what happens when config.logger is set again in config/environments/production.rb. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
logtail-rack 0.2.8 times responses with the monotonic clock, which Timecop doesn't freeze, so "Completed 200 OK in 0.0ms" no longer holds. The last CI run on main still resolved logtail-rack 0.2.7. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
config/application.rb creates the logger in every environment, so an environment that turns the integration off, e.g. development with config.logtail.enabled = false, may well have no token. The empty string case now boots an app too, like the missing token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tion on create_default_logger now only records the blank token, and the Railtie's after-boot check prints the warning, so it appears once per boot even if the logger is created twice, and not in environments that turn the integration off and don't need the token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PetrHeinz
marked this pull request as ready for review
October 2, 2026 09:22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two ways a Rails app ends up without its logs in Better Stack, or fails to boot at all, without the gem saying why:
Logtail::Logger.create_default_loggerraiseArgumentError: The source_token parameter cannot be blankwhile the app boots. This breaksassets:precompilein the Rails 8 Dockerfile, where the token isn't available. The red-team'sbin/rails assets:precompilewithout the token aborted with exactly that error.config.logger = ActiveSupport::TaggedLogging.logger(STDOUT)inconfig/environments/production.rbruns afterconfig/application.rband replaces the Better Stack logger. OnlyRails.eventrows reach Better Stack, and nothing points at the cause. The same happens on Rails 6.1 and 7.0 withRAILS_LOG_TO_STDOUT. The red-team saw it on all seven Rails versions it tested; on 8.1,Rails.loggerwas aBroadcastLoggerwhose only broadcast was the STDOUTActiveSupport::Logger.What changes:
create_default_loggerreturns the STDOUT logger it already uses in the test environment and withLOGTAIL_SKIP_LOGS, instead of raising. Those two cases don't need the token, so nothing changes for them.create_default_loggergot a blank token;Rails.loggerneither is aLogtail::Loggernor broadcasts to one. The warning names the likely cause:config.loggerset again later, e.g. inconfig/environments/production.rb.after_initializeblocks, which may still add the logger withbroadcast_to.config.logtail.enabled = falsefrom Add config.logtail.enabled to turn the integration off per environment #60, orLogtail::Integrations::Rails.enabled = false).config/application.rbcreates the logger in every environment, and e.g. development often has no token. That's why the blank-token warning waits until the app has booted instead of being printed bycreate_default_loggeritself. It also means the warning appears once per boot, even when the logger is created twice.ActiveSupport::Logger.broadcastextends the logger with an anonymous module that doesn't reveal its target. When such a module is present, the check stays quiet rather than risk a false warning.Warnings go through
Kernel#warn, never through the Logtail logger:Behaviour and compatibility:
The boot cases run in subprocesses, because booting patches Rails classes for the whole process: a missing token, an empty token, a missing token with the integration turned off, an overridden
config.logger, a broadcast to the Better Stack logger (BroadcastLoggeron Rails 7.1+,ActiveSupport::Logger.broadcastbefore), and the documented setup.This targets the 0.3.0 minor; merge after 0.2.15 is released. No dependencies.
The commit "Expect real response durations in the request specs" is the same change as in #59: logtail-rack 0.2.8 times responses with the monotonic clock, which Timecop doesn't freeze, so three existing specs now fail on every branch based on main. It's identical in both PRs, so it merges cleanly whichever lands first.
The first commit only adds the tests and is expected to fail on CI. The implementation follows in the later commits.
🤖 Generated with Claude Code