Skip to content

Commit

Permalink
add gomicro
Browse files Browse the repository at this point in the history
  • Loading branch information
NameHaibinZhang committed Jan 10, 2025
1 parent 59fc768 commit 5061280
Show file tree
Hide file tree
Showing 14 changed files with 716 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ Also there are several [**documents**](./docs) that you may find useful for eith
| zap | https://github.com/uber-go/zap | v1.20.0 | v1.27.0 |
| zerolog | https://github.com/rs/zerolog | v1.10.0 | v1.33.0 |
| iris | https://github.com/kataras/iris | v12.2.0 | v12.2.11 |
| gomicro | https://github.com/micro/go-micro | v5.0.0 | v5.3.0 |


We are progressively open-sourcing the libraries we have supported, and your contributions are very welcome 💖!

Expand Down
1 change: 1 addition & 0 deletions docs/supported-libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
| zap | https://github.com/uber-go/zap | v1.20.0 | v1.27.0 |
| zerolog | https://github.com/rs/zerolog | v1.10.0 | v1.33.0 |
| iris | https://github.com/kataras/iris | v12.2.0 | v12.2.11 |
| gomicro | https://github.com/micro/go-micro | v5.0.0 | v5.3.0 |

### Notice

Expand Down
24 changes: 24 additions & 0 deletions pkg/data/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -775,5 +775,29 @@
"ReceiverType": "*routerHandler",
"OnEnter": "irisHttpOnEnter",
"Path": "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/iris"
},
{
"Version": "[5.0.0,5.3.1)",
"ImportPath": "go-micro.dev/v5/client",
"Function": "next",
"ReceiverType": "*rpcClient",
"OnExit": "NextOnExit",
"Path": "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/gomicro"
},
{
"Version": "[5.0.0,5.3.1)",
"ImportPath": "go-micro.dev/v5",
"Function": "NewService",
"OnEnter": "NewServiceOnEnter",
"Path": "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/gomicro"
},
{
"Version": "[5.0.0,5.3.1)",
"ImportPath": "go-micro.dev/v5/server",
"Function": "ServeRequest",
"ReceiverType": "*router",
"OnEnter": "ServeRequestOnEnter",
"OnExit": "ServeRequestOnExit",
"Path": "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/gomicro"
}
]
2 changes: 2 additions & 0 deletions pkg/inst-api/utils/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ const KRATOS_HTTP_INTERNAL_SCOPE_NAME = "pkg/rules/kratos/http/kratos_internal_s
const MONGO_SCOPE_NAME = "pkg/rules/mongo/client_setup.go"
const REDIGO_SCOPE_NAME = "pkg/rules/redigo/redigo_client_setup.go"
const ELASTICSEARCH_SCOPE_NAME = "pkg/rules/elasticsearch/es_client_setup.go"
const GOMICRO_CLIENT_SCOPE_NAME = "pkg/rules/gomicro/client/gomicro_client_setup.go"
const GOMICRO_SERVER_SCOPE_NAME = "pkg/rules/gomicro/server/gomicro_server_setup.go"
92 changes: 92 additions & 0 deletions pkg/rules/gomicro/gomicro_client_setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package gomicro

import (
"context"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/api"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
micro "go-micro.dev/v5"
"go-micro.dev/v5/client"
"go-micro.dev/v5/metadata"
"go-micro.dev/v5/registry"
"go-micro.dev/v5/selector"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
)

var goMicroClientEnabler = instrumenter.NewDefaultInstrumentEnabler()

type clientV5Wrapper struct {
client.Client
}

func NewV5ClientWrapper(cli client.Client) client.Client {
return &clientV5Wrapper{cli}
}

// Call is used for client calls
func (s *clientV5Wrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
request := goMicroRequest{
request: req,
reqType: CallRequest,
ctx: ctx,
}
ctx = goMicroClientInstrument.Start(ctx, request)
mda, _ := metadata.FromContext(request.ctx)
md := metadata.Copy(mda)
otel.GetTextMapPropagator().Inject(ctx, propagation.MapCarrier(md))
ctx = metadata.NewContext(ctx, md)
request.ctx = ctx
err := s.Client.Call(request.ctx, req, rsp, opts...)
response := goMicroResponse{
response: rsp,
err: err,
ctx: request.ctx,
}
goMicroClientInstrument.End(ctx, request, response, err)
return nil
}

