Skip to content

Commit e0cf70b

Browse files
committed
Add otel tracing to quotes-loadgen
1 parent 95f63e3 commit e0cf70b

5 files changed

Lines changed: 217 additions & 36 deletions

File tree

quotes-loadgen/go.mod

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,25 @@ go 1.24.3
55
require (
66
github.com/prometheus/client_golang v1.22.0
77
github.com/spf13/cobra v1.9.1
8+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0
9+
go.opentelemetry.io/otel v1.35.0
10+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0
11+
go.opentelemetry.io/otel/sdk v1.35.0
12+
go.opentelemetry.io/otel/trace v1.35.0
13+
google.golang.org/grpc v1.71.0
814
)
915

1016
require (
1117
github.com/beorn7/perks v1.0.1 // indirect
18+
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
1219
github.com/cespare/xxhash/v2 v2.3.0 // indirect
20+
github.com/felixge/httpsnoop v1.0.4 // indirect
1321
github.com/fsnotify/fsnotify v1.8.0 // indirect
22+
github.com/go-logr/logr v1.4.2 // indirect
23+
github.com/go-logr/stdr v1.2.2 // indirect
1424
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
25+
github.com/google/uuid v1.6.0 // indirect
26+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
1527
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
1628
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
1729
github.com/prometheus/client_model v0.6.1 // indirect
@@ -22,10 +34,17 @@ require (
2234
github.com/spf13/afero v1.12.0 // indirect
2335
github.com/spf13/cast v1.7.1 // indirect
2436
github.com/subosito/gotenv v1.6.0 // indirect
37+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
38+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
39+
go.opentelemetry.io/otel/metric v1.35.0 // indirect
40+
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
2541
go.uber.org/atomic v1.9.0 // indirect
2642
go.uber.org/multierr v1.9.0 // indirect
43+
golang.org/x/net v0.35.0 // indirect
2744
golang.org/x/sys v0.30.0 // indirect
28-
golang.org/x/text v0.21.0 // indirect
45+
golang.org/x/text v0.22.0 // indirect
46+
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
47+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
2948
google.golang.org/protobuf v1.36.5 // indirect
3049
gopkg.in/yaml.v3 v3.0.1 // indirect
3150
)

quotes-loadgen/go.sum

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,34 @@
11
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
22
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
3+
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
4+
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
35
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
46
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
57
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
68
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
79
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
810
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
11+
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
12+
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
913
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
1014
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
1115
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
1216
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
17+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
18+
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
19+
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
20+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
21+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
1322
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
1423
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
24+
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
25+
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
1526
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
1627
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
28+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
29+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
30+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
31+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
1732
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
1833
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
1934
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
@@ -38,8 +53,8 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ
3853
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
3954
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
4055
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
41-
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
42-
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
56+
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
57+
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
4358
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
4459
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
4560
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
@@ -61,14 +76,44 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
6176
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
6277
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
6378
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
79+
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
80+
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
81+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
82+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
83+
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
84+
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
85+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
86+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
87+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
88+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
89+
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
90+
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
91+
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
92+
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
93+
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
94+
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
95+
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
96+
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
97+
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
98+
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
6499
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
65100
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
101+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
102+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
66103
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
67104
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
105+
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
106+
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
68107
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
69108
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
70-
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
71-
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
109+
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
110+
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
111+
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
112+
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
113+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
114+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
115+
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
116+
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
72117
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
73118
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
74119
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

quotes-loadgen/internal/loadgen/loadgen.go

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package loadgen
22

33
import (
4-
"fmt"
4+
"context"
55
"net/http"
66
"os"
77
"strings"
@@ -10,13 +10,18 @@ import (
1010

1111
"log/slog"
1212

13-
"github.com/prometheus/client_golang/prometheus"
14-
"github.com/prometheus/client_golang/prometheus/promhttp"
1513
"github.com/spf13/cobra"
1614
"github.com/spf13/viper"
15+
16+
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
17+
18+
"github.com/nais/examples/quotes-loadgen/internal/metrics"
19+
"github.com/nais/examples/quotes-loadgen/internal/otel"
20+
t "go.opentelemetry.io/otel/trace"
1721
)
1822

1923
var (
24+
tracer t.Tracer
2025
urls []string
2126
duration int
2227
requestsPerSecond int
@@ -26,32 +31,19 @@ var (
2631

2732
metricsEnabled bool
2833
metricsPort int
29-
requestsTotal = prometheus.NewCounterVec(
30-
prometheus.CounterOpts{
31-
Name: "loadgen_requests_total",
32-
Help: "Total number of requests made by the load generator",
33-
},
34-
[]string{"url", "status"},
35-
)
36-
requestDuration = prometheus.NewHistogramVec(
37-
prometheus.HistogramOpts{
38-
Name: "loadgen_request_duration_seconds",
39-
Help: "Histogram of request durations",
40-
Buckets: prometheus.DefBuckets,
41-
},
42-
[]string{"url"},
43-
)
4434
)
4535

4636
func init() {
37+
// Initialize OpenTelemetry Tracing
38+
ctx := context.Background()
39+
tracer, _ = otel.InitTracer(ctx)
4740
logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{}))
4841

4942
// Initialize viper with environment variable prefix
5043
viper.SetEnvPrefix("LOADGEN")
5144
viper.AutomaticEnv()
5245

53-
prometheus.MustRegister(requestsTotal)
54-
prometheus.MustRegister(requestDuration)
46+
metrics.Register()
5547
}
5648

5749
func NewLoadCommand() *cobra.Command {
@@ -83,6 +75,9 @@ func NewLoadCommand() *cobra.Command {
8375
stop := make(chan struct{})
8476

8577
// Start load generation
78+
client := http.Client{
79+
Transport: otelhttp.NewTransport(http.DefaultTransport),
80+
}
8681
for _, url := range urlList {
8782
for i := 0; i < requestsPerSecond; i++ {
8883
wg.Add(1)
@@ -96,27 +91,42 @@ func NewLoadCommand() *cobra.Command {
9691
default:
9792
}
9893
}
94+
// Parent span for the request
95+
ctx, parentSpan := tracer.Start(context.Background(), "loadgen.request")
9996
start := time.Now()
100-
resp, err := http.Get(url)
97+
// Child span for the HTTP GET
98+
ctx, httpSpan := tracer.Start(ctx, "http.get")
99+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
100+
if err != nil {
101+
logger.Error("Error creating request", slog.String("url", url), slog.Any("error", err))
102+
if metricsEnabled {
103+
metrics.RequestsTotal.WithLabelValues(url, "error").Inc()
104+
}
105+
httpSpan.End()
106+
parentSpan.End()
107+
continue
108+
}
109+
resp, err := client.Do(req)
101110
if err != nil {
102111
logger.Error("Error loading URL", slog.String("url", url), slog.Any("error", err))
103112
if metricsEnabled {
104-
requestsTotal.WithLabelValues(url, "error").Inc()
113+
metrics.RequestsTotal.WithLabelValues(url, "error").Inc()
105114
}
106115
} else {
107116
logger.Info("Loaded URL", "url", url, "status", resp.StatusCode)
108117
if metricsEnabled {
109-
requestsTotal.WithLabelValues(url, http.StatusText(resp.StatusCode)).Inc()
110-
requestDuration.WithLabelValues(url).Observe(time.Since(start).Seconds())
118+
metrics.RequestsTotal.WithLabelValues(url, http.StatusText(resp.StatusCode)).Inc()
119+
metrics.RequestDuration.WithLabelValues(url).Observe(time.Since(start).Seconds())
111120
}
112121
resp.Body.Close()
113122
}
123+
httpSpan.End()
124+
parentSpan.End()
114125
time.Sleep(time.Second / time.Duration(requestsPerSecond))
115126
}
116127
}(url)
117128
}
118129
}
119-
120130
// Stop load generation after the specified duration
121131
if duration != 0 {
122132
time.Sleep(time.Duration(duration) * time.Second)
@@ -177,14 +187,9 @@ func NewLoadCommand() *cobra.Command {
177187

178188
if metricsEnabled {
179189
logger.Info("Starting Prometheus metrics server", slog.Int("port", metricsPort))
180-
startMetricsServer()
190+
metrics.StartMetricsServer(metricsPort)
181191
}
182192
}
183193

184194
return cmd
185195
}
186-
187-
func startMetricsServer() {
188-
http.Handle("/metrics", promhttp.Handler())
189-
go http.ListenAndServe(fmt.Sprintf(":%d", metricsPort), nil)
190-
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package metrics
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
7+
"github.com/prometheus/client_golang/prometheus"
8+
"github.com/prometheus/client_golang/prometheus/promhttp"
9+
)
10+
11+
var (
12+
RequestsTotal = prometheus.NewCounterVec(
13+
prometheus.CounterOpts{
14+
Name: "loadgen_requests_total",
15+
Help: "Total number of requests made by the load generator",
16+
},
17+
[]string{"url", "status"},
18+
)
19+
RequestDuration = prometheus.NewHistogramVec(
20+
prometheus.HistogramOpts{
21+
Name: "loadgen_request_duration_seconds",
22+
Help: "Histogram of request durations",
23+
Buckets: prometheus.DefBuckets,
24+
},
25+
[]string{"url"},
26+
)
27+
)
28+
29+
func Register() {
30+
prometheus.MustRegister(RequestsTotal)
31+
prometheus.MustRegister(RequestDuration)
32+
}
33+
34+
func StartMetricsServer(port int) {
35+
http.Handle("/metrics", promhttp.Handler())
36+
go http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
37+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package otel
2+
3+
import (
4+
"context"
5+
"log"
6+
"net"
7+
"os"
8+
9+
"go.opentelemetry.io/otel"
10+
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
11+
"go.opentelemetry.io/otel/sdk/resource"
12+
"go.opentelemetry.io/otel/sdk/trace"
13+
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
14+
oteltrace "go.opentelemetry.io/otel/trace"
15+
"google.golang.org/grpc"
16+
"google.golang.org/grpc/credentials"
17+
)
18+
19+
// InitTracer sets up OpenTelemetry tracing using environment variables.
20+
func InitTracer(ctx context.Context) (oteltrace.Tracer, func()) {
21+
endpoint := os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT")
22+
insecure := os.Getenv("OTEL_EXPORTER_OTLP_INSECURE") == "true"
23+
serviceName := os.Getenv("OTEL_SERVICE_NAME")
24+
if serviceName == "" {
25+
serviceName = "quotes-loadgen"
26+
}
27+
res, err := resource.New(ctx,
28+
resource.WithFromEnv(),
29+
resource.WithProcess(),
30+
resource.WithTelemetrySDK(),
31+
resource.WithHost(),
32+
resource.WithAttributes(
33+
semconv.ServiceName(serviceName),
34+
),
35+
)
36+
if err != nil {
37+
log.Printf("failed to create resource: %v", err)
38+
}
39+
var opts []otlptracegrpc.Option
40+
if endpoint != "" {
41+
opts = append(opts, otlptracegrpc.WithEndpoint(endpoint))
42+
}
43+
if insecure {
44+
opts = append(opts, otlptracegrpc.WithDialOption(grpc.WithTransportCredentials(insecureCreds{})))
45+
}
46+
exporter, err := otlptracegrpc.New(ctx, opts...)
47+
if err != nil {
48+
log.Printf("failed to create OTLP trace exporter: %v", err)
49+
return nil, func() {}
50+
}
51+
bsp := trace.NewBatchSpanProcessor(exporter)
52+
tp := trace.NewTracerProvider(
53+
trace.WithResource(res),
54+
trace.WithSpanProcessor(bsp),
55+
)
56+
otel.SetTracerProvider(tp)
57+
tracer := tp.Tracer(serviceName)
58+
return tracer, func() {
59+
_ = tp.Shutdown(ctx)
60+
}
61+
}
62+
63+
// insecureCreds implements grpc.TransportCredentials for insecure connection
64+
// (copied from original loadgen.go)
65+
type insecureCreds struct{}
66+
67+
func (insecureCreds) ClientHandshake(ctx context.Context, s string, conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
68+
return conn, nil, nil
69+
}
70+
func (insecureCreds) ServerHandshake(conn net.Conn) (net.Conn, credentials.AuthInfo, error) {
71+
return conn, nil, nil
72+
}
73+
func (insecureCreds) Info() credentials.ProtocolInfo { return credentials.ProtocolInfo{} }
74+
func (insecureCreds) Clone() credentials.TransportCredentials { return insecureCreds{} }
75+
func (insecureCreds) OverrideServerName(string) error { return nil }

0 commit comments

Comments
 (0)