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

Add on_breadcrumb callbacks to replace before_breadcrumb_callbacks #686

Merged
merged 6 commits into from
Aug 23, 2021
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ Changelog
* Sessions will now be delivered every 10 seconds, instead of every 30 seconds
| [#680](https://github.com/bugsnag/bugsnag-ruby/pull/680)

* Add `on_breadcrumb` callbacks to replace `before_breadcrumb_callbacks`
| [#686](https://github.com/bugsnag/bugsnag-ruby/pull/686)

### Fixes

* Avoid starting session delivery thread when the current release stage is not enabled
| [#677](https://github.com/bugsnag/bugsnag-ruby/pull/677)

### Deprecated

* `before_breadcrumb_callbacks` have been deprecated in favour of `on_breadcrumb` callbacks and will be removed in the next major release
* For consistency with Bugsnag notifiers for other languages, a number of methods have been deprecated in this release. The old options will be removed in the next major version | [#676](https://github.com/bugsnag/bugsnag-ruby/pull/676)
* The `notify_release_stages` configuration option has been deprecated in favour of `enabled_release_stages`
* The `auto_capture_sessions` and `track_sessions` configuration options have been deprecated in favour of `auto_track_sessions`
Expand Down
33 changes: 32 additions & 1 deletion lib/bugsnag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def leave_breadcrumb(name, meta_data={}, type=Bugsnag::Breadcrumbs::MANUAL_BREAD
# Skip if it's already invalid
return if breadcrumb.ignore?

# Run callbacks
# Run before_breadcrumb_callbacks
configuration.before_breadcrumb_callbacks.each do |c|
c.arity > 0 ? c.call(breadcrumb) : c.call
break if breadcrumb.ignore?
Expand All @@ -261,6 +261,10 @@ def leave_breadcrumb(name, meta_data={}, type=Bugsnag::Breadcrumbs::MANUAL_BREAD
# Return early if ignored
return if breadcrumb.ignore?

# Run on_breadcrumb callbacks
configuration.on_breadcrumb_callbacks.call(breadcrumb)
return if breadcrumb.ignore?

# Validate again in case of callback alteration
validator.validate(breadcrumb)

Expand Down Expand Up @@ -295,6 +299,33 @@ def remove_on_error(callback)
configuration.remove_on_error(callback)
end

##
# Add the given callback to the list of on_breadcrumb callbacks
#
# The on_breadcrumb callbacks will be called when a breadcrumb is left and
# are passed the {Breadcrumbs::Breadcrumb Breadcrumb} object
#
# Returning false from an on_breadcrumb callback will cause the breadcrumb
# to be ignored and will prevent any remaining callbacks from being called
#
# @param callback [Proc, Method, #call]
# @return [void]
def add_on_breadcrumb(callback)
configuration.add_on_breadcrumb(callback)
end

##
# Remove the given callback from the list of on_breadcrumb callbacks
#
# Note that this must be the same instance that was passed to
# {add_on_breadcrumb}, otherwise it will not be removed
#
# @param callback [Proc, Method, #call]
# @return [void]
def remove_on_breadcrumb(callback)
configuration.remove_on_breadcrumb(callback)
end

##
# Returns the client's Cleaner object, or creates one if not yet created.
#
Expand Down
50 changes: 50 additions & 0 deletions lib/bugsnag/breadcrumbs/on_breadcrumb_callback_list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require "set"

module Bugsnag::Breadcrumbs
class OnBreadcrumbCallbackList
def initialize(configuration)
@callbacks = Set.new
@mutex = Mutex.new
@configuration = configuration
end

##
# @param callback [Proc, Method, #call]
# @return [void]
def add(callback)
@mutex.synchronize do
@callbacks.add(callback)
end
end

##
# @param callback [Proc, Method, #call]
# @return [void]
def remove(callback)
@mutex.synchronize do
@callbacks.delete(callback)
end
end

##
# @param breadcrumb [Breadcrumb]
# @return [void]
def call(breadcrumb)
@callbacks.each do |callback|
begin
should_continue = callback.call(breadcrumb)
rescue StandardError => e
@configuration.warn("Error occurred in on_breadcrumb callback: '#{e}'")
@configuration.warn("on_breadcrumb callback stacktrace: #{e.backtrace.inspect}")
end

# only stop if should_continue is explicity 'false' to allow callbacks
# to return 'nil'
if should_continue == false
breadcrumb.ignore!
break
end
end
end
end
end
34 changes: 34 additions & 0 deletions lib/bugsnag/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
require "bugsnag/middleware/breadcrumbs"
require "bugsnag/utility/circular_buffer"
require "bugsnag/breadcrumbs/breadcrumbs"
require "bugsnag/breadcrumbs/on_breadcrumb_callback_list"

module Bugsnag
class Configuration
Expand Down Expand Up @@ -148,6 +149,11 @@ class Configuration
# @return [Array<String>]
attr_reader :scopes_to_filter

# Expose on_breadcrumb_callbacks internally for Bugsnag.leave_breadcrumb
# @api private
# @return [Breadcrumbs::OnBreadcrumbCallbackList]
attr_reader :on_breadcrumb_callbacks

API_KEY_REGEX = /[0-9a-f]{32}/i
THREAD_LOCAL_NAME = "bugsnag_req_data"

Expand Down Expand Up @@ -196,6 +202,7 @@ def initialize
# All valid breadcrumb types should be allowable initially
self.enabled_automatic_breadcrumb_types = Bugsnag::Breadcrumbs::VALID_BREADCRUMB_TYPES.dup
self.before_breadcrumb_callbacks = []
@on_breadcrumb_callbacks = Breadcrumbs::OnBreadcrumbCallbackList.new(self)

# Store max_breadcrumbs here instead of outputting breadcrumbs.max_items
# to avoid infinite recursion when creating breadcrumb buffer
Expand Down Expand Up @@ -506,6 +513,33 @@ def remove_on_error(callback)
middleware.remove(callback)
end

##
# Add the given callback to the list of on_breadcrumb callbacks
#
# The on_breadcrumb callbacks will be called when a breadcrumb is left and
# are passed the {Breadcrumbs::Breadcrumb Breadcrumb} object
#
# Returning false from an on_breadcrumb callback will cause the breadcrumb
# to be ignored and will prevent any remaining callbacks from being called
#
# @param callback [Proc, Method, #call]
# @return [void]
def add_on_breadcrumb(callback)
@on_breadcrumb_callbacks.add(callback)
end

##
# Remove the given callback from the list of on_breadcrumb callbacks
#
# Note that this must be the same instance that was passed to
# {add_on_breadcrumb}, otherwise it will not be removed
#
# @param callback [Proc, Method, #call]
# @return [void]
def remove_on_breadcrumb(callback)
@on_breadcrumb_callbacks.remove(callback)
end

# TODO: These methods can be a simple attr_accessor when they replace the
# methods they are aliasing
# NOTE: they are not aliases as YARD doesn't allow documenting the non-alias
Expand Down
Loading