Skip to content

Commit

Permalink
new package support: go-redis/v8
Browse files Browse the repository at this point in the history
  • Loading branch information
minimAluminiumalism authored and wilsonxscai committed Dec 25, 2024
1 parent 29de25c commit 92cd325
Show file tree
Hide file tree
Showing 16 changed files with 1,210 additions and 0 deletions.
7 changes: 7 additions & 0 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Tracing instrumentation is provided for the following Go libraries.
- [`github.com/segmentio/kafka-go`](#githubcomsegmentiokafka-go)
- [`google.golang.org/grpc`](#googlegolangorggrpc)
- [`net/http`](#nethttp)
- [`github.com/go-redis/redis/v8`](#githubcomgo-redisredisv8)

### database/sql

Expand Down Expand Up @@ -51,3 +52,9 @@ Supported version ranges:
Supported version ranges:

- `go1.12` to `go1.23.4`

### github.com/go-redis/redis/v8

[Package documentation](github.com/go-redis/redis/v8)

- `v8.0.0` to `v8.11.5`
7 changes: 7 additions & 0 deletions examples/httpRedis/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM golang:1.23.4@sha256:70031844b8c225351d0bb63e2c383f80db85d92ba894e3da7e13bcf80efa9a37
WORKDIR /app
COPY ./*.go .
RUN go mod init main
RUN go mod tidy
RUN go build -o main
ENTRYPOINT ["/app/main"]
75 changes: 75 additions & 0 deletions examples/httpRedis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Example of Auto instrumentation of HTTP server + Redis

This example only test [go-redis/v8](github.com/go-redis/redis/v8).

**It is highly recommended to deploy the demo using docker compose**.


## Docker compose

Setup the example:

```
docker compose up
```

Add a key-value pair to redis using below command:

```
curl -X POST http://localhost:8080/set -d '{"key":"name", "value":"Alice"}'
```

Every hit to the server should generate a trace that we can observe in [Jaeger UI](http://localhost:16686/).


## Local deployment

### Setup OpenTelemetry Collector and Jaeger

You can setup a local [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) and start it.

Assuming you've exposed port `4318`, and configured the [Jaeger](jaegertracing.io/docs) backend service in collector.


### Setup auto-instrumentation binary

Build the binary

```
make build
```

You will get binary `otel-go-instrumentation` in current directory. Then start instrumenting the target app

```
sudo OTEL_GO_AUTO_TARGET_EXE=</path/to/executable_app> OTEL_SERVICE_NAME=eBPFApp OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 OTEL_GO_AUTO_INCLUDE_DB_STATEMENT=true ./otel-go-instrumentation
```

### Setup and run the demo
Build and run

```
go build -o main
./main
```

Set

```
curl -X POST http://localhost:8080/set -d '{"key":"name", "value":"Alice"}'
```

Get

```
curl -X POST http://localhost:8080/get -d '{"key":"name"}'
```

Sadd

```
curl -X POST http://localhost:8080/sadd -d '{"key":"mySet", "values":["val1", "val2", "val3", "val4"]}'
```

You can observe the trace in [Jaeger UI](http://localhost:16686/).
70 changes: 70 additions & 0 deletions examples/httpRedis/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
version: "3.9"

networks:
default:
name: http-redis-network
driver: bridge

services:
http-redis:
depends_on:
- jaeger
- redis
build:
context: .
dockerfile: ./Dockerfile
pid: "host"
ports:
- "8080:8080"
volumes:
- /proc:/host/proc
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379

redis:
image: redis:latest
ports:
- "6379:6379"
volumes:
- redis_data:/data
restart: unless-stopped
deploy:
resources:
limits:
memory: 256M

go-auto:
depends_on:
- http-redis
build:
context: ../..
dockerfile: Dockerfile
privileged: true
pid: "host"
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4318
- OTEL_GO_AUTO_TARGET_EXE=/app/main
- OTEL_GO_AUTO_INCLUDE_DB_STATEMENT=true
- OTEL_SERVICE_NAME=eBPF-httpRedis
- OTEL_PROPAGATORS=tracecontext,baggage
- CGO_ENABLED=1
volumes:
- /proc:/host/proc

jaeger:
image: jaegertracing/all-in-one:1.60@sha256:4fd2d70fa347d6a47e79fcb06b1c177e6079f92cba88b083153d56263082135e
ports:
- "16686:16686"
- "14268:14268"
environment:
- COLLECTOR_OTLP_ENABLED=true
- LOG_LEVEL=debug
deploy:
resources:
limits:
memory: 300M
restart: unless-stopped

volumes:
redis_data:
10 changes: 10 additions & 0 deletions examples/httpRedis/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module go.opentelemetry.io/auto/examples/httpRedis

go 1.23.1

require github.com/go-redis/redis/v8 v8.11.5

require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
)
24 changes: 24 additions & 0 deletions examples/httpRedis/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
147 changes: 147 additions & 0 deletions examples/httpRedis/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package main

import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"time"

"github.com/go-redis/redis/v8"
)

var rdb *redis.Client

func main() {
initRedis()

http.HandleFunc("/set", setHandler)
http.HandleFunc("/get", getHandler)
http.HandleFunc("/setex", setexHandler)
http.HandleFunc("/sadd", saddHandler)

log.Println("Starting server on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}

func initRedis() {
redisHost := os.Getenv("REDIS_HOST")
redisPort := os.Getenv("REDIS_PORT")
redisAddr := fmt.Sprintf("%s:%s", redisHost, redisPort)
if redisHost == "" || redisPort == "" {
redisAddr = "localhost:6379"
}
rdb = redis.NewClient(&redis.Options{
Addr: redisAddr,
Password: "",
DB: 0,
})
}

func setHandler(w http.ResponseWriter, r *http.Request) {
var req struct {
Key string `json:"key"`
Value string `json:"value"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err := rdb.Set(r.Context(), req.Key, req.Value, 0).Err()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte("Key-Value pair set successfully\n"))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

func getHandler(w http.ResponseWriter, r *http.Request) {
var req struct {
Key string `json:"key"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
value, err := rdb.Get(r.Context(), req.Key).Result()
if err == redis.Nil {
http.Error(w, "Key does not exist", http.StatusNotFound)
return
} else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(map[string]string{
"key": req.Key,
"value": value,
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

func setexHandler(w http.ResponseWriter, r *http.Request) {
var req struct {
Key string `json:"key"`
Value string `json:"value"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

result, err := rdb.SetEX(r.Context(), req.Key, req.Value, time.Second).Result()
if err == redis.Nil {
http.Error(w, "Key does not exist", http.StatusNotFound)
return
} else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(map[string]string{
"key": req.Key,
"value": result,
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

func saddHandler(w http.ResponseWriter, r *http.Request) {
var req struct {
Key string `json:"key"`
Values []string `json:"values"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err := rdb.SAdd(r.Context(), req.Key, req.Values).Err()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(map[string]interface{}{
"key": req.Key,
"values": req.Values,
"status": "added successfully",
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
2 changes: 2 additions & 0 deletions internal/include/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
#define __VMLINUX_H__

typedef unsigned char __u8;
typedef short int __s8;
typedef short int __s16;
typedef short unsigned int __u16;
typedef int __s32;
typedef unsigned int __u32;
typedef long long int __s64;
typedef long long unsigned int __u64;
typedef __s8 s8;
typedef __u8 u8;
typedef __s16 s16;
typedef __u16 u16;
Expand Down
Loading

0 comments on commit 92cd325

Please sign in to comment.