telemetry: added tracing support

This commit is contained in:
Tigor Hutasuhut 2024-04-13 00:15:31 +07:00
parent 4fdc760554
commit c31c909c7b
13 changed files with 129 additions and 16 deletions

View file

@ -15,7 +15,7 @@ follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html", "sql", "templ"]
include_file = []
include_file = [".env"]
kill_delay = "500ms"
log = "build-errors.log"
poll = false

View file

@ -19,6 +19,8 @@ type ListSubredditsResult struct {
}
func (api *API) ListSubreddits(ctx context.Context, arg ListSubredditsParams) (result ListSubredditsResult, err error) {
ctx, span := tracer.Start(ctx, "api.ListSubreddits")
defer span.End()
if arg.Name != "" {
result.Data, err = api.queries.SubredditsSearch(ctx, queries.SubredditsSearchParams{
Name: "%" + arg.Name + "%",

7
api/tracer.go Normal file
View file

@ -0,0 +1,7 @@
package api
import (
"go.opentelemetry.io/otel"
)
var tracer = otel.Tracer("api")

View file

@ -20,7 +20,11 @@ var serveCmd = &cobra.Command{
Short: "Starts the HTTP Server",
SilenceUsage: true,
Run: func(cmd *cobra.Command, args []string) {
tele := telemetry.New()
tele, err := telemetry.New(cmd.Context(), cfg)
if err != nil {
log.New(cmd.Context()).Err(err).Error("failed to start telemetry")
os.Exit(1)
}
defer tele.Close()
db, err := db.Open(cfg)

View file

@ -36,4 +36,13 @@ var DefaultConfig = map[string]any{
"telemetry.openobserve.log.buffer.timeout": "500ms",
"telemetry.openobserve.log.username": "root@example.com",
"telemetry.openobserve.log.password": "Complexpass#123",
"telemetry.openobserve.trace.enable": true,
"telemetry.openobserve.trace.url": "http://localhost:5080/api/default/v1/traces",
"telemetry.openobserve.trace.auth": "Basic AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"telemetry.trace.ratio": 1,
"runtime.version": "0.0.1",
"runtime.environment": "development",
}

View file

@ -9,6 +9,9 @@ import (
sqldblogger "github.com/simukti/sqldb-logger"
"github.com/tigorlazuardi/redmage/config"
"github.com/tigorlazuardi/redmage/pkg/errs"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"github.com/XSAM/otelsql"
)
var Migrations fs.FS
@ -16,11 +19,18 @@ var Migrations fs.FS
func Open(cfg *config.Config) (*sql.DB, error) {
driver := cfg.String("db.driver")
dsn := cfg.String("db.string")
db, err := sql.Open(driver, dsn)
db, err := otelsql.Open(driver, dsn, otelsql.WithAttributes(
semconv.DBSystemSqlite,
))
if err != nil {
return db, errs.Wrapw(err, "failed to open database", "driver", driver)
}
err = otelsql.RegisterDBStatsMetrics(db, otelsql.WithAttributes(semconv.DBSystemSqlite))
if err != nil {
return db, errs.Wrapw(err, "failed to instrument database with otel")
}
if cfg.Bool("db.automigrate") {
goose.SetLogger(&gooseLogger{})
goose.SetBaseFS(Migrations)

16
go.mod
View file

@ -28,9 +28,22 @@ require (
github.com/teivah/broadcast v0.1.0
)
require github.com/samber/lo v1.38.1 // indirect
require (
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/samber/lo v1.38.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0 // indirect
go.opentelemetry.io/proto/otlp v1.1.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
google.golang.org/grpc v1.63.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
)
require (
github.com/XSAM/otelsql v0.29.0
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
@ -46,6 +59,7 @@ require (
github.com/samber/slog-multi v1.0.2
github.com/sethvargo/go-retry v0.2.4 // indirect
go.opentelemetry.io/otel v1.25.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0
go.opentelemetry.io/otel/metric v1.25.0 // indirect
go.opentelemetry.io/otel/sdk v1.25.0
go.opentelemetry.io/otel/trace v1.25.0 // indirect

22
go.sum
View file

@ -10,6 +10,8 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/XSAM/otelsql v0.29.0 h1:pEw9YXXs8ZrGRYfDc0cmArIz9lci5b42gmP5+tA1Huc=
github.com/XSAM/otelsql v0.29.0/go.mod h1:d3/0xGIGC5RVEE+Ld7KotwaLy6zDeaF3fLJHOPpdN2w=
github.com/a-h/templ v0.2.648 h1:A1ggHGIE7AONOHrFaDTM8SrqgqHL6fWgWCijQ21Zy9I=
github.com/a-h/templ v0.2.648/go.mod h1:SA7mtYwVEajbIXFRh3vKdYm/4FYyLQAtPH1+KxzGPA8=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
@ -22,6 +24,8 @@ github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8=
github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@ -78,6 +82,8 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
@ -220,6 +226,10 @@ go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc=
go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs=
go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k=
go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0 h1:dT33yIHtmsqpixFsSQPwNeY5drM9wTcoL8h0FWF4oGM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0 h1:Mbi5PKN7u322woPa85d7ebZ+SOvEoPvoiBu+ryHWgfA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0/go.mod h1:e7ciERRhZaOZXVjx5MiL8TK5+Xv7G5Gv5PA2ZDEJdL8=
go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA=
go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s=
go.opentelemetry.io/otel/sdk v1.10.0/go.mod h1:vO06iKzD5baltJz1zarxMCNHFpUlUiOy4s65ECtn6kE=
@ -230,6 +240,8 @@ go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om
go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU=
go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM=
go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I=
go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
@ -240,6 +252,8 @@ golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -254,12 +268,20 @@ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0=
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8=
google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View file

@ -4,30 +4,65 @@ import (
"context"
"time"
"github.com/tigorlazuardi/redmage/config"
"github.com/tigorlazuardi/redmage/pkg/errs"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
type Telemetry struct {
tracer *trace.TracerProvider
tracer *sdktrace.TracerProvider
}
func New() Telemetry {
func New(ctx context.Context, cfg *config.Config) (tele Telemetry, err error) {
otel.SetTextMapPropagator(createPropagator())
provider := createProvider()
otel.SetTracerProvider(provider)
return Telemetry{
tracer: provider,
provider, err := createProvider(ctx, cfg)
if err != nil {
return tele, err
}
tele.tracer = provider
otel.SetTracerProvider(provider)
return tele, err
}
func createPropagator() propagation.TextMapPropagator {
return propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
}
func createProvider() *trace.TracerProvider {
return trace.NewTracerProvider()
func createProvider(ctx context.Context, cfg *config.Config) (*sdktrace.TracerProvider, error) {
opts := []sdktrace.TracerProviderOption{
sdktrace.WithSampler(sdktrace.TraceIDRatioBased(cfg.Float64("telemetry.trace.ratio"))),
}
if cfg.Bool("telemetry.openobserve.trace.enable") {
url := cfg.String("telemetry.openobserve.trace.url")
o2exporter, err := otlptracehttp.New(ctx,
otlptracehttp.WithEndpointURL(url),
otlptracehttp.WithHeaders(map[string]string{
"Authorization": cfg.String("telemetry.openobserve.trace.auth"),
}),
)
if err != nil {
return nil, errs.Wrap(err)
}
opts = append(opts, sdktrace.WithBatcher(o2exporter))
}
res := resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("redmage"),
semconv.ServiceVersionKey.String(cfg.String("runtime.version")),
attribute.String("environment", cfg.String("runtime.environment")),
)
opts = append(opts, sdktrace.WithResource(res))
return sdktrace.NewTracerProvider(opts...), nil
}
func (te *Telemetry) Close() error {

View file

@ -9,7 +9,9 @@ import (
)
func (routes *Routes) PageHome(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ctx, span := tracer.Start(r.Context(), "routes.PageHome")
defer span.End()
vc := views.NewContext(routes.Config, r)
params := parseSubredditListQuery(r)

View file

@ -6,6 +6,7 @@ import (
"github.com/go-chi/chi/v5"
chimiddleware "github.com/go-chi/chi/v5/middleware"
"github.com/riandyrn/otelchi"
"github.com/tigorlazuardi/redmage/api"
"github.com/tigorlazuardi/redmage/config"
"github.com/tigorlazuardi/redmage/server/routes/middleware"
@ -29,6 +30,7 @@ func (routes *Routes) Register(router chi.Router) {
}
func (routes *Routes) registerV1APIRoutes(router chi.Router) {
router.Use(otelchi.Middleware("redmage"))
router.Use(chimiddleware.RequestLogger(middleware.ChiLogger{}))
router.Use(chimiddleware.SetHeader("Content-Type", "application/json"))
@ -39,6 +41,7 @@ func (routes *Routes) registerWWWRoutes(router chi.Router) {
router.Mount("/public", http.StripPrefix("/public", http.FileServer(http.FS(routes.PublicDir))))
router.Group(func(r chi.Router) {
r.Use(otelchi.Middleware("redmage"))
r.Use(chimiddleware.RequestID)
r.Use(chimiddleware.RequestLogger(middleware.ChiLogger{}))
r.Use(chimiddleware.SetHeader("Content-Type", "text/html; charset=utf-8"))

7
server/routes/trace.go Normal file
View file

@ -0,0 +1,7 @@
package routes
import (
"go.opentelemetry.io/otel"
)
var tracer = otel.Tracer("server/routes")

View file

@ -7,7 +7,6 @@ import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/riandyrn/otelchi"
"github.com/tigorlazuardi/redmage/api"
"github.com/tigorlazuardi/redmage/config"
"github.com/tigorlazuardi/redmage/pkg/caller"
@ -46,7 +45,6 @@ func (srv *Server) Start(exit <-chan struct{}) error {
func New(cfg *config.Config, api *api.API, publicDir fs.FS) *Server {
router := chi.NewRouter()
router.Use(otelchi.Middleware("redmage"))
routes := routes.Routes{
API: api,