Skip to content
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

feat: support redigo v1.9.0+ #190

Merged
merged 5 commits into from
Nov 18, 2024
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ Also there are several [**documents**](./docs) that you may find useful for eith
| mongodb | https://github.com/mongodb/mongo-go-driver | v1.11.1 | v1.15.2 |
| mux | https://github.com/gorilla/mux | v1.3.0 | v1.8.1 |
| net/http | https://pkg.go.dev/net/http | - | - |
| redigo | https://github.com/gomodule/redigo | v1.9.0 | v1.9.2 |
| slog | https://pkg.go.dev/log/slog | - | - |
| zap | https://github.com/uber-go/zap | v1.20.0 | v1.27.0 |

Expand Down
3 changes: 2 additions & 1 deletion docs/supported-libraries.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## Supported libraries

| Plugin Name | Repository Url | Min Supported Version | Max Supported Version |
|--------------|--------------------------------------------|-----------------------|-----------------------|
| ------------ | ------------------------------------------ | --------------------- | --------------------- |
| database/sql | https://pkg.go.dev/database/sql | - | - |
| echo | https://github.com/labstack/echo | v4.0.0 | v4.12.0 |
| fasthttp | https://github.com/valyala/fasthttp | v1.45.0 | v1.57.0 |
Expand All @@ -16,6 +16,7 @@
| mongodb | https://github.com/mongodb/mongo-go-driver | v1.11.1 | v1.15.2 |
| mux | https://github.com/gorilla/mux | v1.3.0 | v1.8.1 |
| net/http | https://pkg.go.dev/net/http | - | - |
| redigo | https://github.com/gomodule/redigo | v1.9.0 | v1.9.2 |
| slog | https://pkg.go.dev/log/slog | - | - |
| zap | https://github.com/uber-go/zap | v1.20.0 | v1.27.0 |

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/gin-gonic/gin v1.10.0
github.com/go-kratos/kratos/v2 v2.8.0
github.com/go-sql-driver/mysql v1.7.1
github.com/gomodule/redigo v1.9.0
github.com/gorilla/mux v1.8.1
github.com/labstack/echo/v4 v4.12.0
github.com/redis/go-redis/v9 v9.6.1
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.9.0 h1:DEBhR/wOapNDkJg79zliGKF9Qvp0krRinx75dCHC0Y4=
github.com/gomodule/redigo v1.9.0/go.mod h1:76M7UXKeDjV+neXtVEvMiDWnXT5nnUVyWrW1O4Fg8S8=
github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s=
github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
Expand Down
8 changes: 8 additions & 0 deletions pkg/data/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,14 @@
"OnExit": "afterNewRingClient",
"Path": "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/goredis"
},
{
"Version": "[1.9.0,1.9.3)",
"ImportPath": "github.com/gomodule/redigo/redis",
"Function": "DialContext",
"OnEnter": "onBeforeDialContext",
"OnExit": "onExitDialContext",
"Path": "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/redigo"
},
{
"ImportPath": "gorm.io/driver/mysql",
"StructType": "Dialector",
Expand Down
122 changes: 122 additions & 0 deletions pkg/rules/redigo/redigo_client_setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright (c) 2024 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package redigo

import (
"context"
"net"
"time"

"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/api"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
"github.com/gomodule/redigo/redis"
)

var redigoEnabler = instrumenter.NewDefaultInstrumentEnabler()

func onBeforeDialContext(call api.CallContext, ctx context.Context, network, address string, options ...redis.DialOption) {
if !redigoEnabler.Enable() {
return
}
data := make(map[string]interface{}, 2)
data["endpoint"] = address
data["ctx"] = ctx
call.SetData(data)
}

func onExitDialContext(call api.CallContext, conn redis.Conn, err error) {
if !redigoEnabler.Enable() {
return
}
d := call.GetData()
data, ok := d.(map[string]interface{})
if !ok {
return
}
e, ok := data["endpoint"]
if !ok {
return
}
endpoint, ok := e.(string)
if !ok {
return
}
c, ok := data["ctx"]
if !ok {
return
}
ctx, ok := c.(context.Context)
if !ok {
return
}
call.SetReturnVal(0, &armsConn{conn, endpoint, ctx})
}

func onEnterDialURLContext(call api.CallContext, ctx context.Context, rawurl string, options ...redis.DialOption) {
if !redigoEnabler.Enable() {
return
}
data := make(map[string]interface{}, 2)
data["endpoint"] = rawurl
data["ctx"] = ctx
call.SetData(data)
}

func onExitDialURLContext(call api.CallContext, conn redis.Conn, err error) {
if !redigoEnabler.Enable() {
return
}
d := call.GetData()
data, ok := d.(map[string]interface{})
if !ok {
return
}
e, ok := data["endpoint"]
if !ok {
return
}
endpoint, ok := e.(string)
if !ok {
return
}
c, ok := data["ctx"]
if !ok {
return
}
ctx, ok := c.(context.Context)
if !ok {
return
}
call.SetReturnVal(0, &armsConn{conn, endpoint, ctx})
}

func onEnterNewConn(call api.CallContext, netConn net.Conn, readTimeout, writeTimeout time.Duration) {
if !redigoEnabler.Enable() {
return
}
call.SetData(netConn.RemoteAddr().String())
}

func onExitNewConn(call api.CallContext, conn redis.Conn) {
if !redigoEnabler.Enable() {
return
}
e := call.GetData()
endpoint, ok := e.(string)
if !ok {
return
}
call.SetReturnVal(0, &armsConn{conn, endpoint, context.Background()})
}
123 changes: 123 additions & 0 deletions pkg/rules/redigo/redigo_otel_conn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright (c) 2024 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package redigo

import (
"container/list"
"context"
"github.com/gomodule/redigo/redis"
"os"
"strconv"
"time"
)

const max_queue_length = 2048

var configuredQueueLength int

var commandQueue = list.New()

var redigoInstrumenter = BuildRedigoInstrumenter()

type armsConn struct {
redis.Conn
endpoint string
ctx context.Context
}

func (a *armsConn) Close() error {
return a.Conn.Close()
}

func (a *armsConn) Err() error {
return a.Conn.Err()
}

func (a *armsConn) Do(commandName string, args ...interface{}) (reply interface{}, err error) {
req := &redigoRequest{
args: args,
endpoint: a.endpoint,
cmd: commandName,
}
ctx := a.ctx
if ctx == nil {
ctx = context.Background()
}
startTime := time.Now()
reply, err = a.Conn.Do(commandName, args...)
endTime := time.Now()
redigoInstrumenter.StartAndEnd(ctx, req, nil, err, startTime, endTime)
return
}

func (a *armsConn) Send(commandName string, args ...interface{}) error {
now := time.Now()
req := &redigoRequest{
args: args,
endpoint: a.endpoint,
cmd: commandName,
startTime: now,
}
ctx := a.ctx
if ctx == nil {
ctx = context.Background()
}
req.ctx = ctx
push(req)
return a.Conn.Send(commandName, args...)
}

func (a *armsConn) Flush() error {
return a.Conn.Flush()
}

func (a *armsConn) Receive() (reply interface{}, err error) {
reply, err = a.Conn.Receive()
req := pop()
if req != nil {
now := time.Now()
redigoInstrumenter.StartAndEnd(req.ctx, req, nil, err, req.startTime, now)
}
return
}

func push(request *redigoRequest) {
if commandQueue != nil && commandQueue.Len() > getMaxQueueLength() {
return
}
commandQueue.PushBack(request)
}

func pop() *redigoRequest {
front := commandQueue.Front()
commandQueue.Remove(front)
p, ok := front.Value.(*redigoRequest)
if ok {
return p
}
return nil
}

func getMaxQueueLength() int {
if configuredQueueLength == 0 {
var e = os.Getenv("MAX_REDIGO_QUEUE_LENGTH")
if e != "" {
configuredQueueLength, _ = strconv.Atoi(os.Getenv(e))
} else {
configuredQueueLength = max_queue_length
}
}
return configuredQueueLength
}
68 changes: 68 additions & 0 deletions pkg/rules/redigo/redigo_otel_instrumenter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) 2024 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package redigo

