Documentation ¶
Overview ¶
Package app provides helpers for common bedrock.App implementation patterns.
Index ¶
- func Recover(app bedrock.App) bedrock.App
- func WithLifecycleHooks(app bedrock.App, lifecycle Lifecycle) bedrock.App
- func WithOTel(app bedrock.App, opts ...OTelOption) bedrock.App
- func WithSignalNotifications(app bedrock.App, signals ...os.Signal) bedrock.App
- type Lifecycle
- type LifecycleHook
- type LifecycleHookFunc
- type OTelOption
- func OTelLoggerProvider(f func(context.Context) (log.LoggerProvider, error)) OTelOption
- func OTelMeterProvider(f func(context.Context) (metric.MeterProvider, error)) OTelOption
- func OTelTextMapPropogator(f func(context.Context) (propagation.TextMapPropagator, error)) OTelOption
- func OTelTracerProvider(f func(context.Context) (trace.TracerProvider, error)) OTelOption
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Recover ¶
Recover will wrap the give bedrock.App with panic recovery. If the recovered panic value implements [error] then it will be directly returned. If it does not implement [error] then a [PanicError] will be returned instead.
Example ¶
app := runFunc(func(ctx context.Context) error { panic("hello world") return nil }) err := Recover(app).Run(context.Background()) var perr bedrock.PanicError if !errors.As(err, &perr) { fmt.Println("should be a panic error.") return } fmt.Println(perr.Value)
Output: hello world
Example (ErrorValue) ¶
app := runFunc(func(ctx context.Context) error { panic(errors.New("hello world")) return nil }) err := Recover(app).Run(context.Background()) var perr bedrock.PanicError if !errors.As(err, &perr) { fmt.Println("should be a panic error.") return } fmt.Println(perr.Unwrap())
Output: hello world
func WithLifecycleHooks ¶
WithLifecycleHooks wraps a given bedrock.App in an implementation that runs [LifecycleHook]s around the execution of app.Run.
Example ¶
var app bedrock.App = runFunc(func(ctx context.Context) error { return nil }) postRun := LifecycleHookFunc(func(ctx context.Context) error { fmt.Println("ran post run hook") return nil }) app = WithLifecycleHooks(app, Lifecycle{ PostRun: postRun, }) err := app.Run(context.Background()) if err != nil { fmt.Println(err) return }
Output: ran post run hook
Example (UnrecoveredPanic) ¶
var app bedrock.App = runFunc(func(ctx context.Context) error { panic("hello world") return nil }) postRun := LifecycleHookFunc(func(ctx context.Context) error { fmt.Println("ran post run hook") return nil }) app = WithLifecycleHooks(app, Lifecycle{ PostRun: postRun, }) run := func(ctx context.Context) error { // recover here so the panic doesn't crash the example defer func() { recover() }() return app.Run(ctx) } err := run(context.Background()) if err != nil { fmt.Println(err) return }
Output: ran post run hook
func WithOTel ¶
func WithOTel(app bedrock.App, opts ...OTelOption) bedrock.App
WithOTel
Example (LoggerProvider) ¶
var app bedrock.App = runFunc(func(ctx context.Context) error { // here we're using the otelslog bridge which will use the global // LoggerProvider for us to create a otel Logger and map between // the slog and otel log record types. logger := otelslog.NewLogger("app") logger.InfoContext(ctx, "hello") return nil }) var lp *sdklog.LoggerProvider var buf bytes.Buffer app = WithOTel( app, OTelLoggerProvider(func(ctx context.Context) (log.LoggerProvider, error) { // NOTE: this is only for example purposes. DO NOT USE IN PRODUCTION!!! exp, err := stdoutlog.New( stdoutlog.WithWriter(&buf), ) if err != nil { return nil, err } p := sdklog.NewSimpleProcessor(exp) lp = sdklog.NewLoggerProvider( sdklog.WithProcessor(p), ) return lp, nil }), ) err := app.Run(context.Background()) if err != nil { fmt.Println(err) return } // Ensure that the app log is flushed to buf err = lp.Shutdown(context.Background()) if err != nil { fmt.Println(err) return } b, err := io.ReadAll(&buf) if err != nil { fmt.Println(err) return } var m struct { Body struct { Value string `json:"Value"` } `json:"Body"` Scope struct { Name string `json:"Name"` } `json:"Scope"` } err = json.Unmarshal(b, &m) if err != nil { fmt.Println(err) return } fmt.Println(m.Scope.Name, m.Body.Value)
Output: app hello
Example (MeterProvider) ¶
var app bedrock.App = runFunc(func(ctx context.Context) error { counter, err := otel.Meter("app").Int64Counter("Run") if err != nil { return err } counter.Add(ctx, 1) return nil }) var mp *sdkmetric.MeterProvider var buf bytes.Buffer app = WithOTel( app, OTelMeterProvider(func(ctx context.Context) (metric.MeterProvider, error) { // NOTE: this is only for example purposes. DO NOT USE IN PRODUCTION!!! exp, err := stdoutmetric.New( stdoutmetric.WithWriter(&buf), ) if err != nil { return nil, err } r := sdkmetric.NewPeriodicReader(exp) mp = sdkmetric.NewMeterProvider( sdkmetric.WithReader(r), ) return mp, nil }), ) err := app.Run(context.Background()) if err != nil { fmt.Println(err) return } // Ensure that the app metric is flushed to buf err = mp.Shutdown(context.Background()) if err != nil { fmt.Println(err) return } b, err := io.ReadAll(&buf) if err != nil { fmt.Println(err) return } var m struct { ScopeMetrics []struct { Metrics []struct { Name string `json:"Name"` Data struct { DataPoints []struct { Value int `json:"Value"` } `json:"DataPoints"` } `json:"Data"` } `json:"Metrics"` } `json:"ScopeMetrics"` } err = json.Unmarshal(b, &m) if err != nil { fmt.Println(err) return } metric := m.ScopeMetrics[0].Metrics[0] fmt.Println(metric.Name, metric.Data.DataPoints[0].Value)
Output: Run 1
Example (TextMapPropogator) ¶
carrier := make(propagation.MapCarrier) var app bedrock.App = runFunc(func(ctx context.Context) error { tmp := otel.GetTextMapPropagator() tmp.Inject(ctx, carrier) return nil }) app = WithOTel( app, OTelTextMapPropogator(func(ctx context.Context) (propagation.TextMapPropagator, error) { tmp := propagation.Baggage{} return tmp, nil }), ) m, _ := baggage.NewMember("hello", "world") b, _ := baggage.New(m) ctx := baggage.ContextWithBaggage(context.Background(), b) err := app.Run(ctx) if err != nil { fmt.Println(err) return } ctx = propagation.Baggage{}.Extract(context.Background(), carrier) b = baggage.FromContext(ctx) m = b.Member("hello") fmt.Println(m.Value())
Output: world
Example (TracerProvider) ¶
var app bedrock.App = runFunc(func(ctx context.Context) error { _, span := otel.Tracer("app").Start(ctx, "Run") defer span.End() return nil }) var tp *sdktrace.TracerProvider var buf bytes.Buffer app = WithOTel( app, OTelTracerProvider(func(ctx context.Context) (trace.TracerProvider, error) { // NOTE: this is only for example purposes. DO NOT USE IN PRODUCTION!!! exp, err := stdouttrace.New( stdouttrace.WithWriter(&buf), ) if err != nil { return nil, err } sp := sdktrace.NewSimpleSpanProcessor(exp) tp = sdktrace.NewTracerProvider( sdktrace.WithSpanProcessor(sp), ) return tp, nil }), ) err := app.Run(context.Background()) if err != nil { fmt.Println(err) return } // Ensure that the app trace is flushed to buf err = tp.Shutdown(context.Background()) if err != nil { fmt.Println(err) return } b, err := io.ReadAll(&buf) if err != nil { fmt.Println(err) return } var m map[string]any err = json.Unmarshal(b, &m) if err != nil { fmt.Println(err) return } fmt.Println(m["Name"])
Output: Run
func WithSignalNotifications ¶
WithSignalNotifications wraps a given bedrock.App in an implementation that cancels the context.Context that's passed to app.Run if an os.Signal is received by the running process.
Types ¶
type Lifecycle ¶
type Lifecycle struct { // PostRun is always executed regardless if the underlying [bedrock.App] // returns an error or panics. PostRun LifecycleHook }
Lifecycle
type LifecycleHook ¶
LifecycleHook represents functionality that needs to be performed at a specific "time" relative to the execution of bedrock.App.Run.
func ComposeLifecycleHooks ¶ added in v0.16.0
func ComposeLifecycleHooks(hooks ...LifecycleHook) LifecycleHook
ComposeLifecycleHooks combines multiple [LifecycleHook]s into a single hook. Each hook is called sequentially and each hook is called irregardless if a previous hook returned an error or not. Any and all errors are then returned after all hooks have been ran.
Example ¶
var app bedrock.App = runFunc(func(ctx context.Context) error { return nil }) app = WithLifecycleHooks(app, Lifecycle{ PostRun: ComposeLifecycleHooks( LifecycleHookFunc(func(ctx context.Context) error { fmt.Println("one") return nil }), LifecycleHookFunc(func(ctx context.Context) error { fmt.Println("two") return nil }), LifecycleHookFunc(func(ctx context.Context) error { fmt.Println("three") return nil }), ), }) err := app.Run(context.Background()) if err != nil { fmt.Println(err) return }
Output: one two three
type LifecycleHookFunc ¶
LifecycleHookFunc is a convenient helper type for implementing a LifecycleHook from just a regular func.
func (LifecycleHookFunc) Run ¶
func (f LifecycleHookFunc) Run(ctx context.Context) error
Run implements the LifecycleHook interface.
type OTelOption ¶
type OTelOption func(*otelOptions)
OTelOption
func OTelLoggerProvider ¶
func OTelLoggerProvider(f func(context.Context) (log.LoggerProvider, error)) OTelOption
OTelLoggerProvider
func OTelMeterProvider ¶
func OTelMeterProvider(f func(context.Context) (metric.MeterProvider, error)) OTelOption
OTelMeterProvider
func OTelTextMapPropogator ¶
func OTelTextMapPropogator(f func(context.Context) (propagation.TextMapPropagator, error)) OTelOption
OTelTextMapPropogator
func OTelTracerProvider ¶
func OTelTracerProvider(f func(context.Context) (trace.TracerProvider, error)) OTelOption
OTelTracerProvider