Skip to content

Commit 222386e

Browse files
committed
Add transaction.{sampled, type} as span event attribute
1 parent 82d649e commit 222386e

File tree

3 files changed

+83
-21
lines changed

3 files changed

+83
-21
lines changed

enrichments/trace/config/config.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,10 @@ type SpanEventConfig struct {
7979
// TimestampUs is a temporary attribute to enable higher
8080
// resolution timestamps in Elasticsearch. For more details see:
8181
// https://github.com/elastic/opentelemetry-dev/issues/374.
82-
TimestampUs AttributeConfig `mapstructure:"timestamp_us"`
83-
ProcessorEvent AttributeConfig `mapstructure:"processor_event"`
82+
TimestampUs AttributeConfig `mapstructure:"timestamp_us"`
83+
TransactionSampled AttributeConfig `mapstructure:"transaction_sampled"`
84+
TransactionType AttributeConfig `mapstructure:"transaction_type"`
85+
ProcessorEvent AttributeConfig `mapstructure:"processor_event"`
8486

8587
// For exceptions/errors
8688
ErrorID AttributeConfig `mapstructure:"error_id"`
@@ -133,6 +135,8 @@ func Enabled() Config {
133135
},
134136
SpanEvent: SpanEventConfig{
135137
TimestampUs: AttributeConfig{Enabled: true},
138+
TransactionSampled: AttributeConfig{Enabled: true},
139+
TransactionType: AttributeConfig{Enabled: true},
136140
ProcessorEvent: AttributeConfig{Enabled: true},
137141
ErrorID: AttributeConfig{Enabled: true},
138142
ErrorExceptionHandled: AttributeConfig{Enabled: true},

enrichments/trace/internal/elastic/span.go

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ type spanEnrichmentContext struct {
7373

7474
spanStatusCode ptrace.StatusCode
7575

76+
// TODO (lahsivjar): Refactor span enrichment to better utilize isTransaction
77+
isTransaction bool
7678
isMessaging bool
7779
isRPC bool
7880
isHTTP bool
@@ -153,20 +155,22 @@ func (s *spanEnrichmentContext) Enrich(span ptrace.Span, cfg config.Config) {
153155
return true
154156
})
155157

156-
// Ensure all dependent attributes are handled.
157158
s.normalizeAttributes()
158-
159-
isElasticTxn := isElasticTransaction(span)
160-
if isElasticTxn {
161-
s.enrichTransaction(span, cfg.Transaction)
162-
} else {
163-
s.enrichSpan(span, cfg.Span)
164-
}
159+
s.isTransaction = isElasticTransaction(span)
160+
s.enrich(span, cfg)
165161

166162
spanEvents := span.Events()
167163
for i := 0; i < spanEvents.Len(); i++ {
168164
var c spanEventEnrichmentContext
169-
c.enrich(spanEvents.At(i), cfg.SpanEvent)
165+
c.enrich(s, spanEvents.At(i), cfg.SpanEvent)
166+
}
167+
}
168+
169+
func (s *spanEnrichmentContext) enrich(span ptrace.Span, cfg config.Config) {
170+
if s.isTransaction {
171+
s.enrichTransaction(span, cfg.Transaction)
172+
} else {
173+
s.enrichSpan(span, cfg.Span)
170174
}
171175
}
172176

@@ -178,7 +182,7 @@ func (s *spanEnrichmentContext) enrichTransaction(
178182
span.Attributes().PutInt(AttributeTimestampUs, getTimestampUs(span.StartTimestamp()))
179183
}
180184
if cfg.Sampled.Enabled {
181-
span.Attributes().PutBool(AttributeTransactionSampled, true)
185+
span.Attributes().PutBool(AttributeTransactionSampled, s.getSampled())
182186
}
183187
if cfg.ID.Enabled {
184188
span.Attributes().PutStr(AttributeTransactionID, span.SpanID().String())
@@ -200,7 +204,7 @@ func (s *spanEnrichmentContext) enrichTransaction(
200204
span.Attributes().PutInt(AttributeTransactionDurationUs, getDurationUs(span))
201205
}
202206
if cfg.Type.Enabled {
203-
s.setTxnType(span)
207+
span.Attributes().PutStr(AttributeTransactionType, s.getTxnType())
204208
}
205209
if cfg.Result.Enabled {
206210
s.setTxnResult(span)
@@ -252,15 +256,20 @@ func (s *spanEnrichmentContext) normalizeAttributes() {
252256
}
253257
}
254258

255-
func (s *spanEnrichmentContext) setTxnType(span ptrace.Span) {
259+
func (s *spanEnrichmentContext) getSampled() bool {
260+
// Assumes that the method is called only for transaction
261+
return true
262+
}
263+
264+
func (s *spanEnrichmentContext) getTxnType() string {
256265
txnType := "unknown"
257266
switch {
258267
case s.isMessaging:
259268
txnType = "messaging"
260269
case s.isRPC, s.isHTTP:
261270
txnType = "request"
262271
}
263-
span.Attributes().PutStr(AttributeTransactionType, txnType)
272+
return txnType
264273
}
265274

266275
func (s *spanEnrichmentContext) setTxnResult(span ptrace.Span) {
@@ -430,6 +439,7 @@ type spanEventEnrichmentContext struct {
430439
}
431440

432441
func (s *spanEventEnrichmentContext) enrich(
442+
parentCtx *spanEnrichmentContext,
433443
se ptrace.SpanEvent,
434444
cfg config.SpanEventConfig,
435445
) {
@@ -481,6 +491,16 @@ func (s *spanEventEnrichmentContext) enrich(
481491
}
482492
se.Attributes().PutStr(AttributeErrorGroupingKey, hex.EncodeToString(hash.Sum(nil)))
483493
}
494+
495+
// Transaction type and sampled are added as span event enrichment only for errors
496+
if parentCtx.isTransaction && s.exception {
497+
if cfg.TransactionSampled.Enabled {
498+
se.Attributes().PutBool(AttributeTransactionSampled, parentCtx.getSampled())
499+
}
500+
if cfg.TransactionType.Enabled {
501+
se.Attributes().PutStr(AttributeTransactionType, parentCtx.getTxnType())
502+
}
503+
}
484504
}
485505

486506
// getRepresentativeCount returns the number of spans represented by an

enrichments/trace/internal/elastic/span_test.go

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -764,13 +764,15 @@ func TestSpanEventEnrich(t *testing.T) {
764764
ts := pcommon.NewTimestampFromTime(now)
765765
for _, tc := range []struct {
766766
name string
767+
parent ptrace.Span
767768
input ptrace.SpanEvent
768769
config config.SpanEventConfig
769770
errorID bool // indicates if the error ID should be present in the result
770771
enrichedAttrs map[string]any
771772
}{
772773
{
773-
name: "not_exception",
774+
name: "not_exception",
775+
parent: ptrace.NewSpan(),
774776
input: func() ptrace.SpanEvent {
775777
event := ptrace.NewSpanEvent()
776778
event.SetTimestamp(ts)
@@ -783,7 +785,44 @@ func TestSpanEventEnrich(t *testing.T) {
783785
},
784786
},
785787
{
786-
name: "exception",
788+
name: "exception_with_elastic_txn",
789+
parent: func() ptrace.Span {
790+
// No parent, elastic txn
791+
span := ptrace.NewSpan()
792+
return span
793+
}(),
794+
input: func() ptrace.SpanEvent {
795+
event := ptrace.NewSpanEvent()
796+
event.SetName("exception")
797+
event.SetTimestamp(ts)
798+
event.Attributes().PutStr(semconv.AttributeExceptionType, "java.net.ConnectionError")
799+
event.Attributes().PutStr(semconv.AttributeExceptionMessage, "something is wrong")
800+
event.Attributes().PutStr(semconv.AttributeExceptionStacktrace, `Exception in thread "main" java.lang.RuntimeException: Test exception\\n at com.example.GenerateTrace.methodB(GenerateTrace.java:13)\\n at com.example.GenerateTrace.methodA(GenerateTrace.java:9)\\n at com.example.GenerateTrace.main(GenerateTrace.java:5)`)
801+
return event
802+
}(),
803+
config: config.Enabled().SpanEvent,
804+
errorID: true,
805+
enrichedAttrs: map[string]any{
806+
AttributeTimestampUs: ts.AsTime().UnixMicro(),
807+
AttributeProcessorEvent: "error",
808+
AttributeErrorExceptionHandled: true,
809+
AttributeErrorGroupingKey: func() string {
810+
hash := md5.New()
811+
hash.Write([]byte("java.net.ConnectionError"))
812+
return hex.EncodeToString(hash.Sum(nil))
813+
}(),
814+
AttributeTransactionSampled: true,
815+
AttributeTransactionType: "unknown",
816+
},
817+
},
818+
{
819+
name: "exception_with_elastic_span",
820+
parent: func() ptrace.Span {
821+
// Parent, elastic span
822+
span := ptrace.NewSpan()
823+
span.SetParentSpanID([8]byte{8, 9, 10, 11, 12, 13, 14})
824+
return span
825+
}(),
787826
input: func() ptrace.SpanEvent {
788827
event := ptrace.NewSpanEvent()
789828
event.SetName("exception")
@@ -815,13 +854,12 @@ func TestSpanEventEnrich(t *testing.T) {
815854
expectedAttrs[k] = v
816855
}
817856

818-
span := ptrace.NewSpan()
819-
tc.input.MoveTo(span.Events().AppendEmpty())
820-
EnrichSpan(span, config.Config{
857+
tc.input.MoveTo(tc.parent.Events().AppendEmpty())
858+
EnrichSpan(tc.parent, config.Config{
821859
SpanEvent: tc.config,
822860
})
823861

824-
actual := span.Events().At(0).Attributes()
862+
actual := tc.parent.Events().At(0).Attributes()
825863
errorID, ok := actual.Get(AttributeErrorID)
826864
assert.Equal(t, tc.errorID, ok, "error_id must be present for exception and must not be present for non-exception")
827865
if tc.errorID {

0 commit comments

Comments
 (0)