func (s *clientV5Wrapper) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
request := goMicroRequest{
request: req,
reqType: StreamRequest,
ctx: ctx,
}
ctx = goMicroClientInstrument.Start(ctx, request)
stream, err := s.Client.Stream(ctx, req, opts...)
response := goMicroResponse{
response: stream,
err: err,
ctx: ctx,
}
goMicroClientInstrument.End(ctx, request, response, err)

return nil, nil

}

func (s *clientV5Wrapper) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error {
return s.Client.Publish(ctx, p, opts...)

}

func NewServiceOnEnter(call api.CallContext, opts ...micro.Option) {
opts = append(opts, micro.WrapClient(NewV5ClientWrapper))
call.SetParam(0, opts)
}

func NextOnExit(call api.CallContext, nextSelector selector.Next, e error) {
span := sdktrace.SpanFromGLS()
if nextSelector != nil && span != nil {
var selectWrapper selector.Next = func() (*registry.Node, error) {
node, tmp := nextSelector()
if node != nil {
span.SetAttributes(semconv.ServerAddressKey.String(node.Address))
}
return node, tmp
}
call.SetReturnVal(0, selectWrapper)
}
}
40 changes: 40 additions & 0 deletions pkg/rules/gomicro/gomicro_data_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package gomicro

import (
"context"
"go-micro.dev/v5/client"
"go-micro.dev/v5/server"
"go.opentelemetry.io/otel/propagation"
)

var goMicroClientInstrument = BuildGoMicroClientInstrumenter()

type requestType int

const (
MessageRequest requestType = iota
CallRequest
StreamRequest
)

type goMicroRequest struct {
reqType requestType
request client.Request
msg client.Message
ctx context.Context
propagators propagation.TextMapCarrier
}

type goMicroServerRequest struct {
reqType requestType
request server.Request
msg server.Message
ctx context.Context
propagators propagation.TextMapCarrier
}

type goMicroResponse struct {
response interface{}
ctx context.Context
err error
}
21 changes: 21 additions & 0 deletions pkg/rules/gomicro/gomicro_enabler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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 gomicro

import (
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
)

var goMicroEnabler = instrumenter.NewDefaultInstrumentEnabler()
147 changes: 147 additions & 0 deletions pkg/rules/gomicro/gomicro_server_otel_instrumenter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// 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 gomicro

import (
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/http"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/net"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
"go-micro.dev/v5/metadata"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/instrumentation"
)

type GoMicroServerAttrsGetter struct {
}

func (n GoMicroServerAttrsGetter) GetRequestMethod(request goMicroServerRequest) string {
return request.request.Method()
}
func (n GoMicroServerAttrsGetter) GetHttpRequestHeader(request goMicroServerRequest, name string) []string {
all := make([]string, 0)
md, ok := metadata.FromContext(request.ctx)
if ok {
value, ok := md.Get(name)
if ok {
all = append(all, string(value))
}
}
return all
}
func (n GoMicroServerAttrsGetter) GetHttpResponseStatusCode(request goMicroServerRequest, response goMicroResponse, err error) int {
if err != nil {
return 500
}
return 200
}
func (n GoMicroServerAttrsGetter) GetHttpResponseHeader(request goMicroServerRequest, response goMicroResponse, name string) []string {
all := make([]string, 0)
md, ok := metadata.FromContext(response.ctx)
if ok {
value, ok := md.Get(name)
if ok {
all = append(all, string(value))
}
}
return all
}
func (n GoMicroServerAttrsGetter) GetErrorType(request goMicroServerRequest, response goMicroResponse, err error) string {
return ""
}
func (n GoMicroServerAttrsGetter) GetUrlScheme(request goMicroServerRequest) string {
return "http"
}
func (n GoMicroServerAttrsGetter) GetUrlPath(request goMicroServerRequest) string {
return request.request.Endpoint()
}
func (n GoMicroServerAttrsGetter) GetUrlQuery(request goMicroServerRequest) string {
return ""
}
func (n GoMicroServerAttrsGetter) GetNetworkType(request goMicroServerRequest, response goMicroResponse) string {
return "ipv4"
}
func (n GoMicroServerAttrsGetter) GetNetworkTransport(request goMicroServerRequest, response goMicroResponse) string {
return "tcp"
}
func (n GoMicroServerAttrsGetter) GetNetworkProtocolName(request goMicroServerRequest, response goMicroResponse) string {
return "http"
}
func (n GoMicroServerAttrsGetter) GetNetworkProtocolVersion(request goMicroServerRequest, response goMicroResponse) string {
return ""
}
func (n GoMicroServerAttrsGetter) GetNetworkLocalInetAddress(request goMicroServerRequest, response goMicroResponse) string {
return ""
}
func (n GoMicroServerAttrsGetter) GetNetworkLocalPort(request goMicroServerRequest, response goMicroResponse) int {
return 0
}
func (n GoMicroServerAttrsGetter) GetNetworkPeerInetAddress(request goMicroServerRequest, response goMicroResponse) string {
return request.request.Service()
}
func (n GoMicroServerAttrsGetter) GetNetworkPeerPort(request goMicroServerRequest, response goMicroResponse) int {
return 0
}
func (n GoMicroServerAttrsGetter) GetHttpRoute(request goMicroServerRequest) string {
return request.request.Endpoint()
}

