Skip to content

Commit

Permalink
init project
Browse files Browse the repository at this point in the history
  • Loading branch information
shumin1027 committed Aug 7, 2019
1 parent 9cd13ee commit 90a2649
Show file tree
Hide file tree
Showing 12 changed files with 466 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

.vscode
.idea
.DS_Store
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,29 @@
# goredis
a middleware for goredis to use opentracing

```go
import (
"net/http"

"github.com/go-redis/redis"

apmgoredis "github.com/opentracing-contrib/goredis"
)

var redisClient *redis.Client // initialized at program startup

func handleRequest(w http.ResponseWriter, req *http.Request) {
// Wrap and bind redisClient to the request context. If the HTTP
// server is instrumented with Elastic APM (e.g. with apmhttp),
// Redis commands will be reported as spans within the request's
// transaction.
client := apmgoredis.Wrap(redisClient).WithContext(req.Context())
...
}
```

Example: [goredis-example](./examples)

![](./examples/imgs/img1.jpg)

![](./examples/imgs/img2.jpg)
153 changes: 153 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package apm

import (
"context"
"fmt"
"github.com/go-redis/redis"
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"strings"
)

// Client is the interface returned by Wrap.
//
// Client implements redis.UniversalClient
type Client interface {
redis.UniversalClient

// ClusterClient returns the wrapped *redis.ClusterClient,
// or nil if a non-cluster client is wrapped.
Cluster() *redis.ClusterClient

// Ring returns the wrapped *redis.Ring,
// or nil if a non-ring client is wrapped.
RingClient() *redis.Ring

// WithContext returns a shallow copy of the client with
// its context changed to ctx and will add instrumentation
// with client.WrapProcess and client.WrapProcessPipeline
//
// To report commands as spans, ctx must contain a transaction or span.
WithContext(ctx context.Context) Client
}

// Wrap wraps client such that executed commands are reported as spans to Elastic APM,
// using the client's associated context.
// A context-specific client may be obtained by using Client.WithContext.
func Wrap(client redis.UniversalClient) Client {
switch client.(type) {
case *redis.Client:
return contextClient{Client: client.(*redis.Client)}
case *redis.ClusterClient:
return contextClusterClient{ClusterClient: client.(*redis.ClusterClient)}
case *redis.Ring:
return contextRingClient{Ring: client.(*redis.Ring)}
}

return client.(Client)

}

type contextClient struct {
*redis.Client
}

func (c contextClient) WithContext(ctx context.Context) Client {
c.Client = c.Client.WithContext(ctx)

c.WrapProcess(process(ctx))
c.WrapProcessPipeline(processPipeline(ctx))

return c
}

func (c contextClient) Cluster() *redis.ClusterClient {
return nil
}

func (c contextClient) RingClient() *redis.Ring {
return nil
}

type contextClusterClient struct {
*redis.ClusterClient
}

func (c contextClusterClient) Cluster() *redis.ClusterClient {
return c.ClusterClient
}

func (c contextClusterClient) RingClient() *redis.Ring {
return nil
}

func (c contextClusterClient) WithContext(ctx context.Context) Client {
c.ClusterClient = c.ClusterClient.WithContext(ctx)

c.WrapProcess(process(ctx))
c.WrapProcessPipeline(processPipeline(ctx))

return c
}

type contextRingClient struct {
*redis.Ring
}

func (c contextRingClient) Cluster() *redis.ClusterClient {

return nil
}

func (c contextRingClient) RingClient() *redis.Ring {
return c.Ring
}

func (c contextRingClient) WithContext(ctx context.Context) Client {
c.Ring = c.Ring.WithContext(ctx)

c.WrapProcess(process(ctx))
c.WrapProcessPipeline(processPipeline(ctx))

return c
}

func process(ctx context.Context) func(oldProcess func(cmd redis.Cmder) error) func(cmd redis.Cmder) error {
return func(oldProcess func(cmd redis.Cmder) error) func(cmd redis.Cmder) error {
return func(cmd redis.Cmder) error {
spanName := strings.ToUpper(cmd.Name())
span, _ := opentracing.StartSpanFromContext(ctx, spanName)
ext.DBType.Set(span, "redis")
ext.DBStatement.Set(span, fmt.Sprintf("%v", cmd.Args()))
defer span.Finish()

return oldProcess(cmd)
}
}
}

func processPipeline(ctx context.Context) func(oldProcess func(cmds []redis.Cmder) error) func(cmds []redis.Cmder) error {
return func(oldProcess func(cmds []redis.Cmder) error) func(cmds []redis.Cmder) error {
return func(cmds []redis.Cmder) error {
pipelineSpan, ctx := opentracing.StartSpanFromContext(ctx, "(pipeline)")

ext.DBType.Set(pipelineSpan, "redis")

for i := len(cmds); i > 0; i-- {
cmdName := strings.ToUpper(cmds[i-1].Name())
if cmdName == "" {
cmdName = "(empty command)"
}

span, _ := opentracing.StartSpanFromContext(ctx, cmdName)
ext.DBType.Set(span, "redis")
ext.DBStatement.Set(span, fmt.Sprintf("%v", cmds[i-1].Args()))
defer span.Finish()
}

defer pipelineSpan.Finish()

return oldProcess(cmds)
}
}
}
38 changes: 38 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

1. start jaeger
```shell script
docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
-p 5775:5775/udp \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 14268:14268 \
-p 9411:9411 \
jaegertracing/all-in-one:1.13

```

2. start redis

```shell script
docker run -d --name redis -p 6379:6379 redis
```

