package app import ( "context" "errors" "github.com/rs/zerolog" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" "gitea.libretechconsulting.com/rmcguire/go-app/pkg/config" "gitea.libretechconsulting.com/rmcguire/go-app/pkg/otel" "gitea.libretechconsulting.com/rmcguire/go-app/pkg/srv" ) type App struct { AppContext context.Context HTTP *AppHTTP cfg *config.AppConfig l *zerolog.Logger tracer trace.Tracer shutdownFuncs []shutdownFunc appDone chan interface{} } type AppHTTP struct { Funcs []srv.HTTPFunc HealthChecks []srv.HealthCheckFunc httpDone <-chan interface{} } type ( healthCheckFunc func(context.Context) error shutdownFunc func(context.Context) error ) func (a *App) Done() <-chan interface{} { return a.appDone } func (a *App) MustRun() { if a.cfg != nil { panic(errors.New("already ran app trying to run")) } // Set up app a.cfg = config.MustFromCtx(a.AppContext) a.l = zerolog.Ctx(a.AppContext) a.shutdownFuncs = make([]shutdownFunc, 0) a.appDone = make(chan interface{}) a.HTTP.httpDone = make(chan interface{}) if len(a.HTTP.Funcs) < 1 { a.l.Warn().Msg("no http funcs provided, only serving health and metrics") } // Start OTEL a.initOTEL() var initSpan trace.Span _, initSpan = a.tracer.Start(a.AppContext, "init") // Start HTTP a.initHTTP() // Monitor app lifecycle go a.run() // Startup Complete a.l.Info(). Str("name", a.cfg.Name). Str("version", a.cfg.Version). Str("logLevel", a.cfg.Logging.Level). Msg("app initialized") initSpan.SetStatus(codes.Ok, "") initSpan.End() } func (a *App) initHTTP() { var httpShutdown shutdownFunc httpShutdown, a.HTTP.httpDone = srv.MustInitHTTPServer( a.AppContext, a.HTTP.Funcs, a.HTTP.HealthChecks..., ) a.shutdownFuncs = append(a.shutdownFuncs, httpShutdown) } func (a *App) initOTEL() { var otelShutdown shutdownFunc a.AppContext, otelShutdown = otel.Init(a.AppContext) a.shutdownFuncs = append(a.shutdownFuncs, otelShutdown) a.tracer = otel.MustTracerFromCtx(a.AppContext) }