commentator

package
v0.1.0-alpha.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 30, 2025 License: Apache-2.0 Imports: 9 Imported by: 0

README

pkg/controller/commentator

Event Commentator - domain-aware event logging with correlation.

Overview

Observability component that subscribes to all controller events and produces structured logs with domain insights and event correlation.

Features

  • Domain-aware logging: Adds business context to events
  • Event correlation: Uses ring buffer to relate events temporally
  • Automatic log levels: Error, Warn, Info, Debug based on event type
  • Ring buffer: Stores recent events for correlation (default: 1000)

Quick Start

import "haptic/pkg/controller/commentator"

commentator := commentator.NewEventCommentator(bus, logger, 1000)
go commentator.Start(ctx)

Example Logs

INFO  Configuration validated successfully version=12345 templates=2
DEBUG Resource index updated type=ingresses added=5 updated=2 deleted=1
INFO  Reconciliation started trigger=config_change since_last=5.2s
INFO  Reconciliation completed duration_ms=1234
ERROR Deployment failed instance=haproxy-1 error="connection refused"

Ring Buffer

Stores last N events for correlation:

// Find recent event of specific type
lastRecon := commentator.ringBuffer.FindLast("reconciliation.started")

// Calculate time since last occurrence
timeSince := currentEvent.Timestamp.Sub(lastRecon.Timestamp)

License

See main repository for license information.

Documentation

Overview

Package commentator provides the Event Commentator pattern for domain-aware logging.

The Event Commentator subscribes to all EventBus events and produces insightful log messages that apply domain knowledge to explain what's happening in the system, similar to how a sports commentator adds context and analysis to events.

Index

Constants

View Source
const (
	// ComponentName is the unique identifier for this component.
	ComponentName = "commentator"

	// EventBufferSize is the size of the event subscription buffer.
	// Size 200: High-volume component that observes all events for logging.
	EventBufferSize = 200
)

Variables

This section is empty.

Functions

This section is empty.

Types

type EventCommentator

type EventCommentator struct {
	// contains filtered or unexported fields
}

EventCommentator provides domain-aware logging for all events flowing through the EventBus. It decouples logging from business logic.

func NewEventCommentator

func NewEventCommentator(eventBus *busevents.EventBus, logger *slog.Logger, bufferSize int) *EventCommentator

NewEventCommentator creates a new Event Commentator.

Parameters:

  • eventBus: The EventBus to subscribe to
  • logger: The structured logger to use
  • bufferSize: Ring buffer capacity (recommended: 1000)

Returns:

  • *EventCommentator ready to start

func (*EventCommentator) FindByCorrelationID

func (ec *EventCommentator) FindByCorrelationID(correlationID string, maxCount int) []busevents.Event

FindByCorrelationID returns events matching the specified correlation ID. This method is used for debugging event flows through the reconciliation pipeline.

Parameters:

  • correlationID: The correlation ID to search for
  • maxCount: Maximum number of events to return (0 = no limit)

Returns:

  • Slice of events matching the correlation ID, newest first

func (*EventCommentator) FindRecent

func (ec *EventCommentator) FindRecent(n int) []busevents.Event

FindRecent returns the N most recent events, newest first. This method is used for debugging recent event activity.

func (*EventCommentator) Name

func (ec *EventCommentator) Name() string

Name returns the unique identifier for this component. Implements the lifecycle.Component interface.

func (*EventCommentator) Start

func (ec *EventCommentator) Start(ctx context.Context) error

Start begins processing events from the EventBus.

This method blocks until Stop() is called or the context is canceled. The component is already subscribed to the EventBus (subscription happens in constructor). Returns nil on graceful shutdown.

Example:

go commentator.Start(ctx)

func (*EventCommentator) Stop

func (ec *EventCommentator) Stop()

Stop gracefully stops the commentator.

type ReconciliationSummary

