You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-11-23 22:34:47 +02:00
Golang opentelemetry-go draft API (incomplete) (#9)
* Work in progress from https://github.com/lightstep/opentelemetry-golang-prototype * Renames * Rename * Finish rename * Rename packages * README
This commit is contained in:
committed by
rghetia
parent
1429272864
commit
e17f4468a6
144
api/trace/api.go
Normal file
144
api/trace/api.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package trace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/open-telemetry/opentelemetry-go/api/core"
|
||||
"github.com/open-telemetry/opentelemetry-go/api/log"
|
||||
"github.com/open-telemetry/opentelemetry-go/api/scope"
|
||||
"github.com/open-telemetry/opentelemetry-go/api/stats"
|
||||
"github.com/open-telemetry/opentelemetry-go/api/tag"
|
||||
)
|
||||
|
||||
type (
|
||||
Tracer interface {
|
||||
Start(context.Context, string, ...Option) (context.Context, Span)
|
||||
|
||||
WithSpan(
|
||||
ctx context.Context,
|
||||
operation string,
|
||||
body func(ctx context.Context) error,
|
||||
) error
|
||||
|
||||
WithService(name string) Tracer
|
||||
WithComponent(name string) Tracer
|
||||
WithResources(res ...core.KeyValue) Tracer
|
||||
|
||||
// Note: see https://github.com/opentracing/opentracing-go/issues/127
|
||||
Inject(context.Context, Span, Injector)
|
||||
|
||||
// ScopeID returns the resource scope of this tracer.
|
||||
scope.Scope
|
||||
}
|
||||
|
||||
Span interface {
|
||||
scope.Mutable
|
||||
|
||||
log.Interface
|
||||
|
||||
stats.Interface
|
||||
|
||||
SetError(bool)
|
||||
|
||||
Tracer() Tracer
|
||||
|
||||
Finish()
|
||||
}
|
||||
|
||||
Injector interface {
|
||||
Inject(core.SpanContext, tag.Map)
|
||||
}
|
||||
|
||||
Option struct {
|
||||
attribute core.KeyValue
|
||||
attributes []core.KeyValue
|
||||
startTime time.Time
|
||||
reference Reference
|
||||
}
|
||||
|
||||
Reference struct {
|
||||
core.SpanContext
|
||||
RelationshipType
|
||||
}
|
||||
|
||||
RelationshipType int
|
||||
)
|
||||
|
||||
const (
|
||||
ChildOfRelationship RelationshipType = iota
|
||||
FollowsFromRelationship
|
||||
)
|
||||
|
||||
func GlobalTracer() Tracer {
|
||||
if t := global.Load(); t != nil {
|
||||
return t.(Tracer)
|
||||
}
|
||||
return empty
|
||||
}
|
||||
|
||||
func SetGlobalTracer(t Tracer) {
|
||||
global.Store(t)
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, name string, opts ...Option) (context.Context, Span) {
|
||||
return GlobalTracer().Start(ctx, name, opts...)
|
||||
}
|
||||
|
||||
func Active(ctx context.Context) Span {
|
||||
span, _ := scope.Active(ctx).(*span)
|
||||
return span
|
||||
}
|
||||
|
||||
func WithSpan(ctx context.Context, name string, body func(context.Context) error) error {
|
||||
return GlobalTracer().WithSpan(ctx, name, body)
|
||||
}
|
||||
|
||||
func SetError(ctx context.Context, v bool) {
|
||||
Active(ctx).SetError(v)
|
||||
}
|
||||
|
||||
func Inject(ctx context.Context, injector Injector) {
|
||||
span := Active(ctx)
|
||||
if span == nil {
|
||||
return
|
||||
}
|
||||
|
||||
span.Tracer().Inject(ctx, span, injector)
|
||||
}
|
||||
|
||||
func WithStartTime(t time.Time) Option {
|
||||
return Option{
|
||||
startTime: t,
|
||||
}
|
||||
}
|
||||
|
||||
func WithAttributes(attrs ...core.KeyValue) Option {
|
||||
return Option{
|
||||
attributes: attrs,
|
||||
}
|
||||
}
|
||||
|
||||
func WithAttribute(attr core.KeyValue) Option {
|
||||
return Option{
|
||||
attribute: attr,
|
||||
}
|
||||
}
|
||||
|
||||
func ChildOf(sc core.SpanContext) Option {
|
||||
return Option{
|
||||
reference: Reference{
|
||||
SpanContext: sc,
|
||||
RelationshipType: ChildOfRelationship,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func FollowsFrom(sc core.SpanContext) Option {
|
||||
return Option{
|
||||
reference: Reference{
|
||||
SpanContext: sc,
|
||||
RelationshipType: FollowsFromRelationship,
|
||||
},
|
||||
}
|
||||
}
|
||||
138
api/trace/span.go
Normal file
138
api/trace/span.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package trace
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/open-telemetry/opentelemetry-go/api/core"
|
||||
"github.com/open-telemetry/opentelemetry-go/api/log"
|
||||
"github.com/open-telemetry/opentelemetry-go/api/stats"
|
||||
"github.com/open-telemetry/opentelemetry-go/exporter/observer"
|
||||
)
|
||||
|
||||
func (sp *span) ScopeID() core.ScopeID {
|
||||
if sp == nil {
|
||||
return core.ScopeID{}
|
||||
}
|
||||
sp.lock.Lock()
|
||||
sid := core.ScopeID{
|
||||
EventID: sp.eventID,
|
||||
SpanContext: sp.spanContext,
|
||||
}
|
||||
sp.lock.Unlock()
|
||||
return sid
|
||||
}
|
||||
|
||||
func (sp *span) updateScope() (core.ScopeID, core.EventID) {
|
||||
next := observer.NextEventID()
|
||||
|
||||
sp.lock.Lock()
|
||||
sid := core.ScopeID{
|
||||
EventID: sp.eventID,
|
||||
SpanContext: sp.spanContext,
|
||||
}
|
||||
sp.eventID = next
|
||||
sp.lock.Unlock()
|
||||
|
||||
return sid, next
|
||||
}
|
||||
|
||||
func (sp *span) SetError(v bool) {
|
||||
sp.SetAttribute(ErrorKey.Bool(v))
|
||||
}
|
||||
|
||||
func (sp *span) SetAttribute(attribute core.KeyValue) {
|
||||
if sp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
sid, next := sp.updateScope()
|
||||
|
||||
observer.Record(observer.Event{
|
||||
Type: observer.MODIFY_ATTR,
|
||||
Scope: sid,
|
||||
Sequence: next,
|
||||
Attribute: attribute,
|
||||
})
|
||||
}
|
||||
|
||||
func (sp *span) SetAttributes(attributes ...core.KeyValue) {
|
||||
if sp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
sid, next := sp.updateScope()
|
||||
|
||||
observer.Record(observer.Event{
|
||||
Type: observer.MODIFY_ATTR,
|
||||
Scope: sid,
|
||||
Sequence: next,
|
||||
Attributes: attributes,
|
||||
})
|
||||
}
|
||||
|
||||
func (sp *span) ModifyAttribute(mutator core.Mutator) {
|
||||
if sp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
sid, next := sp.updateScope()
|
||||
|
||||
observer.Record(observer.Event{
|
||||
Type: observer.MODIFY_ATTR,
|
||||
Scope: sid,
|
||||
Sequence: next,
|
||||
Mutator: mutator,
|
||||
})
|
||||
}
|
||||
|
||||
func (sp *span) ModifyAttributes(mutators ...core.Mutator) {
|
||||
if sp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
sid, next := sp.updateScope()
|
||||
|
||||
observer.Record(observer.Event{
|
||||
Type: observer.MODIFY_ATTR,
|
||||
Scope: sid,
|
||||
Sequence: next,
|
||||
Mutators: mutators,
|
||||
})
|
||||
}
|
||||
|
||||
func (sp *span) Finish() {
|
||||
if sp == nil {
|
||||
return
|
||||
}
|
||||
recovered := recover()
|
||||
sp.finishOnce.Do(func() {
|
||||
observer.Record(observer.Event{
|
||||
Type: observer.FINISH_SPAN,
|
||||
Scope: sp.ScopeID(),
|
||||
Recovered: recovered,
|
||||
})
|
||||
})
|
||||
if recovered != nil {
|
||||
panic(recovered)
|
||||
}
|
||||
}
|
||||
|
||||
func (sp *span) Tracer() Tracer {
|
||||
return sp.tracer
|
||||
}
|
||||
|
||||
func (sp *span) Log(ctx context.Context, msg string, args ...core.KeyValue) {
|
||||
log.With(sp).Log(ctx, msg, args...)
|
||||
}
|
||||
|
||||
func (sp *span) Logf(ctx context.Context, fmt string, args ...interface{}) {
|
||||
log.With(sp).Logf(ctx, fmt, args...)
|
||||
}
|
||||
|
||||
func (sp *span) Record(ctx context.Context, m ...core.Measurement) {
|
||||
stats.With(sp).Record(ctx, m...)
|
||||
}
|
||||
|
||||
func (sp *span) RecordSingle(ctx context.Context, m core.Measurement) {
|
||||
stats.With(sp).RecordSingle(ctx, m)
|
||||
}
|
||||
145
api/trace/trace.go
Normal file
145
api/trace/trace.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package trace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/open-telemetry/opentelemetry-go/api/core"
|
||||
"github.com/open-telemetry/opentelemetry-go/api/log"
|
||||
"github.com/open-telemetry/opentelemetry-go/api/scope"
|
||||
"github.com/open-telemetry/opentelemetry-go/api/tag"
|
||||
"github.com/open-telemetry/opentelemetry-go/exporter/observer"
|
||||
)
|
||||
|
||||
type (
|
||||
span struct {
|
||||
tracer *tracer
|
||||
spanContext core.SpanContext
|
||||
lock sync.Mutex
|
||||
eventID core.EventID
|
||||
finishOnce sync.Once
|
||||
}
|
||||
|
||||
tracer struct {
|
||||
resources core.EventID
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
ServiceKey = tag.New("service")
|
||||
ComponentKey = tag.New("component")
|
||||
ErrorKey = tag.New("error")
|
||||
SpanIDKey = tag.New("span_id")
|
||||
TraceIDKey = tag.New("trace_id")
|
||||
ParentSpanIDKey = tag.New("parent_span_id")
|
||||
MessageKey = tag.New("message",
|
||||
tag.WithDescription("message text: info, error, etc"),
|
||||
)
|
||||
|
||||
// The process global tracer could have process-wide resource
|
||||
// tags applied directly, or we can have a SetGlobal tracer to
|
||||
// install a default tracer w/ resources.
|
||||
global atomic.Value
|
||||
empty = &tracer{}
|
||||
)
|
||||
|
||||
func (t *tracer) ScopeID() core.ScopeID {
|
||||
return t.resources.Scope()
|
||||
}
|
||||
|
||||
func (t *tracer) WithResources(attributes ...core.KeyValue) Tracer {
|
||||
s := scope.New(t.resources.Scope(), attributes...)
|
||||
return &tracer{
|
||||
resources: s.ScopeID().EventID,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *tracer) WithComponent(name string) Tracer {
|
||||
return g.WithResources(ComponentKey.String(name))
|
||||
}
|
||||
|
||||
func (g *tracer) WithService(name string) Tracer {
|
||||
return g.WithResources(ServiceKey.String(name))
|
||||
}
|
||||
|
||||
func (t *tracer) WithSpan(ctx context.Context, name string, body func(context.Context) error) error {
|
||||
// TODO: use runtime/trace.WithRegion for execution tracer support
|
||||
// TODO: use runtime/pprof.Do for profile tags support
|
||||
ctx, span := t.Start(ctx, name)
|
||||
defer span.Finish()
|
||||
|
||||
if err := body(ctx); err != nil {
|
||||
span.SetAttribute(ErrorKey.Bool(true))
|
||||
log.Log(ctx, "span error", MessageKey.String(err.Error()))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *tracer) Start(ctx context.Context, name string, opts ...Option) (context.Context, Span) {
|
||||
var child core.SpanContext
|
||||
|
||||
child.SpanID = rand.Uint64()
|
||||
|
||||
var startTime time.Time
|
||||
var attributes []core.KeyValue
|
||||
var reference Reference
|
||||
|
||||
for _, opt := range opts {
|
||||
if !opt.startTime.IsZero() {
|
||||
startTime = opt.startTime
|
||||
}
|
||||
if len(opt.attributes) != 0 {
|
||||
attributes = append(opt.attributes, attributes...)
|
||||
}
|
||||
if opt.attribute.Key != nil {
|
||||
attributes = append(attributes, opt.attribute)
|
||||
}
|
||||
if opt.reference.HasTraceID() {
|
||||
reference = opt.reference
|
||||
}
|
||||
}
|
||||
|
||||
var parentScope core.ScopeID
|
||||
|
||||
if reference.HasTraceID() {
|
||||
parentScope = reference.Scope()
|
||||
} else {
|
||||
parentScope = Active(ctx).ScopeID()
|
||||
}
|
||||
|
||||
if parentScope.HasTraceID() {
|
||||
parent := parentScope.SpanContext
|
||||
child.TraceIDHigh = parent.TraceIDHigh
|
||||
child.TraceIDLow = parent.TraceIDLow
|
||||
} else {
|
||||
child.TraceIDHigh = rand.Uint64()
|
||||
child.TraceIDLow = rand.Uint64()
|
||||
}
|
||||
|
||||
childScope := core.ScopeID{
|
||||
SpanContext: child,
|
||||
EventID: t.resources,
|
||||
}
|
||||
|
||||
span := &span{
|
||||
spanContext: child,
|
||||
tracer: t,
|
||||
eventID: observer.Record(observer.Event{
|
||||
Time: startTime,
|
||||
Type: observer.START_SPAN,
|
||||
Scope: scope.New(childScope, attributes...).ScopeID(),
|
||||
Context: ctx,
|
||||
Parent: parentScope,
|
||||
String: name,
|
||||
}),
|
||||
}
|
||||
return scope.SetActive(ctx, span), span
|
||||
}
|
||||
|
||||
func (t *tracer) Inject(ctx context.Context, span Span, injector Injector) {
|
||||
injector.Inject(span.ScopeID().SpanContext, tag.FromContext(ctx))
|
||||
}
|
||||
Reference in New Issue
Block a user