refactor: combine tracing & metrics in observability package

This commit is contained in:
Dominik Süß 2025-02-05 17:11:28 +01:00
commit 826c36f162
No known key found for this signature in database
GPG key ID: 9B1DDB4B45B86806
10 changed files with 64 additions and 81 deletions

View file

@ -50,9 +50,9 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/internal/media/ffmpeg"
"github.com/superseriousbusiness/gotosocial/internal/messages"
"github.com/superseriousbusiness/gotosocial/internal/metrics"
"github.com/superseriousbusiness/gotosocial/internal/middleware"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/observability"
"github.com/superseriousbusiness/gotosocial/internal/oidc"
"github.com/superseriousbusiness/gotosocial/internal/processing"
tlprocessor "github.com/superseriousbusiness/gotosocial/internal/processing/timeline"
@ -61,7 +61,6 @@ import (
gtsstorage "github.com/superseriousbusiness/gotosocial/internal/storage"
"github.com/superseriousbusiness/gotosocial/internal/subscriptions"
"github.com/superseriousbusiness/gotosocial/internal/timeline"
"github.com/superseriousbusiness/gotosocial/internal/tracing"
"github.com/superseriousbusiness/gotosocial/internal/transport"
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
"github.com/superseriousbusiness/gotosocial/internal/web"
@ -196,7 +195,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
}
// Initialize tracing (noop if not enabled).
if err := tracing.Initialize(); err != nil {
if err := observability.InitializeTracing(); err != nil {
return fmt.Errorf("error initializing tracing: %w", err)
}
@ -393,7 +392,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
}
// Initialize metrics.
if err := metrics.Initialize(state.DB); err != nil {
if err := observability.InitializeMetrics(state.DB); err != nil {
return fmt.Errorf("error initializing metrics: %w", err)
}
@ -426,12 +425,12 @@ var Start action.GTSAction = func(ctx context.Context) error {
// Add tracing middleware if enabled.
if config.GetTracingEnabled() {
middlewares = append(middlewares, tracing.InstrumentGin())
middlewares = append(middlewares, observability.TracingMiddleware())
}
// Add metrics middleware if enabled.
if config.GetMetricsEnabled() {
middlewares = append(middlewares, metrics.InstrumentGin())
middlewares = append(middlewares, observability.MetricsMiddleware())
}
middlewares = append(middlewares, []gin.HandlerFunc{

View file

@ -38,8 +38,8 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/language"
"github.com/superseriousbusiness/gotosocial/internal/log"
"github.com/superseriousbusiness/gotosocial/internal/metrics"
"github.com/superseriousbusiness/gotosocial/internal/middleware"
"github.com/superseriousbusiness/gotosocial/internal/observability"
"github.com/superseriousbusiness/gotosocial/internal/oidc"
tlprocessor "github.com/superseriousbusiness/gotosocial/internal/processing/timeline"
"github.com/superseriousbusiness/gotosocial/internal/router"
@ -47,7 +47,6 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/storage"
"github.com/superseriousbusiness/gotosocial/internal/subscriptions"
"github.com/superseriousbusiness/gotosocial/internal/timeline"
"github.com/superseriousbusiness/gotosocial/internal/tracing"
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
"github.com/superseriousbusiness/gotosocial/internal/web"
"github.com/superseriousbusiness/gotosocial/testrig"
@ -127,7 +126,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
}
config.SetInstanceLanguages(parsedLangs)
if err := tracing.Initialize(); err != nil {
if err := observability.InitializeTracing(); err != nil {
return fmt.Errorf("error initializing tracing: %w", err)
}
@ -195,7 +194,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
defer testrig.StopWorkers(state)
// Initialize metrics.
if err := metrics.Initialize(state.DB); err != nil {
if err := observability.InitializeMetrics(state.DB); err != nil {
return fmt.Errorf("error initializing metrics: %w", err)
}
@ -213,11 +212,11 @@ var Start action.GTSAction = func(ctx context.Context) error {
middleware.AddRequestID(config.GetRequestIDHeader()), // requestID middleware must run before tracing
}
if config.GetTracingEnabled() {
middlewares = append(middlewares, tracing.InstrumentGin())
middlewares = append(middlewares, observability.TracingMiddleware())
}
if config.GetMetricsEnabled() {
middlewares = append(middlewares, metrics.InstrumentGin())
middlewares = append(middlewares, observability.MetricsMiddleware())
}
middlewares = append(middlewares, []gin.HandlerFunc{

View file

@ -15,7 +15,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//go:build !nometrics
//go:build !nootel
package metrics

View file

@ -15,7 +15,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//go:build nometrics
//go:build nootel
package metrics

View file

@ -41,9 +41,8 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/db/bundb/migrations"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/log"
"github.com/superseriousbusiness/gotosocial/internal/metrics"
"github.com/superseriousbusiness/gotosocial/internal/observability"
"github.com/superseriousbusiness/gotosocial/internal/state"
"github.com/superseriousbusiness/gotosocial/internal/tracing"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect"
"github.com/uptrace/bun/dialect/pgdialect"
@ -324,11 +323,10 @@ func bunDB(sqldb *sql.DB, dialect func() schema.Dialect) *bun.DB {
// Add our SQL connection hooks.
db.AddQueryHook(queryHook{})
if config.GetTracingEnabled() {
db.AddQueryHook(tracing.InstrumentBun())
}
if config.GetMetricsEnabled() {
db.AddQueryHook(metrics.InstrumentBun())
metricsEnabled := config.GetMetricsEnabled()
tracingEnabled := config.GetTracingEnabled()
if metricsEnabled || tracingEnabled {
db.AddQueryHook(observability.InstrumentBun(tracingEnabled, metricsEnabled))
}
// table registration is needed for many-to-many, see:

View file

@ -15,29 +15,28 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//go:build notracing
//go:build !nootel
package tracing
package observability
import (
"errors"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/uptrace/bun"
"github.com/uptrace/bun/extra/bunotel"
metricnoop "go.opentelemetry.io/otel/metric/noop"
tracenoop "go.opentelemetry.io/otel/trace/noop"
)
func Initialize() error {
if config.GetTracingEnabled() {
return errors.New("tracing was disabled at build time")
func InstrumentBun(traces bool, metrics bool) bun.QueryHook {
opts := []bunotel.Option{
bunotel.WithFormattedQueries(true),
}
return nil
}
func InstrumentGin() gin.HandlerFunc {
return func(c *gin.Context) {}
}
func InstrumentBun() bun.QueryHook {
return nil
if !traces {
opts = append(opts, bunotel.WithTracerProvider(tracenoop.NewTracerProvider()))
}
if !metrics {
opts = append(opts, bunotel.WithMeterProvider(metricnoop.NewMeterProvider()))
}
return bunotel.NewQueryHook(
opts...,
)
}

View file

@ -15,24 +15,24 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//go:build !nometrics
//go:build !nootel
package metrics
package observability
import (
"context"
"errors"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/gin-gonic/gin"
"github.com/technologize/otel-go-contrib/otelginmetrics"
"github.com/uptrace/bun"
"github.com/uptrace/bun/extra/bunotel"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/prometheus"
"go.opentelemetry.io/otel/metric"
sdk "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/exemplar"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
)
@ -41,7 +41,7 @@ const (
serviceName = "GoToSocial"
)
func Initialize(db db.DB) error {
func InitializeMetrics(db db.DB) error {
if !config.GetMetricsEnabled() {
return nil
}
@ -66,6 +66,7 @@ func Initialize(db db.DB) error {
}
meterProvider := sdk.NewMeterProvider(
sdk.WithExemplarFilter(exemplar.AlwaysOffFilter),
sdk.WithResource(r),
sdk.WithReader(prometheusExporter),
)
@ -127,12 +128,6 @@ func Initialize(db db.DB) error {
return nil
}
func InstrumentGin() gin.HandlerFunc {
func MetricsMiddleware() gin.HandlerFunc {
return otelginmetrics.Middleware(serviceName)
}
func InstrumentBun() bun.QueryHook {
return bunotel.NewQueryHook(
bunotel.WithMeterProvider(otel.GetMeterProvider()),
)
}

View file

@ -15,30 +15,32 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//go:build nometrics
//go:build nootel
package metrics
package observability
import (
"errors"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/uptrace/bun"
)
func Initialize(db db.DB) error {
if config.GetMetricsEnabled() {
return errors.New("metrics was disabled at build time")
}
func InitializeMetrics(db db.DB) error {
return nil
}
func InitializeTracing() error {
return nil
}
func InstrumentGin() gin.HandlerFunc {
return func(c *gin.Context) {}
}
func InstrumentBun() bun.QueryHook {
func MetricsMiddleware() gin.HandlerFunc {
return nil
}
func TracingMiddleware() gin.HandlerFunc {
return nil
}
func InstrumentBun(traces bool, metrics bool) bun.QueryHook {
return nil
}

View file

@ -15,9 +15,9 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//go:build !notracing
//go:build !nootel
package tracing
package observability
import (
"context"
@ -25,8 +25,6 @@ import (
"codeberg.org/gruf/go-kv"
"github.com/gin-gonic/gin"
"github.com/uptrace/bun"
"github.com/uptrace/bun/extra/bunotel"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
@ -45,10 +43,10 @@ import (
const (
tracerKey = "gotosocial-server-tracer"
tracerName = "github.com/superseriousbusiness/gotosocial/internal/tracing"
tracerName = "github.com/superseriousbusiness/gotosocial/internal/observability"
)
func Initialize() error {
func InitializeTracing() error {
if !config.GetTracingEnabled() {
return nil
}
@ -119,7 +117,7 @@ func Initialize() error {
// InstrumentGin is a middleware injecting tracing information based on the
// otelgin implementation found at
// https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go
func InstrumentGin() gin.HandlerFunc {
func TracingMiddleware() gin.HandlerFunc {
provider := otel.GetTracerProvider()
tracer := provider.Tracer(
tracerName,
@ -182,9 +180,3 @@ func InjectRequestID() gin.HandlerFunc {
}
}
}
func InstrumentBun() bun.QueryHook {
return bunotel.NewQueryHook(
bunotel.WithFormattedQueries(true),
)
}

View file

@ -17,8 +17,7 @@ GO_GCFLAGS=${GO_GCFLAGS-}
# Available Go build tags, with explanation, followed by benefits of enabling it:
# - kvformat: enables prettier output of log fields (slightly better performance)
# - timetzdata: embed timezone database inside binary (allow setting local time inside Docker containers, at cost of 450KB)
# - notracing: disables compiling-in otel tracing support (reduced binary size, better performance)
# - nometrics: disables compiling-in otel metrics support (reduced binary size, better performance)
# - nootel: disables compiling-in otel support (reduced binary size)
# - noerrcaller: disables caller function prefix in errors (slightly better performance, at cost of err readability)
# - debug: enables /debug/pprof endpoint (adds debug, at performance cost)
# - debugenv: enables /debug/pprof endpoint if DEBUG=1 env during runtime (adds debug, at performance cost)