Files
simplexcalc/internal/app/app.go
T
clawbot f8ce8cef83 Seed from go-template-repo, renamed to simplexcalc
The template's files at a77fd30, without its history or LICENSE, after
script/rename simplexcalc.

Model: opus-5-5
2026-09-26 21:38:57 +00:00

73 lines
2.2 KiB
Go

// Package app wires the object graph. It is the one place that knows
// which concrete types satisfy the application's dependencies, so every
// other package can be constructed in a test with substitutes.
package app
import (
"log/slog"
"go.uber.org/fx"
"go.uber.org/fx/fxevent"
"sneak.berlin/go/simplexcalc/internal/config"
"sneak.berlin/go/simplexcalc/internal/database"
"sneak.berlin/go/simplexcalc/internal/globals"
"sneak.berlin/go/simplexcalc/internal/handlers"
"sneak.berlin/go/simplexcalc/internal/logger"
"sneak.berlin/go/simplexcalc/internal/middleware"
"sneak.berlin/go/simplexcalc/internal/render"
"sneak.berlin/go/simplexcalc/internal/server"
"sneak.berlin/go/simplexcalc/internal/telemetry"
)
// Module is every provider the service needs. Constructor order is
// irrelevant to fx; the order here is the order a reader wants: build
// metadata, logging, configuration, storage, then the HTTP layer.
//
//nolint:gochecknoglobals // an fx module is a declaration, not mutable state.
var Module = fx.Options(
fx.Provide(
globals.New,
logger.New,
config.New,
database.New,
telemetry.NewSentry,
telemetry.NewMetrics,
render.New,
middleware.New,
handlers.New,
server.New,
),
// fx's own lifecycle events go through the application logger, so
// the process emits one stream in one format. Without this, fx
// prints its own plain-text output to stderr and a log pipeline
// gets two formats from one process.
fx.WithLogger(func(l *logger.Logger) fxevent.Logger {
return &fxevent.SlogLogger{Logger: l.Get()}
}),
)
// Invoke forces the graph to be built. fx constructs lazily: without a
// request for the Server, a perfectly valid App would start, construct
// nothing, and serve nothing.
//
//nolint:gochecknoglobals // as above.
var Invoke = fx.Invoke(func(_ *server.Server, log *logger.Logger, cfg *config.Config) {
if cfg.Debug {
log.EnableDebugLogging()
}
log.Identify()
})
// New builds the fx application for `serve`.
func New(opts ...fx.Option) *fx.App {
return fx.New(append([]fx.Option{Module, Invoke}, opts...)...)
}
// DiscardLogger is a logger that writes nothing, for tests that build
// the graph and do not want its startup output.
func DiscardLogger() *slog.Logger {
return slog.New(slog.DiscardHandler)
}