import (
"context"
"fmt"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/db"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
"strings"
"time"
)

type redigoRequest struct {
args []interface{}
endpoint string
cmd string
ctx context.Context
startTime time.Time
}

type redigoAttrsGetter struct {
}

func (m redigoAttrsGetter) GetSystem(request *redigoRequest) string {
return "redis"
}

func (m redigoAttrsGetter) GetServerAddress(request *redigoRequest) string {
return request.endpoint
}

func (m redigoAttrsGetter) GetStatement(request *redigoRequest) string {
builder := strings.Builder{}
builder.WriteString(request.cmd + " ")
for _, arg := range request.args {
builder.WriteString(fmt.Sprintf("%v ", arg))
}
return builder.String()
}

func (m redigoAttrsGetter) GetOperation(request *redigoRequest) string {
return request.cmd
}

func (m redigoAttrsGetter) GetParameters(request *redigoRequest) []any {
return nil
}

func BuildRedigoInstrumenter() instrumenter.Instrumenter[*redigoRequest, interface{}] {
builder := instrumenter.Builder[*redigoRequest, any]{}
getter := redigoAttrsGetter{}
return builder.Init().SetSpanNameExtractor(&db.DBSpanNameExtractor[*redigoRequest]{Getter: getter}).SetSpanKindExtractor(&instrumenter.AlwaysClientExtractor[*redigoRequest]{}).
AddAttributesExtractor(&db.DbClientAttrsExtractor[*redigoRequest, any, db.DbClientAttrsGetter[*redigoRequest]]{Base: db.DbClientCommonAttrsExtractor[*redigoRequest, any, db.DbClientAttrsGetter[*redigoRequest]]{Getter: getter}}).
BuildInstrumenter()
}
13 changes: 13 additions & 0 deletions test/redigo/v1.9.0/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module redigo

go 1.22

replace github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier => ../../../../opentelemetry-go-auto-instrumentation/test/verifier

replace github.com/alibaba/opentelemetry-go-auto-instrumentation => ../../../../opentelemetry-go-auto-instrumentation

require (
github.com/alibaba/opentelemetry-go-auto-instrumentation v0.0.0-00010101000000-000000000000
github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier v0.0.0-00010101000000-000000000000
github.com/gomodule/redigo v1.9.0
)
Loading
Loading