Skip to content

Commit 65e059f

Browse files
committed
update manual instr and sampling
Signed-off-by: Benedikt Bongartz <bongartz@klimlive.de>
1 parent 6e15951 commit 65e059f

4 files changed

Lines changed: 62 additions & 45 deletions

File tree

04-manual-instrumentation.md

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ As a basis for the instrumentation we use [backend4](./app/backend4/main.go). To
66

77
# Initialize OpenTelemetry-go-sdk
88

9-
### TODO
9+
Before we start instrumenting our application, we should create a standard tracer and register it globally. This ensures that the same exporter is used throughout the application and that the same process steps are performed.
1010

1111
```diff
1212
func main() {
@@ -21,9 +21,9 @@ func main() {
2121
```
2222

2323

24-
## Create and register a global trace provider
24+
### Create and register a global trace provider
2525

26-
### TODO
26+
First we have to create a tracer that identifies our specific service.
2727

2828
```diff
2929
+var tracer = otel.GetTracerProvider().Tracer("github.com/kubecon-eu-2024/backend")
@@ -42,14 +42,12 @@ Keep in mind that any Span that is created `MUST` also be ended. This is the res
4242
When defining a span name, it's important to choose descriptive and meaningful names that accurately reflect the operation being performed.
4343

4444
```diff
45-
mux.HandleFunc("GET /rolldice", func(w http.ResponseWriter, r *http.Request) {
46-
+ var span trace.Span
47-
+ ctx, span := tracer.Start(r.Context(), "rolldice")
48-
+ defer span.End()
49-
player := "Anonymous player"
50-
if p := r.URL.Query().Get("player"); p != "" {
51-
player = p
52-
}
45+
mux := http.NewServeMux()
46+
47+
+ registerHandleFunc := func(pattern string, h http.HandlerFunc) {
48+
+ route := strings.Split(pattern, " ")
49+
+ mux.Handle(pattern, otelhttp.NewHandler(otelhttp.WithRouteTag(route[len(route)-1], h), pattern))
50+
+ }
5351
```
5452

5553
To simulate a more complex behaviour, we find a `causeError` function in the `/rolldice` handler source code of the backend4 application. Since there is a defined probability that errors will occur, it makes sense to take this part into account as well.
@@ -62,14 +60,13 @@ RecordError will record err as an exception span event for this span. An additio
6260

6361
```diff
6462
func causeError(ctx context.Context, rate int) error {
65-
+ var span trace.Span
66-
+ _, span = tracer.Start(ctx, "causeError")
63+
+ _, span := tracer.Start(ctx, "causeError")
6764
+ defer span.End()
6865

6966
randomNumber := rand.Intn(100)
70-
+ span.AddEvent(fmt.Sprintf("random nr: %d", randomNumber))
67+
+ span.AddEvent("roll", trace.WithAttributes(attribute.Int("number", randomNumber)))
7168
if randomNumber < rate {
72-
err := fmt.Errorf("internal server error")
69+
err := fmt.Errorf("number(%d)) < rate(%d)", randomNumber, rate)
7370
+ span.RecordError(err)
7471
+ span.SetStatus(codes.Error, "some error occured")
7572
return err
@@ -88,11 +85,10 @@ AddEvent adds an event with the provided name and optionsAddEvent adds an event
8885

8986
```diff
9087
func causeDelay(ctx context.Context, rate int) {
91-
+ var span trace.Span
92-
+ _, span = tracer.Start(ctx, "causeDelay")
88+
+ _, span := tracer.Start(ctx, "causeDelay")
9389
+ defer span.End()
9490
randomNumber := rand.Intn(100)
95-
+ span.AddEvent(fmt.Sprintf("random nr: %d", randomNumber))
91+
+ span.AddEvent("roll", trace.WithAttributes(attribute.Int("number", randomNumber)))
9692
if randomNumber < rate {
9793
time.Sleep(time.Duration(2+rand.Intn(3)) * time.Second)
9894
}
@@ -103,30 +99,14 @@ func causeDelay(ctx context.Context, rate int) {
10399

104100
Once the code has been instrumented, we can use `go mod tidy` to update the existing `go.mod` file and start testing our application.
105101

106-
## Configuring an OTLP exporter and setting the endpoint
107-
108-
To get quick feedback, we can run a Jaeger instance locally and point our application at it. Jaeger all-in-one will make this easy.
109-
110-
```bash
111-
docker run --rm -it -p 127.0.0.1:4317:4317 -p 127.0.0.1:16686:16686 -e COLLECTOR_OTLP_ENABLED=true -e LOG_LEVEL=debug jaegertracing/all-in-one:latest
112-
```
113-
114-
Now we can configure our application with a specific `RATE_ERROR` and `RATE_DELAY` in `%`. This indicates how many traces should be delayed and/or cause an error.
115-
116-
Finally we need to configure the OpenTelemetry-SDK, by default we can use common environment variables. [Documentation](https://opentelemetry.io/docs/languages/sdk-configuration/)
117-
118-
```bash
119-
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 OTEL_SERVICE_NAME=go-backend RATE_ERROR=20 RATE_HIGH_DELAY=20 go run app/backend4/main.go
120-
```
121-
122102
## Apply Backend4 to the Kubernetes test cluster
123103

124104
Now that we have instrumentalised `backend4`, we can use it as a drop-in replacement for `backend2`.
125105

126106
For this we need to build and provide a new container image or use the prepared `backend4:with-instr` version.
127107

128108
```bash
129-
kubectl apply -f https://raw.githubusercontent.com/pavolloffay/kubecon-eu-2024-opentelemetry-kubernetes-tracing-tutorial/main/backend/04-backend.yaml
109+
kubectl apply -f https://raw.githubusercontent.com/pavolloffay/kubecon-eu-2024-opentelemetry-kubernetes-tracing-tutorial/main/app/instrumentation-replace-backend2.yaml
130110
```
131111

132112
When using `kubectl diff` we should see something similar to this.
@@ -153,8 +133,40 @@ spec:
153133
- name: backend2
154134
- image: ghcr.io/pavolloffay/kubecon-eu-2024-opentelemetry-kubernetes-tracing-tutorial-backend2:latest
155135
+ image: ghcr.io/frzifus/kubecon-eu-2024-opentelemetry-kubernetes-tracing-tutorial-backend4:with-instr
136+
env:
137+
+ - name: RATE_ERROR
138+
+ value: 20
139+
+ - name: RATE_HIGH_DELAY
140+
+ value: 20
141+
```
142+
143+
> [!NOTE]
144+
> This is an optional section.
145+
146+
<details>
147+
148+
<summary>Run and test backend 4 locally (shorter development cycle)</summary>
149+
150+
## Configuring an OTLP exporter and setting the endpoint
151+
152+
To get quick feedback, we can run a Jaeger instance locally and point our application at it. Jaeger all-in-one will make this easy.
153+
154+
```bash
155+
docker run --rm -it -p 127.0.0.1:4317:4317 -p 127.0.0.1:16686:16686 -e COLLECTOR_OTLP_ENABLED=true -e LOG_LEVEL=debug jaegertracing/all-in-one:latest
156156
```
157157

158+
Now we can configure our application with a specific `RATE_ERROR` and `RATE_DELAY` in `%`. This indicates how many traces should be delayed and/or cause an error.
159+
160+
Finally we need to configure the OpenTelemetry-SDK, by default we can use common environment variables. [Documentation](https://opentelemetry.io/docs/languages/sdk-configuration/)
161+
162+
```bash
163+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 OTEL_SERVICE_NAME=go-backend RATE_ERROR=20 RATE_HIGH_DELAY=20 go run main.go
164+
```
165+
166+
</details>
167+
168+
---
169+
158170
By instrumenting our applications, whether manually or automatically, we get more telemetry data to help us understand our system. However, since a large amount of telemetry data also generates costs, in the next chapter we will discuss how we can utilise this amount in a meaningful way.
159171

160172
---

05-sampling.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ This tutorial step covers the basic usage of the OpenTelemetry Collector on Kube
44

55
## Overview
66

7-
![tracing setup](images/tracing-setup.png)
7+
In chapter 3 we saw the [schematic structure of the dice game application](https://github.com/pavolloffay/kubecon-eu-2024-opentelemetry-kubernetes-tracing-tutorial/blob/main/03-auto-instrumentation.md#application-description). The following diagram illustrates how the telemetry data collected there is exported and stored. [excalidraw](https://excalidraw.com/#json=15BrdSOMEkc9RA5cxeqwz,urTmfk01mbx7V-PpQI7KgA)
88

9-
[excalidraw](https://excalidraw.com/#json=15BrdSOMEkc9RA5cxeqwz,urTmfk01mbx7V-PpQI7KgA)
9+
![tracing setup](images/tracing-setup.png)
1010

1111
## Sampling, what does it mean and why is it important?
1212

app/backend4/main.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http"
99
"os"
1010
"strconv"
11+
"strings"
1112
"time"
1213

1314
"github.com/prometheus/client_golang/prometheus"
@@ -74,8 +75,12 @@ func main() {
7475

7576
mux := http.NewServeMux()
7677

77-
const path = "GET /rolldice"
78-
mux.Handle(path, otelhttp.NewMiddleware(path)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
78+
registerHandleFunc := func(pattern string, h http.HandlerFunc) {
79+
route := strings.Split(pattern, " ")
80+
mux.Handle(pattern, otelhttp.NewHandler(otelhttp.WithRouteTag(route[len(route)-1], h), pattern))
81+
}
82+
83+
registerHandleFunc("GET /rolldice", func(w http.ResponseWriter, r *http.Request) {
7984
player := "Anonymous player"
8085
if p := r.URL.Query().Get("player"); p != "" {
8186
player = p
@@ -101,9 +106,9 @@ func main() {
101106
w.WriteHeader(http.StatusInternalServerError)
102107
}
103108

104-
})))
109+
})
105110

106-
mux.HandleFunc("GET /metrics", promhttp.Handler().ServeHTTP)
111+
registerHandleFunc("GET /metrics", promhttp.Handler().ServeHTTP)
107112
srv := &http.Server{
108113
Addr: "0.0.0.0:5165",
109114
Handler: mux,
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ spec:
3232
- name: RATE_HIGH_DELAY
3333
value: 20
3434
# NOTE: alternative to instrumentation annotation
35-
# - name: OTEL_EXPORTER_OTLP_ENDPOINT
36-
# value: http://otel-collector.observability-backend.svc.cluster.local:4317
37-
# - name: OTEL_SERVICE_NAME
38-
# value: go-backend
35+
- name: OTEL_EXPORTER_OTLP_ENDPOINT
36+
value: http://otel-collector.observability-backend.svc.cluster.local:4317
37+
- name: OTEL_SERVICE_NAME
38+
value: go-backend

0 commit comments

Comments
 (0)