Skip to content

Conversation

rabidpraxis
Copy link
Contributor

@rabidpraxis rabidpraxis commented Oct 8, 2025

Status

WIP

Description

Adds Honeybadger Insights events support with batching, retry logic, and throttling. Events
are queued and sent asynchronously in configurable batches. Includes BeforeEvent hooks for
filtering/modifying events before sending.

Key features:

  • Asynchronous event batching with configurable batch size and timeout
  • Retry logic with configurable max attempts
  • Throttling support (429/503) with backoff
  • Queue size limits with automatic dropping of oldest events
  • BeforeEvent callbacks for modification and filtering
  • Zerolog adapter for sending logs as events
  • Updated GH test matrix to only run against supported versions

Related PRs

None

Todos

  • Tests
  • Documentation
  • More consistent logging
  • ENV var config settings
  • Event context API
  • Dropped events periodic logging
  • Godoc comments on exported types
  • slog adapter
  • logrus adapter (maybe)
  • Changelog Entry (unreleased)

@rabidpraxis rabidpraxis requested a review from Copilot October 8, 2025 16:08
Copy link

@Copilot 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 adds Honeybadger Insights events support with asynchronous batching, retry logic, and throttling capabilities. Events are queued and sent in configurable batches with support for filtering/modification through BeforeEvent hooks.

Key changes:

  • Event batching system with configurable batch size and timeout
  • Retry logic with exponential backoff and throttling support
  • Queue management with automatic dropping of oldest events when at capacity
  • BeforeEvent callback system for event filtering and modification
  • Zerolog adapter for sending logs as Insights events

Reviewed Changes

Copilot reviewed 17 out of 19 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
event.go Defines event payload structure and creation logic
events_worker.go Implements asynchronous event batching and sending worker
ring_buffer.go Provides circular buffer for efficient event queuing
client.go Adds Event method and BeforeEvent handler support
configuration.go Adds events-related configuration options
server.go Updates HTTP client to support events endpoint and JSONL format
honeybadger.go Adds public Event and BeforeEvent functions
null_backend.go Adds Event method to null backend implementation
zerolog/ New zerolog adapter package for sending logs as events
go.mod Updates Go version and dependencies
README.md Documents new events functionality
Makefile Updates linting tools
*_test.go Comprehensive test coverage for events functionality

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

case 403:
return ErrUnauthorized
default:
bodyBytes, _ := ioutil.ReadAll(resp.Body)
Copy link

Copilot AI Oct 8, 2025

Choose a reason for hiding this comment

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

The ioutil package is deprecated since Go 1.16. Use io.ReadAll instead.

Copilot uses AI. Check for mistakes.

Comment on lines +606 to +614
fmt.Println("First attempt", string(req1.Body))
req1.Response <- 500

req2 := <-control
fmt.Println("Second attempt", string(req2.Body))
req2.Response <- 500

req3 := <-control
fmt.Println("Third attempt", string(req3.Body))
Copy link

Copilot AI Oct 8, 2025

Choose a reason for hiding this comment

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

Debug print statements should be removed from test code or replaced with proper test logging using t.Logf().

Suggested change
fmt.Println("First attempt", string(req1.Body))
req1.Response <- 500
req2 := <-control
fmt.Println("Second attempt", string(req2.Body))
req2.Response <- 500
req3 := <-control
fmt.Println("Third attempt", string(req3.Body))
t.Logf("First attempt %s", string(req1.Body))
req1.Response <- 500
req2 := <-control
t.Logf("Second attempt %s", string(req2.Body))
req2.Response <- 500
req3 := <-control
t.Logf("Third attempt %s", string(req3.Body))

Copilot uses AI. Check for mistakes.

Comment on lines +606 to +614
fmt.Println("First attempt", string(req1.Body))
req1.Response <- 500

req2 := <-control
fmt.Println("Second attempt", string(req2.Body))
req2.Response <- 500

req3 := <-control
fmt.Println("Third attempt", string(req3.Body))
Copy link

Copilot AI Oct 8, 2025

Choose a reason for hiding this comment

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

Debug print statements should be removed from test code or replaced with proper test logging using t.Logf().

Suggested change
fmt.Println("First attempt", string(req1.Body))
req1.Response <- 500
req2 := <-control
fmt.Println("Second attempt", string(req2.Body))
req2.Response <- 500
req3 := <-control
fmt.Println("Third attempt", string(req3.Body))
t.Logf("First attempt %s", string(req1.Body))
req1.Response <- 500
req2 := <-control
t.Logf("Second attempt %s", string(req2.Body))
req2.Response <- 500
req3 := <-control
t.Logf("Third attempt %s", string(req3.Body))

Copilot uses AI. Check for mistakes.

Comment on lines +606 to +614
fmt.Println("First attempt", string(req1.Body))
req1.Response <- 500

req2 := <-control
fmt.Println("Second attempt", string(req2.Body))
req2.Response <- 500

req3 := <-control
fmt.Println("Third attempt", string(req3.Body))
Copy link

Copilot AI Oct 8, 2025

Choose a reason for hiding this comment

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

Debug print statements should be removed from test code or replaced with proper test logging using t.Logf().

Suggested change
fmt.Println("First attempt", string(req1.Body))
req1.Response <- 500
req2 := <-control
fmt.Println("Second attempt", string(req2.Body))
req2.Response <- 500
req3 := <-control
fmt.Println("Third attempt", string(req3.Body))
t.Logf("First attempt %s", string(req1.Body))
req1.Response <- 500
req2 := <-control
t.Logf("Second attempt %s", string(req2.Body))
req2.Response <- 500
req3 := <-control
t.Logf("Third attempt %s", string(req3.Body))

Copilot uses AI. Check for mistakes.

maxQueueSize: cfg.EventsMaxQueueSize,
maxRetries: cfg.EventsMaxRetries,
throttleWait: cfg.EventsThrottleWait,
logger: cfg.Logger,
Copy link

Copilot AI Oct 8, 2025

Choose a reason for hiding this comment

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

The magic number '+1' appears twice without explanation. Consider adding a comment explaining why the buffer size is batch size + 1.

Suggested change
logger: cfg.Logger,
logger: cfg.Logger,
// The ring buffer size is batchSize + 1 to distinguish full from empty states.

Copilot uses AI. Check for mistakes.

if len(events) > 0 {
w.batches = append(w.batches, &Batch{events: events, attempts: 0})
}
w.queue = newRingBuffer(w.batchSize + 1)
Copy link

Copilot AI Oct 8, 2025

Choose a reason for hiding this comment

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

The magic number '+1' appears twice without explanation. Consider adding a comment explaining why the buffer size is batch size + 1.

Copilot uses AI. Check for mistakes.

Comment on lines +15 to +17
if q.size == q.cap {
return false
} // full
Copy link

Copilot AI Oct 8, 2025

Choose a reason for hiding this comment

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

[nitpick] The comment '// full' should be on the same line as the if statement or properly formatted as a block comment for better readability.

Suggested change
if q.size == q.cap {
return false
} // full
if q.size == q.cap { // full
return false
}

Copilot uses AI. Check for mistakes.

Only run tests against the supported runtimes & add blurb about it in
the README.
@rabidpraxis rabidpraxis changed the title Insights events feat(insights): add events support Oct 8, 2025
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.

1 participant