3. set env
```shell script
export JAEGER_AGENT_HOST=localhost
export JAEGER_AGENT_PORT=6831
export JAEGER_ENABLED=true
```

4. run example
```shell script
go run server.go
```

5. call the server
```shell script
curl http://localhost:1323/hello
```
21 changes: 21 additions & 0 deletions examples/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module github.com/opentracing-contrib/goredis/examples

go 1.12

replace github.com/opentracing-contrib/goredis => ../

replace github.com/opentracing-contrib/echo => github.com/opentracing-lib/echo v0.0.0-20190807081036-673d4a7607b1

require (
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
github.com/go-redis/redis v6.15.3+incompatible
github.com/labstack/echo/v4 v4.1.8
github.com/opentracing-contrib/echo v0.0.0-00010101000000-000000000000
github.com/opentracing-contrib/goredis v0.0.0-00010101000000-000000000000
github.com/opentracing/opentracing-go v1.1.0
github.com/pkg/errors v0.8.1 // indirect
github.com/uber-go/atomic v1.4.0 // indirect
github.com/uber/jaeger-client-go v2.16.0+incompatible
github.com/uber/jaeger-lib v2.0.0+incompatible // indirect
go.uber.org/atomic v1.4.0 // indirect
)
83 changes: 83 additions & 0 deletions examples/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-redis/redis v6.15.3+incompatible h1:NZ0O90AhLSvSrvLZ/S9h7D4kl1mW2PrKyxL7MyBKO2g=
github.com/go-redis/redis v6.15.3+incompatible/go.mod h1:W2YCLaZryXHirdd9QqwkiVUxCQsrx8SbLq9Uqk7JS7A=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/labstack/echo/v4 v4.1.8 h1:2IBbRrln806Ao53hR4dxU1SFgJEDWG/IUU81ryYlGdE=
github.com/labstack/echo/v4 v4.1.8/go.mod h1:kU/7PwzgNxZH4das4XNsSpBSOD09XIF5YEPzjpkGnGE=
github.com/labstack/gommon v0.2.9 h1:heVeuAYtevIQVYkGj6A41dtfT91LrvFG220lavpWhrU=
github.com/labstack/gommon v0.2.9/go.mod h1:E8ZTmW9vw5az5/ZyHWCp0Lw4OH2ecsaBP1C/NKavGG4=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/opentracing-lib/echo v0.0.0-20190807081036-673d4a7607b1 h1:C0WJxwa9jHoRE0qTJy55aW0JR10+U8BNCOJ/u1yTSHQ=
github.com/opentracing-lib/echo v0.0.0-20190807081036-673d4a7607b1/go.mod h1:H/4DFXmu9Mu9gJvYfa/IUWFTSmZ0PzFem+AZosNJpDQ=
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/uber-go/atomic v1.4.0 h1:yOuPqEq4ovnhEjpHmfFwsqBXDYbQeT6Nb0bwD6XnD5o=
github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
github.com/uber/jaeger-client-go v2.16.0+incompatible h1:Q2Pp6v3QYiocMxomCaJuwQGFt7E53bPYqEgug/AoBtY=
github.com/uber/jaeger-client-go v2.16.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.0.0+incompatible h1:iMSCV0rmXEogjNWPh2D0xk9YVKvrtGoHJNe9ebLu/pw=
github.com/uber/jaeger-lib v2.0.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190607181551-461777fb6f67 h1:rJJxsykSlULwd2P2+pg/rtnwN2FrWp4IuCxOSyS0V00=
golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190609082536-301114b31cce h1:CQakrGkKbydnUmt7cFIlmQ4lNQiqdTPt6xzXij4nYCc=
golang.org/x/sys v0.0.0-20190609082536-301114b31cce/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190608022120-eacb66d2a7c3/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
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.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
Binary file added examples/imgs/img1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/imgs/img2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions examples/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package main

import (
"github.com/go-redis/redis"
"github.com/labstack/echo/v4"
apmecho "github.com/opentracing-contrib/echo"
"github.com/opentracing-contrib/goredis/examples/tracer"
apmgoredis "github.com/opentracing-contrib/goredis"
"github.com/opentracing/opentracing-go"
"net/http"
"os"
)

const (
DefaultComponentName = "goredis-demo"
)

func main() {

flag := os.Getenv("JAEGER_ENABLED")
if flag == "true" {
// 1. init tracer
tracer, closer := tracer.Init(DefaultComponentName)
if closer != nil {
defer closer.Close()
}
// 2. ste the global tracer
if tracer != nil {
opentracing.SetGlobalTracer(tracer)
}
}

e := echo.New()

if flag == "true" {
// 3. use the middleware
e.Use(apmecho.Middleware(DefaultComponentName))
}

rdb := redis.NewUniversalClient(&redis.UniversalOptions{
Addrs: []string{"127.0.0.1:6379"},
DB: 0,
})
defer rdb.Close()

e.GET("/", func(c echo.Context) error {
rdb = apmgoredis.Wrap(rdb).WithContext(c.Request().Context())
rdb.Ping()
return c.String(http.StatusOK, "Hello, World!")
})

e.GET("/hello", func(c echo.Context) error {
rdb = apmgoredis.Wrap(rdb).WithContext(c.Request().Context())
rdb.Set("data", "world", 1000000) //1ms
data := rdb.Get("data").String()

return c.String(http.StatusOK, data)
})

e.Logger.Fatal(e.Start(":1323"))
}
Loading

0 comments on commit 90a2649

Please sign in to comment.