type goMicroServerTextMapCarrier struct {
request *goMicroServerRequest
}

func (h goMicroServerTextMapCarrier) Get(key string) string {
mda, _ := metadata.FromContext(h.request.ctx)
md := metadata.Copy(mda)
value, _ := md.Get(key)
return value
}

func (h goMicroServerTextMapCarrier) Set(key string, value string) {
mda, _ := metadata.FromContext(h.request.ctx)
md := metadata.Copy(mda)
md.Set(key, value)
h.request.ctx = metadata.NewContext(h.request.ctx, md)
}

func (h goMicroServerTextMapCarrier) Keys() []string {
keys := make([]string, 0)
mda, _ := metadata.FromContext(h.request.ctx)
md := metadata.Copy(mda)
for k, _ := range md {
keys = append(keys, k)
}
return keys
}

func BuildGoMicroServerOtelInstrumenter() *instrumenter.PropagatingFromUpstreamInstrumenter[goMicroServerRequest, goMicroResponse] {
builder := instrumenter.Builder[goMicroServerRequest, goMicroResponse]{}
serverGetter := GoMicroServerAttrsGetter{}
commonExtractor := http.HttpCommonAttrsExtractor[goMicroServerRequest, goMicroResponse, GoMicroServerAttrsGetter, GoMicroServerAttrsGetter]{HttpGetter: serverGetter, NetGetter: serverGetter}
networkExtractor := net.NetworkAttrsExtractor[goMicroServerRequest, goMicroResponse, GoMicroServerAttrsGetter]{Getter: serverGetter}
urlExtractor := net.UrlAttrsExtractor[goMicroServerRequest, goMicroResponse, GoMicroServerAttrsGetter]{Getter: serverGetter}
return builder.Init().SetSpanStatusExtractor(http.HttpServerSpanStatusExtractor[goMicroServerRequest, goMicroResponse]{Getter: serverGetter}).SetSpanNameExtractor(&http.HttpServerSpanNameExtractor[goMicroServerRequest, goMicroResponse]{Getter: serverGetter}).
SetSpanKindExtractor(&instrumenter.AlwaysServerExtractor[goMicroServerRequest]{}).
AddOperationListeners(http.HttpServerMetrics("gomicro.server")).
SetInstrumentationScope(instrumentation.Scope{
Name: utils.GOMICRO_SERVER_SCOPE_NAME,
Version: version.Tag,
}).
AddAttributesExtractor(&http.HttpServerAttrsExtractor[goMicroServerRequest, goMicroResponse, GoMicroServerAttrsGetter, GoMicroServerAttrsGetter, GoMicroServerAttrsGetter]{Base: commonExtractor, NetworkExtractor: networkExtractor, UrlExtractor: urlExtractor}).BuildPropagatingFromUpstreamInstrumenter(func(n goMicroServerRequest) propagation.TextMapCarrier {
return goMicroServerTextMapCarrier{request: &n}
}, otel.GetTextMapPropagator())
}
Loading

0 comments on commit 5061280

Please sign in to comment.