Skip to content

merge origin #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Oct 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 10 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@

> :heart: [**Uptrace.dev** - distributed traces, logs, and errors in one place](https://uptrace.dev)

- [Docs](https://redis.uptrace.dev)
- Join [Discord](https://discord.gg/rWtp5Aj) to ask questions.
- [Documentation](https://redis.uptrace.dev)
- [Reference](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc)
- [Examples](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#pkg-examples)
- [RealWorld example app](https://github.com/uptrace/go-treemux-realworld-example-app)
- Join [Discord](https://discord.gg/rWtp5Aj) to ask questions.

## Ecosystem

- [redisext](https://github.com/go-redis/redisext) - tracing using OpenTelemetryHook.
- [Distributed Locks](https://github.com/bsm/redislock).
- [Redis Cache](https://github.com/go-redis/cache).
- [Rate limiting](https://github.com/go-redis/redis_rate).
- [Distributed Locks](https://github.com/bsm/redislock).

## Features

Expand All @@ -40,18 +39,18 @@

## Installation

go-redis requires a Go version with [Modules](https://github.com/golang/go/wiki/Modules) support and
uses import versioning. So please make sure to initialize a Go module before installing go-redis:
go-redis supports 2 last Go versions and requires a Go version with
[modules](https://github.com/golang/go/wiki/Modules) support. So make sure to initialize a Go
module:

```shell
go mod init github.com/my/repo
go get github.com/go-redis/redis/v8
```

Import:
And then install go-redis (note _v8_ in the import; omitting it is a popular mistake):

```go
import "github.com/go-redis/redis/v8"
```shell
go get github.com/go-redis/redis/v8
```

## Quickstart
Expand All @@ -64,24 +63,13 @@ import (

var ctx = context.Background()

func ExampleNewClient() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})

pong, err := rdb.Ping(ctx).Result()
fmt.Println(pong, err)
// Output: PONG <nil>
}

func ExampleClient() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})

err := rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
panic(err)
Expand All @@ -106,11 +94,6 @@ func ExampleClient() {
}
```

## Howto

Please go through [examples](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#pkg-examples)
to get an idea how to use this package.

## Look and feel

Some corner cases:
Expand Down
11 changes: 11 additions & 0 deletions extra/rediscensus/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/go-redis/redis/extra/rediscensus

go 1.15

replace github.com/go-redis/redis/extra/rediscmd => ../rediscmd

require (
github.com/go-redis/redis/extra/rediscmd v0.1.0
github.com/go-redis/redis/v8 v8.3.2
go.opencensus.io v0.22.5
)
45 changes: 45 additions & 0 deletions extra/rediscensus/rediscensus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package rediscensus

import (
"context"

"github.com/go-redis/redis/extra/rediscmd"
"github.com/go-redis/redis/v8"
"go.opencensus.io/trace"
)

type TracingHook struct{}

var _ redis.Hook = TracingHook{}

func (TracingHook) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) {
ctx, span := trace.StartSpan(ctx, cmd.FullName())
span.AddAttributes(trace.StringAttribute("db.system", "redis"),
trace.StringAttribute("redis.cmd", rediscmd.CmdString(cmd)))

return ctx, nil
}

func (TracingHook) AfterProcess(ctx context.Context, cmd redis.Cmder) error {
span := trace.FromContext(ctx)
if err := cmd.Err(); err != nil {
recordErrorOnOCSpan(ctx, span, err)
}
span.End()
return nil
}

func (TracingHook) BeforeProcessPipeline(ctx context.Context, cmds []redis.Cmder) (context.Context, error) {
return ctx, nil
}

func (TracingHook) AfterProcessPipeline(ctx context.Context, cmds []redis.Cmder) error {
return nil
}

func recordErrorOnOCSpan(ctx context.Context, span *trace.Span, err error) {
if err != redis.Nil {
span.AddAttributes(trace.BoolAttribute("error", true))
span.Annotate([]trace.Attribute{trace.StringAttribute("Error", "redis error")}, err.Error())
}
}
9 changes: 9 additions & 0 deletions extra/rediscmd/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module github.com/go-redis/redis/extra/rediscmd

go 1.15

require (
github.com/go-redis/redis/v8 v8.3.2
github.com/onsi/ginkgo v1.14.2
github.com/onsi/gomega v1.10.3
)
149 changes: 149 additions & 0 deletions extra/rediscmd/rediscmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package rediscmd

import (
"encoding/hex"
"fmt"
"strconv"
"strings"
"time"

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

func CmdString(cmd redis.Cmder) string {
b := make([]byte, 0, 32)
b = AppendCmd(b, cmd)
return String(b)
}

func CmdsString(cmds []redis.Cmder) (string, string) {
const numCmdLimit = 100
const numNameLimit = 10

seen := make(map[string]struct{}, numNameLimit)
unqNames := make([]string, 0, numNameLimit)

b := make([]byte, 0, 32*len(cmds))

for i, cmd := range cmds {
if i > numCmdLimit {
break
}

if i > 0 {
b = append(b, '\n')
}
b = AppendCmd(b, cmd)

if len(unqNames) >= numNameLimit {
continue
}

name := cmd.FullName()
if _, ok := seen[name]; !ok {
seen[name] = struct{}{}
unqNames = append(unqNames, name)
}
}

summary := strings.Join(unqNames, " ")
return summary, String(b)
}

func AppendCmd(b []byte, cmd redis.Cmder) []byte {
const numArgLimit = 32

for i, arg := range cmd.Args() {
if i > numArgLimit {
break
}
if i > 0 {
b = append(b, ' ')
}
b = appendArg(b, arg)
}

if err := cmd.Err(); err != nil {
b = append(b, ": "...)
b = append(b, err.Error()...)
}

return b
}

func appendArg(b []byte, v interface{}) []byte {
const argLenLimit = 64

switch v := v.(type) {
case nil:
return append(b, "<nil>"...)
case string:
if len(v) > argLenLimit {
v = v[:argLenLimit]
}
return appendUTF8String(b, Bytes(v))
case []byte:
if len(v) > argLenLimit {
v = v[:argLenLimit]
}
return appendUTF8String(b, v)
case int:
return strconv.AppendInt(b, int64(v), 10)
case int8:
return strconv.AppendInt(b, int64(v), 10)
case int16:
return strconv.AppendInt(b, int64(v), 10)
case int32:
return strconv.AppendInt(b, int64(v), 10)
case int64:
return strconv.AppendInt(b, v, 10)
case uint:
return strconv.AppendUint(b, uint64(v), 10)
case uint8:
return strconv.AppendUint(b, uint64(v), 10)
case uint16:
return strconv.AppendUint(b, uint64(v), 10)
case uint32:
return strconv.AppendUint(b, uint64(v), 10)
case uint64:
return strconv.AppendUint(b, v, 10)
case float32:
return strconv.AppendFloat(b, float64(v), 'f', -1, 64)
case float64:
return strconv.AppendFloat(b, v, 'f', -1, 64)
case bool:
if v {
return append(b, "true"...)
}
return append(b, "false"...)
case time.Time:
return v.AppendFormat(b, time.RFC3339Nano)
default:
return append(b, fmt.Sprint(v)...)
}
}

func appendUTF8String(dst []byte, src []byte) []byte {
if isSimple(src) {
dst = append(dst, src...)
return dst
}

s := len(dst)
dst = append(dst, make([]byte, hex.EncodedLen(len(src)))...)
hex.Encode(dst[s:], src)
return dst
}

func isSimple(b []byte) bool {
for _, c := range b {
if !isSimpleByte(c) {
return false
}
}
return true
}

func isSimpleByte(c byte) bool {
return c >= 0x21 && c <= 0x7e
}
32 changes: 32 additions & 0 deletions extra/rediscmd/rediscmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package rediscmd

import (
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
)

func TestGinkgo(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "redisext")
}

var _ = Describe("AppendArg", func() {
DescribeTable("...",
func(src string, wanted string) {
b := appendArg(nil, src)
Expect(string(b)).To(Equal(wanted))
},

Entry("", "-inf", "-inf"),
Entry("", "+inf", "+inf"),
Entry("", "foo.bar", "foo.bar"),
Entry("", "foo:bar", "foo:bar"),
Entry("", "foo{bar}", "foo{bar}"),
Entry("", "foo-123_BAR", "foo-123_BAR"),
Entry("", "foo\nbar", "666f6f0a626172"),
Entry("", "\000", "00"),
)
})
11 changes: 11 additions & 0 deletions extra/rediscmd/safe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// +build appengine

package rediscmd

func String(b []byte) string {
return string(b)
}

func Bytes(s string) []byte {
return []byte(s)
}
20 changes: 20 additions & 0 deletions extra/rediscmd/unsafe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// +build !appengine

package rediscmd

import "unsafe"

// String converts byte slice to string.
func String(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}

// Bytes converts string to byte slice.
func Bytes(s string) []byte {
return *(*[]byte)(unsafe.Pointer(
&struct {
string
Cap int
}{s, len(s)},
))
}
11 changes: 11 additions & 0 deletions extra/redisotel/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/go-redis/redis/extra/redisotel

go 1.15

replace github.com/go-redis/redis/extra/rediscmd => ../rediscmd

require (
github.com/go-redis/redis/extra/rediscmd v0.1.0
github.com/go-redis/redis/v8 v8.3.2
go.opentelemetry.io/otel v0.13.0
)
Loading