diff --git a/v1/ao/opentracing/tags.go b/v1/ao/opentracing/tags.go index 953f3247..fd742475 100644 --- a/v1/ao/opentracing/tags.go +++ b/v1/ao/opentracing/tags.go @@ -19,6 +19,8 @@ var otAOMap = map[string]string{ string(ext.DBInstance): "Database", string(ext.DBStatement): "Query", string(ext.DBType): "Flavor", + + "resource.name": "TransactionName", } func translateTagName(key string) string { @@ -27,11 +29,3 @@ func translateTagName(key string) string { } return key } - -func translateTags(tags map[string]interface{}) map[string]interface{} { - ret := make(map[string]interface{}) - for k, v := range tags { - ret[translateTagName(k)] = v - } - return ret -} diff --git a/v1/ao/opentracing/tracer.go b/v1/ao/opentracing/tracer.go index 3e755fa6..e630b2bd 100644 --- a/v1/ao/opentracing/tracer.go +++ b/v1/ao/opentracing/tracer.go @@ -37,6 +37,7 @@ func (t *Tracer) StartSpan(operationName string, opts ...ot.StartSpanOption) ot. func (t *Tracer) startSpanWithOptions(operationName string, opts ot.StartSpanOptions) ot.Span { // check if trace has already started (use Trace if there is no parent, Span otherwise) // XXX handle StartTime + var newSpan ot.Span for _, ref := range opts.References { switch ref.Type { @@ -46,26 +47,33 @@ func (t *Tracer) startSpanWithOptions(operationName string, opts ot.StartSpanOpt if refCtx.span == nil { // referenced spanContext created by Extract() var span ao.Span if refCtx.sampled { - span = ao.NewTraceFromID(operationName, refCtx.remoteMD, func() ao.KVMap { - return translateTags(opts.Tags) - }) + span = ao.NewTraceFromID(operationName, refCtx.remoteMD, nil) } else { span = ao.NewNullTrace() } - return &spanImpl{tracer: t, context: spanContext{ + newSpan = &spanImpl{tracer: t, context: spanContext{ span: span, sampled: refCtx.sampled, baggage: refCtx.baggage, }, } + } else { + // referenced spanContext was in-process + newSpan = &spanImpl{tracer: t, context: spanContext{span: refCtx.span.BeginSpan(operationName)}} } - // referenced spanContext was in-process - return &spanImpl{tracer: t, context: spanContext{span: refCtx.span.BeginSpan(operationName)}} } } // otherwise, no parent span found, so make new trace and return as span - newSpan := &spanImpl{tracer: t, context: spanContext{span: ao.NewTrace(operationName)}} + if newSpan == nil { + newSpan = &spanImpl{tracer: t, context: spanContext{span: ao.NewTrace(operationName)}} + } + + // add tags, if provided in span options + for k, v := range opts.Tags { + newSpan.SetTag(k, v) + } + return newSpan } @@ -190,7 +198,14 @@ func (s *spanImpl) SetOperationName(operationName string) ot.Span { func (s *spanImpl) SetTag(key string, value interface{}) ot.Span { s.Lock() defer s.Unlock() - s.context.span.AddEndArgs(translateTagName(key), value) + // if transaction name is passed, set on the span + if tagName := translateTagName(key); tagName == "TransactionName" { + if txnName, ok := value.(string); ok { + s.context.span.SetTransactionName(txnName) + } + } else { + s.context.span.AddEndArgs(tagName, value) + } return s } diff --git a/v1/ao/opentracing/tracer_test.go b/v1/ao/opentracing/tracer_test.go index 84ff976b..efdb2942 100644 --- a/v1/ao/opentracing/tracer_test.go +++ b/v1/ao/opentracing/tracer_test.go @@ -5,9 +5,12 @@ package opentracing import ( "testing" + g "github.com/appoptics/appoptics-apm-go/v1/ao/internal/graphtest" + "github.com/appoptics/appoptics-apm-go/v1/ao/internal/metrics" "github.com/appoptics/appoptics-apm-go/v1/ao/internal/reporter" opentracing "github.com/opentracing/opentracing-go" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestSpanBaggageUnsampled(t *testing.T) { @@ -23,3 +26,33 @@ func TestSpanBaggageUnsampled(t *testing.T) { childSpan := tr.StartSpan("op2", opentracing.ChildOf(sp.Context())) assert.NotNil(t, childSpan) } + +func testTransactionName(t *testing.T, tagName, txnName string) { + r := reporter.SetTestReporter() // set up test reporter + tr := NewTracer() + + span := tr.StartSpan("op") + assert.NotNil(t, span) + span.SetTag(tagName, txnName) + span.SetTag("http.url", "http://app.com/myURL/123/456") + span.Finish() + + r.Close(2) + g.AssertGraph(t, r.EventBufs, 2, g.AssertNodeKVMap{ + {"op", "entry", "", ""}: {}, + {"op", "exit", "TransactionName", txnName}: {Edges: g.Edges{{"op", "entry"}}}, + }) + + require.Len(t, r.SpanMessages, 1) + m, ok := r.SpanMessages[0].(*metrics.HTTPSpanMessage) + require.True(t, ok) + assert.Equal(t, txnName, m.Transaction) +} + +func TestOTSetTransactionName(t *testing.T) { + testTransactionName(t, "TransactionName", "myTxn") +} + +func TestOTSetResourceName(t *testing.T) { + testTransactionName(t, "resource.name", "myTxn2") +}