type ReconciliationSummary struct {
	// Trigger is the reason that initiated the reconciliation.
	Trigger string

	// RenderMs is the time spent rendering templates.
	RenderMs int64

	// ValidateMs is the time spent validating the HAProxy configuration.
	ValidateMs int64

	// DeployMs is the time spent deploying to HAProxy instances.
	DeployMs int64

	// TotalMs is the wall-clock time from reconciliation trigger to deployment completion.
	// This may be less than the sum of individual phase durations if there are gaps.
	TotalMs int64

	// Instances is the "succeeded/total" string for deployment.
	Instances string

	// Reloads is the number of HAProxy reloads triggered.
	Reloads int

	// Operations is the total number of API operations performed.
	Operations int
}

ReconciliationSummary contains aggregated metrics from a complete reconciliation cycle. It is computed by correlating events with the same correlation ID.

type RingBuffer

type RingBuffer struct {
	// contains filtered or unexported fields
}

Typical capacity: 1000 events (configurable).

func NewRingBuffer

func NewRingBuffer(capacity int) *RingBuffer

NewRingBuffer creates a new ring buffer with the specified capacity.

Parameters:

  • capacity: Maximum number of events to store (recommended: 1000)

Returns:

  • *RingBuffer ready for use

func (*RingBuffer) Add

func (rb *RingBuffer) Add(event busevents.Event)

Add appends an event to the buffer.

If the buffer is full, the oldest event is overwritten (circular behavior). The type index and correlation index are updated to include the new event. Old correlation index entries are actively cleaned up when events are overwritten to prevent memory growth.

This operation is O(1) amortized.

func (*RingBuffer) Capacity

func (rb *RingBuffer) Capacity() int

Capacity returns the maximum capacity of the buffer.

func (*RingBuffer) FindByCorrelationID

func (rb *RingBuffer) FindByCorrelationID(correlationID string, maxCount int) []busevents.Event

FindByCorrelationID returns events with the specified correlation ID, newest first.

Parameters:

  • correlationID: The correlation ID to search for
  • maxCount: Maximum number of events to return (0 = no limit)

Returns:

  • Slice of events matching the correlation ID, newest first

Complexity: O(k) where k = number of events with that correlation ID (typically 10-15 for a reconciliation cycle)

Example:

// Find all events in a reconciliation cycle
events := rb.FindByCorrelationID("550e8400-e29b-41d4-a716-446655440000", 100)

func (*RingBuffer) FindByType

func (rb *RingBuffer) FindByType(eventType string) []busevents.Event

FindByType returns all events of the specified type, newest first.

The returned slice is a copy - modifications won't affect the buffer.

Complexity: O(k) where k = number of events of that type (typically small)

Example:

events := rb.FindByType("config.validated")
for _, evt := range events {
    // Process events (newest first)
}

func (*RingBuffer) FindByTypeInWindow

func (rb *RingBuffer) FindByTypeInWindow(eventType string, window time.Duration) []busevents.Event

FindByTypeInWindow returns events of the specified type within the time window, newest first.

Parameters:

  • eventType: The event type to filter by
  • window: Time duration to look back (e.g., 5 * time.Minute)

Returns:

  • Slice of events matching the type and within the window, newest first

Example:

// Find all config validations in the last 5 minutes
events := rb.FindByTypeInWindow("config.validated", 5*time.Minute)

func (*RingBuffer) FindRecent

func (rb *RingBuffer) FindRecent(n int) []busevents.Event

FindRecent returns the N most recent events of any type, newest first.

Parameters:

  • n: Maximum number of events to return

Returns:

  • Slice of up to N most recent events, newest first

Example:

// Get last 10 events for debugging
recent := rb.FindRecent(10)

func (*RingBuffer) FindRecentByPredicate

func (rb *RingBuffer) FindRecentByPredicate(maxCount int, predicate func(busevents.Event) bool) []busevents.Event

FindRecentByPredicate returns recent events matching a predicate, newest first.

Parameters:

  • maxCount: Maximum number of matching events to return
  • predicate: Function that returns true for events to include

Returns:

  • Slice of matching events, newest first

Example:

// Find recent deployment events
deployments := rb.FindRecentByPredicate(5, func(e busevents.Event) bool {
    return strings.HasPrefix(e.EventType(), "deployment.")
})

func (*RingBuffer) Size

func (rb *RingBuffer) Size() int

Size returns the current number of events in the buffer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL