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 one_email_per_occurrence option and migration task #53

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7bc8480
Add one_email_per_occurrence option and migration task
imageaid Jul 17, 2024
9f18111
standard.rb fixes
imageaid Jul 17, 2024
b2e1ded
Adjustments from feedback on PR
imageaid Jul 18, 2024
319fa02
Refactor solid_errors_tasks.rake to remove hardcoded migrations
imageaid Jul 18, 2024
5fe0e51
Rework 'prev_resolved_at' from error_params
imageaid Jul 18, 2024
c47a881
Refactor email sending condition in SolidErrors
imageaid Jul 18, 2024
8719f90
Remove one_email_per_occurrence config option from SolidErrors
imageaid Jul 18, 2024
212e5ff
Better README update for explaining new behavior
imageaid Jul 18, 2024
b78a6e9
Make email sending condition consistent style; update migration copyi…
imageaid Jul 18, 2024
b728c2c
Update file existence check in solid_errors_tasks
imageaid Jul 18, 2024
20bf39a
Simplify file search in solid_errors_tasks rake task
imageaid Jul 19, 2024
3c41ab2
Update README.md
imageaid Jul 19, 2024
3f3ae1e
Update lib/tasks/solid_errors_tasks.rake
imageaid Jul 19, 2024
cf27fc6
Update lib/tasks/solid_errors_tasks.rake
imageaid Jul 19, 2024
e3fc454
Update README and solid_errors tasks
imageaid Jul 19, 2024
bac9123
Forgot to remove an underscore
imageaid Jul 19, 2024
32f3242
bumping version so I can test migration copying
imageaid Jul 22, 2024
3843711
a little more tweaking to test migration copy
imageaid Jul 22, 2024
7f4755c
another test run
imageaid Jul 22, 2024
3fad88f
version bump 0.4.3.003
imageaid Jul 23, 2024
0c16934
Merge branch 'main' into limited_emails_sent
fractaledmind Aug 22, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
/tmp/
.DS_Store
test/dummy/log/*.log
.idea
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ There are two ways to configure email notifications. First, you can use environm
ENV["SOLIDERRORS_SEND_EMAILS"] = true # defaults to false
ENV["SOLIDERRORS_EMAIL_FROM"] = "[email protected]" # defaults to "[email protected]"
ENV["SOLIDERRORS_EMAIL_TO"] = "[email protected]" # no default, must be set
ENV["SOLIDERRORS_ONE_EMAIL_PER_OCCURRENCE"] = false # defaults to false
```

Second, you can set the values via the configuration object:
Expand All @@ -144,10 +145,14 @@ Second, you can set the values via the configuration object:
config.solid_errors.send_emails = true
config.solid_errors.email_from = "[email protected]"
config.solid_errors.email_to = "[email protected]"
# Tell Solid Errors whether or not to limit the total emails per occurrence. Defaults to false.
config.solid_errors.one_email_per_occurrence = true
```

If you have set `send_emails` to `true` and have set an `email_to` address, Solid Errors will send an email notification whenever an error occurs. If you have not set `send_emails` to `true` or have not set an `email_to` address, Solid Errors will not send any email notifications.

If you have set `send_emails` to `true` and have set `one_email_per_occurrence` to `true`, Solid Errors will only send an email notification after the first occurrence of a new error or the first reoccurrence of a previously resolved error. If you have not set `one_email_per_occurrence` to `true`, Solid Errors will send an email notification for each occurrence of an error.
fractaledmind marked this conversation as resolved.
Show resolved Hide resolved

### Examples

There are only two screens in the dashboard.
Expand Down
13 changes: 12 additions & 1 deletion app/models/solid_errors/occurrence.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module SolidErrors
class Occurrence < Record
belongs_to :error, class_name: "SolidErrors::Error"

after_create_commit :send_email, if: -> { SolidErrors.send_emails? && SolidErrors.email_to.present? }
after_create_commit :send_email, if: :should_send_email?

# The parsed exception backtrace. Lines in this backtrace that are from installed gems
# have the base path for gem installs replaced by "[GEM_ROOT]", while those in the project
Expand All @@ -23,5 +23,16 @@ def parse_backtrace(backtrace)
def send_email
ErrorMailer.error_occurred(self).deliver_later
end

def should_send_email?
SolidErrors.send_emails? && SolidErrors.email_to.present? && under_limit?
end

def under_limit?
return true if error.occurrences.count == 1
imageaid marked this conversation as resolved.
Show resolved Hide resolved
return true if !SolidErrors.one_email_per_occurrence

error.occurrences.where(created_at: error.prev_resolved_at..).one?
end
fractaledmind marked this conversation as resolved.
Show resolved Hide resolved
end
end
7 changes: 7 additions & 0 deletions lib/solid_errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module SolidErrors
mattr_writer :username
mattr_writer :password
mattr_writer :send_emails
mattr_writer :one_email_per_occurrence
mattr_writer :email_from
mattr_writer :email_to

Expand All @@ -30,6 +31,12 @@ def send_emails?
@send_emails ||= ENV["SOLIDERRORS_SEND_EMAILS"] || @@send_emails || false
end

# only send one email per occurrence while the issue is Unresolved
# if the issue was resolved and then reoccurs, another email will be sent
def one_email_per_occurrence
@one_email_per_occurrence ||= ENV["SOLIDERRORS_ONE_EMAIL_PER_OCCURRENCE"] || @@one_email_per_occurrence || false
end

def email_from
@email_from ||= ENV["SOLIDERRORS_EMAIL_FROM"] || @@email_from || "[email protected]"
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddPrevResolvedAtToSolidErrors < ActiveRecord::Migration[6.1]
def change
add_column :solid_errors, :prev_resolved_at, :datetime
end
end
2 changes: 1 addition & 1 deletion lib/solid_errors/subscriber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def report(error, handled:, severity:, context:, source: nil)
}
fingerprint = Digest::SHA256.hexdigest(error_attributes.values.join)
if (record = SolidErrors::Error.find_by(fingerprint: fingerprint))
record.update!(resolved_at: nil, updated_at: Time.now)
record.update!(prev_resolved_at: record.resolved_at, resolved_at: nil, updated_at: Time.now)
fractaledmind marked this conversation as resolved.
Show resolved Hide resolved
else
record = SolidErrors::Error.create!(error_attributes.merge(fingerprint: fingerprint))
end
Expand Down
25 changes: 25 additions & 0 deletions lib/tasks/solid_errors_tasks.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace :solid_errors do
desc "Copy and run migrations from Solid Errors"
task install_migrations: :environment do
source = File.expand_path("../../solid_errors/db/migrate", __FILE__)
destination = File.join(Rails.root, "db", "migrate")
imageaid marked this conversation as resolved.
Show resolved Hide resolved

Dir.glob("#{source}/*.rb").each do |migration|
filename = File.basename(migration)
unless File.exist?(File.join(destination, filename))
puts "Copying #{filename} from Solid Errors to Rails application"
FileUtils.cp(migration, destination)
imageaid marked this conversation as resolved.
Show resolved Hide resolved
end
end
# this could be a way to "force" a migration to run in the future but
# the more thought into this, it seems too rigid and hard-coded
# Plus, after we copy the migration over, Rails will alert a user
# to run migrations/there are pending migrations.
# Set version for our specific migration
# ENV["VERSION"] = "20240716154238"
# Run just our specific migration file
# Rake::Task["db:migrate:up"].invoke
# Now clear that!
# ENV["VERSION"] = nil
fractaledmind marked this conversation as resolved.
Show resolved Hide resolved
end
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi, Rails Engines have this functionality built in. I don't use it in GoodJob, but that was more out of ignorance at the time than anything else.

https://guides.rubyonrails.org/engines.html#engine-setup

Solid Queue does it really well:

https://github.com/rails/solid_queue/blob/ac477d7b45f530026f36456ee114f223d86fd4ef/lib/generators/solid_queue/install/install_generator.rb

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really great! Thanks so much @bensheldon (particularly for the great write-up above!)

2 changes: 2 additions & 0 deletions solid_errors.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ Gem::Specification.new do |spec|

# For more information and examples about making a new gem, check out our
# guide at: https://bundler.io/guides/creating_gem.html

spec.post_install_message = "Remember to run `rails solid_errors:install_migrations` to copy *and* run new migrations."
fractaledmind marked this conversation as resolved.
Show resolved Hide resolved
end