|
|
|
package trace
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
ztrace "github.com/zeromicro/go-zero/internal/trace"
|
|
|
|
"go.opentelemetry.io/otel"
|
|
|
|
"go.opentelemetry.io/otel/attribute"
|
|
|
|
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
|
|
|
|
"go.opentelemetry.io/otel/trace"
|
|
|
|
"google.golang.org/grpc/peer"
|
|
|
|
)
|
|
|
|
|
|
|
|
const localhost = "127.0.0.1"
|
|
|
|
|
|
|
|
var (
|
|
|
|
// SpanIDFromContext returns the span id from ctx.
|
|
|
|
SpanIDFromContext = ztrace.SpanIDFromContext
|
|
|
|
// TraceIDFromContext returns the trace id from ctx.
|
|
|
|
TraceIDFromContext = ztrace.TraceIDFromContext
|
|
|
|
)
|
|
|
|
|
|
|
|
// PeerFromCtx returns the peer from ctx.
|
|
|
|
func PeerFromCtx(ctx context.Context) string {
|
|
|
|
p, ok := peer.FromContext(ctx)
|
|
|
|
if !ok || p == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
return p.Addr.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
// SpanInfo returns the span info.
|
|
|
|
func SpanInfo(fullMethod, peerAddress string) (string, []attribute.KeyValue) {
|
|
|
|
attrs := []attribute.KeyValue{RPCSystemGRPC}
|
|
|
|
name, mAttrs := ParseFullMethod(fullMethod)
|
|
|
|
attrs = append(attrs, mAttrs...)
|
|
|
|
attrs = append(attrs, PeerAttr(peerAddress)...)
|
|
|
|
return name, attrs
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParseFullMethod returns the method name and attributes.
|
|
|
|
func ParseFullMethod(fullMethod string) (string, []attribute.KeyValue) {
|
|
|
|
name := strings.TrimLeft(fullMethod, "/")
|
|
|
|
parts := strings.SplitN(name, "/", 2)
|
|
|
|
if len(parts) != 2 {
|
|
|
|
// Invalid format, does not follow `/package.service/method`.
|
|
|
|
return name, []attribute.KeyValue(nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
var attrs []attribute.KeyValue
|
|
|
|
if service := parts[0]; service != "" {
|
|
|
|
attrs = append(attrs, semconv.RPCServiceKey.String(service))
|
|
|
|
}
|
|
|
|
if method := parts[1]; method != "" {
|
|
|
|
attrs = append(attrs, semconv.RPCMethodKey.String(method))
|
|
|
|
}
|
|
|
|
|
|
|
|
return name, attrs
|
|
|
|
}
|
|
|
|
|
|
|
|
// PeerAttr returns the peer attributes.
|
|
|
|
func PeerAttr(addr string) []attribute.KeyValue {
|
|
|
|
host, port, err := net.SplitHostPort(addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(host) == 0 {
|
|
|
|
host = localhost
|
|
|
|
}
|
|
|
|
|
|
|
|
return []attribute.KeyValue{
|
|
|
|
semconv.NetPeerIPKey.String(host),
|
|
|
|
semconv.NetPeerPortKey.String(port),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TracerFromContext returns a tracer in ctx, otherwise returns a global tracer.
|
|
|
|
func TracerFromContext(ctx context.Context) (tracer trace.Tracer) {
|
|
|
|
if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() {
|
|
|
|
tracer = span.TracerProvider().Tracer(TraceName)
|
|
|
|
} else {
|
|
|
|
tracer = otel.Tracer(TraceName)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|