inital commit
This commit is contained in:
28
README.md
Normal file
28
README.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Redis example
|
||||||
|
Код реазлизует простейший веб сервис отдающий информацию о пользователе по его id.
|
||||||
|
```sh
|
||||||
|
❯ http http://127.0.0.1:8080/user?id=1
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Length: 37
|
||||||
|
Content-Type: application/json
|
||||||
|
Date: Thu, 12 Dec 2024 05:08:45 GMT
|
||||||
|
|
||||||
|
{
|
||||||
|
"age": 30,
|
||||||
|
"id": 1,
|
||||||
|
"name": "Test User"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Данные о пользователях хранятся в PostgreSQL. Для ускорения ответа используется Redis.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
В папке `deployment` находится `docker-compose.yml` файл, который запускает все необходимые зависимости:
|
||||||
|
- `PostgreSQL` - основное хранилище данных
|
||||||
|
- `Redis` - кэш
|
||||||
|
- `OpenTelemetry Collector` - сборщик трейсов
|
||||||
|
- `Jaeger` - визуализация трейсов
|
||||||
|
|
||||||
|
`go run *.go` - запуск сервиса
|
||||||
|
|
||||||
|
После запуска сервиса следует сделать к нему ряд запросов. В интерфейсе [Jaeger](http://127.0.0.1:16686/) будет видно, что запросы которые идут подряд меньше чем за десять секунд, используют кэш и отрабатывают быстрее.
|
||||||
39
deployment/compose.yaml
Normal file
39
deployment/compose.yaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:latest
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: user
|
||||||
|
POSTGRES_PASSWORD: password
|
||||||
|
POSTGRES_DB: mydb
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
|
|
||||||
|
keydb:
|
||||||
|
image: eqalpha/keydb:latest
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
|
||||||
|
otel-collector:
|
||||||
|
image: otel/opentelemetry-collector:latest
|
||||||
|
container_name: otel-collector
|
||||||
|
command: ["--config=/etc/otel-collector-config.yaml"]
|
||||||
|
volumes:
|
||||||
|
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||||
|
ports:
|
||||||
|
- "4317:4317"
|
||||||
|
depends_on:
|
||||||
|
- jaeger
|
||||||
|
|
||||||
|
jaeger:
|
||||||
|
image: jaegertracing/all-in-one:latest
|
||||||
|
container_name: jaeger
|
||||||
|
environment:
|
||||||
|
- COLLECTOR_OTLP_ENABLED=true
|
||||||
|
- COLLECTOR_OTLP_GRPC_HOST-PORT=:4317
|
||||||
|
- COLLECTOR_OTLP_GRPC_HOST_PORT=:4317
|
||||||
|
ports:
|
||||||
|
- "16686:16686"
|
||||||
9
deployment/init.sql
Normal file
9
deployment/init.sql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id INT PRIMARY KEY,
|
||||||
|
name VARCHAR(100),
|
||||||
|
age INT
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO users (id, name, age)
|
||||||
|
VALUES (1, 'Test User', 30)
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
19
deployment/otel-collector-config.yaml
Normal file
19
deployment/otel-collector-config.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
receivers:
|
||||||
|
otlp:
|
||||||
|
protocols:
|
||||||
|
grpc:
|
||||||
|
endpoint: 0.0.0.0:4317
|
||||||
|
processors:
|
||||||
|
exporters:
|
||||||
|
otlp:
|
||||||
|
endpoint: "http://jaeger:4317"
|
||||||
|
tls:
|
||||||
|
insecure: true
|
||||||
|
debug:
|
||||||
|
verbosity: detailed
|
||||||
|
service:
|
||||||
|
pipelines:
|
||||||
|
traces:
|
||||||
|
receivers: [otlp]
|
||||||
|
processors: []
|
||||||
|
exporters: [otlp, debug]
|
||||||
35
go.mod
Normal file
35
go.mod
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
module github.com/maksim77/redis_example
|
||||||
|
|
||||||
|
go 1.23.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/XSAM/otelsql v0.35.0
|
||||||
|
github.com/lib/pq v1.10.9
|
||||||
|
github.com/redis/go-redis/extra/redisotel/v9 v9.7.0
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0
|
||||||
|
go.opentelemetry.io/otel v1.32.0
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0
|
||||||
|
go.opentelemetry.io/otel/sdk v1.32.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect
|
||||||
|
github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/metric v1.32.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
||||||
|
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||||
|
golang.org/x/net v0.30.0 // indirect
|
||||||
|
golang.org/x/sys v0.27.0 // indirect
|
||||||
|
golang.org/x/text v0.20.0 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect
|
||||||
|
google.golang.org/grpc v1.67.1 // indirect
|
||||||
|
google.golang.org/protobuf v1.35.1 // indirect
|
||||||
|
)
|
||||||
71
go.sum
Normal file
71
go.sum
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4=
|
||||||
|
github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc=
|
||||||
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||||
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||||
|
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||||
|
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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
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/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
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.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0=
|
||||||
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0 h1:BIx9TNZH/Jsr4l1i7VVxnV0JPiwYj8qyrHyuL0fGZrk=
|
||||||
|
github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0/go.mod h1:eTg/YQtGYAZD5r3DlGlJptJ45AHA+/G+2NPn30PKzik=
|
||||||
|
github.com/redis/go-redis/extra/redisotel/v9 v9.7.0 h1:bQk8xiVFw+3ln4pfELVktpWgYdFpgLLU+quwSoeIof0=
|
||||||
|
github.com/redis/go-redis/extra/redisotel/v9 v9.7.0/go.mod h1:0LyN+GHLIJmKtjYRPF7nHyTTMV6E91YngoOopNifQRo=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
|
||||||
|
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0/go.mod h1:JyA0FHXe22E1NeNiHmVp7kFHglnexDQ7uRWDiiJ1hKQ=
|
||||||
|
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
|
||||||
|
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
|
||||||
|
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
|
||||||
|
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||||
|
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||||
|
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||||
|
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||||
|
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 h1:XVhgTWWV3kGQlwJHR3upFWZeTsei6Oks1apkZSeonIE=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||||
|
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
|
||||||
|
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
|
||||||
|
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||||
|
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
147
main.go
Normal file
147
main.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/XSAM/otelsql"
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
"github.com/redis/go-redis/extra/redisotel/v9"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
)
|
||||||
|
|
||||||
|
// User представляет структуру пользователя.
|
||||||
|
type User struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Age int `json:"age"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
db *sql.DB
|
||||||
|
rdb *redis.Client
|
||||||
|
tracer = otel.Tracer("redis_example")
|
||||||
|
)
|
||||||
|
|
||||||
|
// initDB инициализирует подключение к базе данных.
|
||||||
|
func initDB() error {
|
||||||
|
var err error
|
||||||
|
connStr := "postgres://user:password@localhost/mydb?sslmode=disable"
|
||||||
|
db, err = otelsql.Open("postgres", connStr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ошибка подключения к БД: %v", err)
|
||||||
|
}
|
||||||
|
return db.Ping()
|
||||||
|
}
|
||||||
|
|
||||||
|
// initRedis инициализирует подключение к Redis/KeyDB.
|
||||||
|
func initRedis() {
|
||||||
|
rdb = redis.NewClient(&redis.Options{
|
||||||
|
Addr: "localhost:6379",
|
||||||
|
})
|
||||||
|
if err := redisotel.InstrumentTracing(rdb); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getUserByID возвращает пользователя из БД по ID, с кешированием в Redis.
|
||||||
|
func getUserByID(ctx context.Context, id int) (*User, error) {
|
||||||
|
ctxLocal, span := tracer.Start(ctx, "getUserByID")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
// Пытаемся получить данные из кеша.
|
||||||
|
cachedUser, err := rdb.Get(ctxLocal, strconv.Itoa(id)).Result()
|
||||||
|
if err == nil {
|
||||||
|
var user User
|
||||||
|
if err := json.Unmarshal([]byte(cachedUser), &user); err == nil {
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var user User
|
||||||
|
query := "SELECT id, name, age FROM users WHERE id = $1"
|
||||||
|
err = db.QueryRowContext(ctxLocal, query, id).Scan(&user.ID, &user.Name, &user.Age)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil // пользователь не найден
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, fmt.Errorf("ошибка запроса: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сохраняем результаты в кеш.
|
||||||
|
encodedUser, err := json.Marshal(user)
|
||||||
|
if err == nil {
|
||||||
|
rdb.Set(ctxLocal, strconv.Itoa(user.ID), encodedUser, time.Second*10)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// userHandler обрабатывает запросы для получения пользователя.
|
||||||
|
func userHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctxLocal, span := tracer.Start(r.Context(), "handler")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
ids := r.URL.Query().Get("id")
|
||||||
|
if ids == "" {
|
||||||
|
http.Error(w, "id не указан", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(ids)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "id должен быть числом", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := getUserByID(ctxLocal, id)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("ошибка получения пользователя: %v", err), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user == nil {
|
||||||
|
http.Error(w, "пользователь не найден", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
if err := json.NewEncoder(w).Encode(user); err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("ошибка кодирования ответа: %v", err), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
shutdown, err := InstallExportPipeline()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := shutdown(context.Background()); err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Инициализируем подключение к БД.
|
||||||
|
if err := initDB(); err != nil {
|
||||||
|
log.Fatalf("не удалось инициализировать БД: %v", err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// Инициализируем подключение к Redis.
|
||||||
|
initRedis()
|
||||||
|
defer rdb.Close()
|
||||||
|
|
||||||
|
// Регистрируем обработчик.
|
||||||
|
http.HandleFunc("/user", userHandler)
|
||||||
|
|
||||||
|
// Запускаем сервер.
|
||||||
|
fmt.Println("Сервер запущен на :8080")
|
||||||
|
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||||
|
}
|
||||||
55
otel.go
Normal file
55
otel.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
|
||||||
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||||
|
"go.opentelemetry.io/otel/propagation"
|
||||||
|
"go.opentelemetry.io/otel/sdk/resource"
|
||||||
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||||
|
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InstallExportPipeline() (func(context.Context) error, error) {
|
||||||
|
traceClient := otlptracegrpc.NewClient(
|
||||||
|
otlptracegrpc.WithInsecure(),
|
||||||
|
otlptracegrpc.WithEndpoint("127.0.0.1:4317"),
|
||||||
|
)
|
||||||
|
sctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
traceExp, err := otlptrace.New(sctx, traceClient)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("creating stdout exporter: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := resource.New(context.Background(),
|
||||||
|
resource.WithFromEnv(),
|
||||||
|
resource.WithProcess(),
|
||||||
|
resource.WithTelemetrySDK(),
|
||||||
|
resource.WithHost(),
|
||||||
|
resource.WithAttributes(
|
||||||
|
semconv.ServiceNameKey.String("redis_example"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tracerProvider := sdktrace.NewTracerProvider(
|
||||||
|
sdktrace.WithBatcher(traceExp),
|
||||||
|
sdktrace.WithResource(res),
|
||||||
|
)
|
||||||
|
otel.SetTracerProvider(tracerProvider)
|
||||||
|
otel.SetTextMapPropagator(propagation.TraceContext{})
|
||||||
|
|
||||||
|
return tracerProvider.Shutdown, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user