Debug events
A Debug event is delivered only while the producer’s debug mode is on. While it is off, SendEvent drops the event and returns nil, before the capture time is stamped and before anything reaches the channel.
That is the point of the type. Debug calls can stay in the code on the path you need them on, and the cost of leaving them there is one atomic load plus whatever you spent building the event.
package main
import ( "context" "log"
"github.com/kataras/patrol")
func main() { ctx := context.Background() producer := patrol.NewProducer(patrol.ProducerOptions{ProjectName: "checkout-api"}) defer producer.Close(ctx)
// Dropped: debug mode is off. Returns nil. if err := producer.SendEvent(ctx, patrol.NewEvent(patrol.Debug).WithMessage("cache miss")); err != nil { log.Println(err) }
producer.Debug(true)
// Delivered. if err := producer.SendEvent(ctx, patrol.NewEvent(patrol.Debug).WithMessage("cache miss")); err != nil { log.Println(err) }}patrol.NewEvent(patrol.Debug) sets the type and nothing else. event.WithDebug("message") sets the type, the message and a fresh stacktrace in one call, which is what you want when the interesting part is where the code was.
Turning it on
Section titled “Turning it on”producer.Debug(true) turns debug mode on for the whole producer until something turns it off. producer.Debug(false) turns it off, except while a Debugging session is running: a session has asked for debug mode and keeps it until it ends.
One block at a time
Section titled “One block at a time”Debugging runs a function with debug mode forced on and sends the event that function returns:
package main
import ( "context" "fmt" "log"
"github.com/kataras/patrol")
func main() { ctx := context.Background() producer := patrol.NewProducer(patrol.ProducerOptions{ProjectName: "checkout-api"}) defer producer.Close(ctx)
err := producer.Debugging(ctx, func(ctx context.Context) (*patrol.Event, error) { total, err := recalculate(ctx) if err != nil { return nil, err } return patrol.NewEvent(patrol.Debug). WithMessage("recalculated the basket"). WithField("Total", total), nil }) if err != nil { log.Println("debugging:", err) }}
func recalculate(context.Context) (int, error) { return 1299, fmt.Errorf("basket 84213: no such row")}The rules it follows:
- The event you return is sent as a
Debugevent. Its type is overwritten, so returning anInfoevent does not sneak past the switch. - Returning
nil, nilsends nothing and returnsnil. That is the normal path when the block found nothing worth reporting. - Returning an error wraps it as
patrol: debugging transaction failed: ..., sends it as anErrorevent, and returns it. So a failed debugging block reports itself even though debug delivery is what you were testing. - Sessions may overlap. Debug mode turns off when the last one ends, not when the first one does.
Closewaits for every active session before it drains the buffer, so a session in flight cannot lose its event.- After
Close,Debuggingreturnspatrol.ErrClosedwithout running the function.
Where they show up
Section titled “Where they show up”A Debug event is an ordinary event in the batch once it is buffered: same sort, same merge, same fan-out. Slack colours its attachment yellow, #aabb15. The SQL table stores it with type = 3. Nothing filters it out downstream, which is worth remembering before turning debug mode on in a service that pages someone.
Next: shutdown.