Documentation
¶
Overview ¶
Package sentinel provides reliability handling and observability monitoring for Go applications. It wraps task execution with Prometheus metrics, observing errors, panic occurrences, retries, and timeouts — making critical routines safe, measurable, and reliable.
Index ¶
- Constants
- func IsPanicError(err error) (any, bool)
- func RetryCount(ctx context.Context) int
- type ErrControlBreaker
- type Observer
- func (o *Observer) Collect(ch chan<- prometheus.Metric)
- func (o *Observer) Describe(ch chan<- *prometheus.Desc)
- func (o *Observer) DisablePanicRecovery(disable bool)
- func (o *Observer) MustRegister(registry prometheus.Registerer)
- func (o *Observer) Register(registry prometheus.Registerer) error
- func (o *Observer) Run(fn func() error) error
- func (o *Observer) RunFunc(fn func(ctx context.Context) error) error
- func (o *Observer) UseConfig(config ObserverConfig)
- type ObserverConfig
- type ObserverOption
- type RecoveredPanic
- type VecObserver
- func (vo *VecObserver) Collect(ch chan<- prometheus.Metric)
- func (vo *VecObserver) CurryWith(labels prometheus.Labels) (*VecObserver, error)
- func (vo *VecObserver) Describe(ch chan<- *prometheus.Desc)
- func (vo *VecObserver) MustRegister(registry prometheus.Registerer)
- func (vo *VecObserver) Register(registry prometheus.Registerer) error
- func (vo *VecObserver) Reset()
- func (vo *VecObserver) With(labels prometheus.Labels) (*Observer, error)
- func (vo *VecObserver) WithLabels(labelValues ...string) (*Observer, error)
Constants ¶
const ( MetricInFlight = "inFlight" MetricSuccesses = "successes" MetricFailures = "failures" MetricErrors = "errors" MetricTimeouts = "timeouts" MetricPanics = "panics" MetricDurations = "durations" MetricRetries = "retries" MetricPending = "pending" )
Metric names that can be enabled/disabled
Variables ¶
This section is empty.
Functions ¶
func IsPanicError ¶ added in v0.5.0
IsPanicError checks if the given error was caused by a panic that was recovered by the Observer. It returns the panic value and a boolean indicating whether a panic occurred.
Example usage:
err := observer.RunTask(myTask)
if panicValue, isPanic := IsPanicError(err); isPanic {
log.Printf("Task panicked with value: %v", panicValue)
// Handle panic-specific logic
} else if err != nil {
log.Printf("Task failed with error: %v", err)
// Handle regular error
}
func RetryCount ¶ added in v0.8.0
RetryCount returns the current retry count from the context. Returns 0 if the retry count is not set in the context.
Example usage:
observer := sentinel.NewObserver(nil)
observer.UseConfig(sentinel.ObserverConfig{
MaxRetries: 3,
})
_ = observer.RunFunc(func(ctx context.Context) error {
retryCount := sentinel.RetryCount(ctx)
log.Printf("Current retry count: %d\n", retryCount)
return nil
})
Types ¶
type ErrControlBreaker ¶ added in v0.6.0
type ErrControlBreaker struct{}
ErrControlBreaker is the error returned when a control breaker is triggered. This occurs when ObserverConfig.Control returns true, preventing task execution before it even begins (during PhaseNewRequest) or stopping retry attempts (during PhaseRetry).
func (*ErrControlBreaker) Error ¶ added in v0.6.0
func (e *ErrControlBreaker) Error() string
type Observer ¶
type Observer struct {
// contains filtered or unexported fields
}
Observer monitors and measures task executions, collecting Prometheus metrics for successes, failures, timeouts, panics, retries, and observed runtimes. It provides methods to execute tasks with various ObserverConfig options.
func NewObserver ¶
func NewObserver(durationBuckets []float64, opts ...ObserverOption) *Observer
NewObserver configures a new Observer with duration buckets and optional configuration. The Observer will need to be registered with a Prometheus registry to expose metrics. Please refer to Observer.MustRegister and Observer.Register for more information.
Example usage:
// Default configuration
observer := sentinel.NewObserver(nil)
// With duration metrics
observer := sentinel.NewObserver([]float64{0.05, 1, 5, 30, 600})
// With custom namespace and subsystem
observer := sentinel.NewObserver(
[]float64{0.1, 0.5, 1, 2, 5},
sentinel.WithNamespace("my_app"),
sentinel.WithSubsystem("workers"),
)
func (*Observer) Collect ¶ added in v0.8.0
func (o *Observer) Collect(ch chan<- prometheus.Metric)
Collect implements the prometheus.Collector interface by collecting metrics. This can be useful to register the Observer with the default Prometheus registry.
func (*Observer) Describe ¶ added in v0.8.0
func (o *Observer) Describe(ch chan<- *prometheus.Desc)
Describe implements the prometheus.Collector interface by describing metrics. This can be useful to register the Observer with the default Prometheus registry.
func (*Observer) DisablePanicRecovery ¶ added in v0.6.0
DisablePanicRecovery sets whether panic recovery should be disabled for the observer. Recovery is enabled by default, meaning panics are caught and converted to errors. When disabled, panics will propagate normally and may crash the program.
func (*Observer) MustRegister ¶
func (o *Observer) MustRegister(registry prometheus.Registerer)
MustRegister registers all Observer metrics with the provided Prometheus registry. This method panics if any metric registration failures occur. Use Observer.Register if you prefer to handle registration errors gracefully instead of panicking.
Example usage:
registry := prometheus.NewRegistry() observer.MustRegister(registry) // Will panic if registration fails
func (*Observer) Register ¶
func (o *Observer) Register(registry prometheus.Registerer) error
Register registers all Observer metrics with the provided Prometheus registry. This method returns an error if any metric registration fails. Use Observer.MustRegister if you want the program to panic on registration conflicts instead of handling errors.
Example usage:
registry := prometheus.NewRegistry()
if err := observer.Register(registry); err != nil {
log.Fatalf("Failed to register metrics: %v", err)
}
func (*Observer) Run ¶
Run executes fn and records metrics according to the observer's configuration. This method does not respect timeouts set in the observer's ObserverConfig. Use RunFunc if you need timeout support.
The function is executed with panic recovery enabled by default. Panics are converted to errors and recorded in metrics. Use DisablePanicRecovery(true) to propagate panics instead.
If the function returns context.DeadlineExceeded, it will be recorded as a timeout when timeout metrics are enabled.
Example usage:
observer := sentinel.NewObserver()
err := observer.Run(func() error {
return nil
})
if err != nil {
log.Printf("Task failed: %v", err)
}
func (*Observer) RunFunc ¶
RunFunc executes fn and records metrics according to the observer's configuration. For timeouts specified by the observer's ObserverConfig, the fn will be passed a context with the timeout. This is the recommended method when you need timeout support.
The function is executed with panic recovery enabled by default. Panics are converted to errors and recorded in metrics. Use DisablePanicRecovery(true) to propagate panics instead.
If the function returns context.DeadlineExceeded, it will be recorded as a timeout when timeout metrics are enabled.
Example usage:
observer := sentinel.NewObserver()
observer.UseConfig(sentinel.ObserverConfig{
Timeout: 10 * time.Second,
})
err := observer.RunFunc(func(ctx context.Context) error {
// Your task logic here with timeout support
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(5 * time.Second):
return nil
}
})
if err != nil {
log.Printf("Task failed: %v", err)
}
func (*Observer) UseConfig ¶ added in v0.6.0
func (o *Observer) UseConfig(config ObserverConfig)
UseConfig configures the observer for how to handle Run methods. This sets the ObserverConfig that will be used for all subsequent Run, RunFunc calls. See ObserverConfig for more information on available configuration options.
Example usage:
observer.UseConfig(sentinel.ObserverConfig{
Timeout: 10 * time.Second,
MaxRetries: 3,
RetryStrategy: retry.Exponential(100 * time.Millisecond),
RetryBreaker: circuit.OnPanic(),
MaxConcurrency: 10, // Limit to 10 concurrent executions
})
type ObserverConfig ¶
type ObserverConfig struct {
// Timeout sets a context deadline for functions passed to [Observer.RunFunc].
// The observer records timeout occurrences under the "timeouts" metric when enabled.
// The timeout is applied per iterative attempt to run the function.
Timeout time.Duration
// MaxRetries specifies the number of retry attempts for tasks on errors. If a task
// fails for all attempts, the observer groups errors from multiple attempts using
// [errors.Join]. By default, no retries are performed.
MaxRetries int
// RetryStrategy is a handler which returns wait durations between retry attempts.
// The first retry attempt will call the handler with retryCount=1. By default,
// no wait strategy is applied (immediate retry).
RetryStrategy retry.WaitFunc
// RetryBreaker is a handler that skips following retry attempts for a task when
// returning true. The handler will be provided the error from the previous attempt.
// When nil, the observer will always attempt the next retry. This is useful to stop
// retries on particular errors.
RetryBreaker circuit.Breaker
// Control receives the execution phase (PhaseNewRequest for new task executions, or
// PhaseRetry for retry attempts) and returns true to cancel execution. This is useful
// to manage or avoid new task executions on shutdown signals, or handling of specific
// errors. When nil, all requests and retries are allowed.
Control circuit.Control
// MaxConcurrency limits the number of concurrent task executions. When set to a value
// greater than 0, the observer will use a semaphore to limit concurrent executions.
// This is useful for rate limiting or preventing resource exhaustion from too many
// concurrent operations.
MaxConcurrency int
}
type ObserverOption ¶ added in v0.5.0
type ObserverOption func(*config)
ObserverOption defines prometheus metrics options for an Observer. Options are provided to NewObserver on setting up the Observer.
func WithConstLabels ¶ added in v0.5.0
func WithConstLabels(labels prometheus.Labels) ObserverOption
WithConstLabels sets constant labels to exported metrics from the Observer. By convention, ConstLabels are not a recommended practice for Prometheus metrics. For more information, please refer to prometheus.Opts.ConstLabels documentation.
Example usage:
observer := sentinel.NewObserver(
sentinel.WithConstLabels(
prometheus.Labels{"env": "production"},
),
)
func WithDescription ¶ added in v0.5.0
func WithDescription(description string) ObserverOption
WithDescription sets the description used in the help text for generated prometheus metrics to describe the tasks being observed. For example, "background processes" results in help text like: "Number of successes from observed background processes". Defaults to "tasks" to convey a generic process if not specified.
Example usage:
observer := sentinel.NewObserver(
sentinel.WithDescription("background processes"),
)
func WithMetrics ¶ added in v0.8.0
func WithMetrics(metricNames ...string) ObserverOption
WithMetrics enables only the specified metrics for export. If not called, all metrics are enabled by default. Metrics that are not included will not be registered or exported.
Example usage:
// Only export successes and failures
observer := sentinel.NewObserver(
nil,
sentinel.WithMetrics(
sentinel.MetricSuccesses,
sentinel.MetricFailures,
),
)
// Export all metrics except durations
observer := sentinel.NewObserver(
nil,
sentinel.WithMetrics(
sentinel.MetricInFlight,
sentinel.MetricSuccesses,
sentinel.MetricFailures,
sentinel.MetricErrors,
sentinel.MetricTimeouts,
sentinel.MetricPanics,
sentinel.MetricRetries,
),
)
func WithNamespace ¶ added in v0.5.0
func WithNamespace(namespace string) ObserverOption
WithNamespace sets the prometheus namespace for all metrics generated by this observer. For example, "myapp" with no subsystem results in metrics like "myapp_success_total". If empty with subsystem, no namespace prefix is used.
Example usage:
observer := sentinel.NewObserver(
sentinel.WithNamespace("myapp"),
)
func WithSubsystem ¶ added in v0.5.0
func WithSubsystem(subsystem string) ObserverOption
WithSubsystem sets the prometheus subsystem for all metrics generated by this observer. For example, "workers" with no namespace results in metrics like "workers_success_total". If empty with namespace, defaults to "sentinel" if not specified.
Example usage:
observer := sentinel.NewObserver(
sentinel.WithSubsystem("workers"),
)
type RecoveredPanic ¶ added in v0.9.0
type RecoveredPanic struct {
// contains filtered or unexported fields
}
ErrRecoveredPanic is the error returned when a panic occurs and is recovered by the Observer. The panic value can be retrieved from the error directly.
func (RecoveredPanic) Callers ¶ added in v0.9.0
func (e RecoveredPanic) Callers() []uintptr
Callers returns the program counters of the call stack at the time of panic. This can be used with runtime.CallersFrames to inspect the call stack.
func (RecoveredPanic) Error ¶ added in v0.9.0
func (e RecoveredPanic) Error() string
func (RecoveredPanic) Stack ¶ added in v0.9.0
func (e RecoveredPanic) Stack() []byte
Stack returns the stack trace captured at the time of panic recovery. The stack trace is formatted as a byte slice, similar to debug.Stack().
func (RecoveredPanic) Value ¶ added in v0.9.0
func (e RecoveredPanic) Value() any
Value returns the original panic value that was recovered. This is the value that was passed to panic() when the panic occurred.
type VecObserver ¶ added in v0.8.0
type VecObserver struct {
// contains filtered or unexported fields
}
VecObserver is an Observer that supports Prometheus labels for multi-dimensional metrics. It follows the same pattern as Prometheus's GaugeVec and CounterVec, providing methods to create child observers with specific label combinations.
Example usage:
vecObserver := sentinel.NewVecObserver(
[]float64{0.1, 0.5, 1, 2, 5},
[]string{"service", "environment"},
)
apiObserver, _ := vecObserver.WithLabels("api", "production")
dbObserver, _ := vecObserver.WithLabels("db", "staging")
func NewVecObserver ¶ added in v0.8.0
func NewVecObserver(durationBuckets []float64, labelNames []string, opts ...ObserverOption) *VecObserver
NewVecObserver creates a new VecObserver with label support. When LabelNames is set in the VecObserverConfig, Vec metrics are used instead of direct metrics.
Example usage:
observer := sentinel.NewVecObserver(
[]float64{0.1, 0.5, 1, 2, 5},
[]string{"service", "status"},
sentinel.WithNamespace("myapp"),
)
func (*VecObserver) Collect ¶ added in v0.8.0
func (vo *VecObserver) Collect(ch chan<- prometheus.Metric)
Collect implements the prometheus.Collector interface by collecting metrics. This can be useful to register the Observer with the default Prometheus registry.
func (*VecObserver) CurryWith ¶ added in v0.8.0
func (vo *VecObserver) CurryWith(labels prometheus.Labels) (*VecObserver, error)
CurryWith returns a VecObserver curried with the provided labels. Currying allows you to pre-set some labels, creating a new VecObserver that requires fewer labels for subsequent operations. This is useful when you have a common label value (like "environment") that you want to apply to multiple observers.
An error will be returned if the labels do not match initially configured label names.
Example usage:
vecObserver := sentinel.NewVecObserver(
[]float64{0.1, 0.5, 1, 2, 5},
[]string{"service", "environment"},
)
// Curry with environment="production", now only service label is needed
prodObserver, err := vecObserver.CurryWith(prometheus.Labels{"environment": "production"})
if err != nil {
log.Fatal(err)
}
// Create observers with only the service label
apiObserver, _ := prodObserver.WithLabels("api")
dbObserver, _ := prodObserver.WithLabels("db")
func (*VecObserver) Describe ¶ added in v0.8.0
func (vo *VecObserver) Describe(ch chan<- *prometheus.Desc)
Describe implements the prometheus.Collector interface by describing metrics. This can be useful to register the Observer with the default Prometheus registry.
func (*VecObserver) MustRegister ¶ added in v0.8.0
func (vo *VecObserver) MustRegister(registry prometheus.Registerer)
MustRegister registers all VecObserver metrics with the provided Prometheus registry. This method panics if any metric registration failures occur. Use VecObserver.Register if you prefer to handle registration errors gracefully instead of panicking.
Example usage:
registry := prometheus.NewRegistry() vecObserver.MustRegister(registry) // Will panic if registration fails
func (*VecObserver) Register ¶ added in v0.8.0
func (vo *VecObserver) Register(registry prometheus.Registerer) error
Register registers all VecObserver metrics with the provided Prometheus registry. This method returns an error if any metric registration fails. Use VecObserver.MustRegister if you want the program to panic on registration conflicts instead of handling errors.
Example usage:
registry := prometheus.NewRegistry()
if err := vecObserver.Register(registry); err != nil {
log.Fatalf("Failed to register metrics: %v", err)
}
func (*VecObserver) Reset ¶ added in v0.8.0
func (vo *VecObserver) Reset()
Reset deletes all metrics in this VecObserver.
This method affects all child observers created from this VecObserver. After reset:
- All metric values tracked by the VecObserver are cleared
- Existing child observers created before Reset() can still be called without panicking, but their metrics will not be tracked by the VecObserver (they record to old metric instances that were removed from the Vec's internal map)
- To continue tracking metrics after Reset(), create new child observers using VecObserver.WithLabels or VecObserver.With
This method follows the same pattern as Prometheus's GaugeVec.Reset method.
func (*VecObserver) With ¶ added in v0.8.0
func (vo *VecObserver) With(labels prometheus.Labels) (*Observer, error)
With returns a new Observer with the given labels. The observer will share the same underlying metrics as the original, but will record metrics with the specified label values. An error will be returned if the labels do not match initially configured label names.
Example usage:
vecObserver := sentinel.NewVecObserver(
[]float64{0.1, 0.5, 1, 2, 5},
[]string{"service", "environment"},
)
observer, err := vecObserver.With(prometheus.Labels{
"service": "api",
"environment": "production",
})
if err != nil {
log.Fatal(err)
}
func (*VecObserver) WithLabels ¶ added in v0.8.0
func (vo *VecObserver) WithLabels(labelValues ...string) (*Observer, error)
WithLabels returns a new Observer with the given label values. An error will be returned if the label values do not match initially configured label names.
Example usage:
vecObserver := sentinel.NewVecObserver(
[]float64{0.1, 0.5, 1, 2, 5},
[]string{"service", "environment"},
)
observer, err := vecObserver.WithLabels("api", "production")
if err != nil {
log.Fatal(err)
}
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package circuit provides circuit breaker predicates for sentinel's retry logic.
|
Package circuit provides circuit breaker predicates for sentinel's retry logic. |
|
Package retry provides WaitFunc implementations for the sentinel package.
|
Package retry provides WaitFunc implementations for the sentinel package. |