Skip to content

Refactor Sentry error reporting pattern with flexible options across application layers#62

Merged
aaronbrethorst merged 8 commits intoOneBusAway:mainfrom
0xaboomar:main
Jun 17, 2025
Merged

Refactor Sentry error reporting pattern with flexible options across application layers#62
aaronbrethorst merged 8 commits intoOneBusAway:mainfrom
0xaboomar:main

Conversation

@0xaboomar
Copy link
Copy Markdown
Member

  • Refactored Sentry reporting to use a unified SentryReportOptions for passing tags, context, and severity level
  • Introduced ReportErrorWithSentryOptions to replace ad-hoc reporting calls with a consistent helper
  • Improved ConfigureScope to include goarch and renamed version tag to app_version
  • Renamed ReportIfProdReportError
  • Updated main application flow to consistently use the Reporter with the new pattern (GTFS download, config loading, cache creation)
  • Integrated Sentry reporting into collectMetricsForServer
  • Enhanced tests in main_test.go for Reporter integration

- Added `SentryReportOptions` struct to allow passing extra context, custom tags, and severity level.
- Introduced `ReportErrorWithSentryOptions` method for reporting with fine-grained control.
- Improved `ConfigureScope` by including `goarch` and renaming `version` tag to `app_version`.
- Renamed `ReportIfProd` to `ReportError` and removed environment check to allow caller control.
…pplication flow

- Add Reporter dependency to application struct and main functions
- Report errors to Sentry with tags and context across GTFS download, config loading, and cache directory creation
- Refactor main.go to pass Reporter to functions that can produce reportable errors
@coveralls
Copy link
Copy Markdown

coveralls commented Jun 15, 2025

Coverage Status

coverage: 67.407% (-3.4%) from 70.833%
when pulling a1bf3eb on Abo-Omar-74:main
into e5a84f4 on OneBusAway:main.

@aaronbrethorst aaronbrethorst requested a review from Copilot June 15, 2025 21:14
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors how Sentry error reporting is handled by introducing a unified options struct and updating all layers to use a consistent reporting helper.

  • Introduces SentryReportOptions and ReportErrorWithSentryOptions
  • Renames ReportIfProdReportError and standardizes Sentry scope tags (e.g., app_version, goarch)
  • Injects Reporter into main, metrics, and test code and updates function signatures accordingly

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
internal/report/reporter.go Added SentryReportOptions type, ReportErrorWithSentryOptions, updated ReportError and scope configuration
cmd/watchdog/metrics.go Replaced ad-hoc Sentry calls with ReportErrorWithSentryOptions in collectMetricsForServer
cmd/watchdog/main_test.go Injected Reporter into tests and updated calls to loader functions
cmd/watchdog/main.go Wired reporter through application, updated function signatures, set up and flushed Sentry
Comments suppressed due to low confidence (2)

internal/report/reporter.go:7

  • This file uses runtime.Version(), runtime.GOARCH, and os.Hostname(), but neither runtime nor os are imported. Add "runtime" and "os" to the import block to avoid compile errors.
import (

internal/report/reporter.go:70

  • Consider adding unit tests for ReportError and ReportErrorWithSentryOptions to verify that tags, context, and default level behaviors are applied correctly.
type SentryReportOptions struct {

Comment on lines +91 to +93
if opts.Level != "" {
scope.SetLevel(opts.Level)
}
Copy link

Copilot AI Jun 15, 2025

Choose a reason for hiding this comment

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

[nitpick] If no level is provided (opts.Level is zero), no level is set on the scope. Consider defaulting opts.Level to sentry.LevelError before this check so every reported error has an explicit severity.

Suggested change
if opts.Level != "" {
scope.SetLevel(opts.Level)
}
level := opts.Level
if level == "" {
level = sentry.LevelError
}
scope.SetLevel(level)

Copilot uses AI. Check for mistakes.
Comment thread cmd/watchdog/main_test.go Outdated
tmpFile.Close()

servers, err := loadConfigFromFile(tmpFile.Name())
servers, err := loadConfigFromFile(tmpFile.Name() , reporter)
Copy link

Copilot AI Jun 15, 2025

Choose a reason for hiding this comment

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

[nitpick] There’s a stray space before the comma in the function call. Removing it (tmpFile.Name(), reporter) will keep the code consistent with standard Go formatting.

Suggested change
servers, err := loadConfigFromFile(tmpFile.Name() , reporter)
servers, err := loadConfigFromFile(tmpFile.Name(), reporter)

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

@aaronbrethorst aaronbrethorst left a comment

Choose a reason for hiding this comment

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

code looks good! I have some nitpicks I'd like to see addressed before merging, but this is good work! 👍

Comment thread cmd/watchdog/main.go Outdated

cacheDir := "cache"
if err = createCacheDirectory(cacheDir, logger); err != nil {
if err = createCacheDirectory(cacheDir, logger , reporter); err != nil {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

there's an extra space in between logger and the comma. it should look like this: logger, reporter

Comment thread cmd/watchdog/main.go Outdated

// Download GTFS bundles for all servers on startup
downloadGTFSBundles(servers, cacheDir, logger)
downloadGTFSBundles(servers, cacheDir, logger , reporter)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

there's an extra space in between logger and the comma. it should look like this: logger, reporter.

Comment thread cmd/watchdog/main.go Outdated

// Cron job to download GTFS bundles for all servers every 24 hours
go refreshGTFSBundles(servers, cacheDir, logger , 24 * time.Hour)
go refreshGTFSBundles(servers, cacheDir, logger , 24 * time.Hour , reporter)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

there's an extra space in between logger and the comma. it should look like this: logger, reporter

Comment thread cmd/watchdog/main.go
if err != nil {
if os.IsNotExist(err){
if err := os.MkdirAll(cacheDir, os.ModePerm); err != nil {
reporter.ReportErrorWithSentryOptions(err, report.SentryReportOptions{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think you need to run go fmt on this code. the indentation is strange.

Comment thread cmd/watchdog/main.go
}
if !stat.IsDir() {
return fmt.Errorf("%s is not a directory", cacheDir)
err := fmt.Errorf("%s is not a directory", cacheDir)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same here on formatting.

Comment thread cmd/watchdog/main.go Outdated
_, err := utils.DownloadGTFSBundle(server.GtfsUrl, cacheDir, server.ID, hashStr)
if err != nil {
reporter.ReportErrorWithSentryOptions(err, report.SentryReportOptions{
Tags: map[string]string{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indentation

Comment thread cmd/watchdog/main.go Outdated

// refreshGTFSBundles periodically downloads GTFS bundles at the specified interval.
func refreshGTFSBundles(servers []models.ObaServer, cacheDir string, logger *slog.Logger , interval time.Duration) {
func refreshGTFSBundles(servers []models.ObaServer, cacheDir string, logger *slog.Logger , interval time.Duration , reporter *report.Reporter) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

watch those extra spaces again ,, here and throughout the function below

Comment thread cmd/watchdog/main.go Outdated
newServers, err := loadConfigFromURL(configURL, configAuthUser, configAuthPass , reporter)
if err != nil {
reporter.ReportErrorWithSentryOptions(err, report.SentryReportOptions{
Tags: map[string]string{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

you're creating these map[string]string types a lot here for maps with a single key/value pair. I recommend creating a helper function that can generate them for you. it'll make the code more readable:

func makeMap(key, value string) map[string]string {
  return map[string]string{ key: value }
}

Comment thread cmd/watchdog/main.go
func loadConfigFromFile(filePath string , reporter *report.Reporter) ([]models.ObaServer, error) {
data, err := os.ReadFile(filePath)
if err != nil {
reporter.ReportErrorWithSentryOptions(err, report.SentryReportOptions{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

formatting

Comment thread cmd/watchdog/main.go

var servers []models.ObaServer
if err := json.Unmarshal(data, &servers); err != nil {
reporter.ReportErrorWithSentryOptions(err, report.SentryReportOptions{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

formatting

Copy link
Copy Markdown
Member

@aaronbrethorst aaronbrethorst left a comment

Choose a reason for hiding this comment

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

Lgtm!

@aaronbrethorst aaronbrethorst merged commit 578749c into OneBusAway:main Jun 17, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants