fix: update compressed span name logic for spec change#1336
fix: update compressed span name logic for spec change#1336kruskall merged 7 commits intoelastic:mainfrom
Conversation
The logic to infer the compressed span name has been updated to use the service.target.* fields. Update the code to be compliant with the specification.
🌐 Coverage report
|
axw
left a comment
There was a problem hiding this comment.
Code looks fine. Are we missing some tests?
Sorry for the late reply, I don't think we are. The composite span name should be covered by the current tests: see https://github.com/elastic/apm-agent-go/blob/main/span_test.go#L634 and https://github.com/elastic/apm-agent-go/blob/main/span_test.go#L754. I've added a couple more assertions in the remaining compression span tests for consistency. Let me know what you think! |
|
@kruskall there are now 4 possible ways the composite span name can be constructed, whereas there was just 1 before. I think we should have tests that cover each of those to ensure we maintain compatibility with the spec. Do those tests you pointed out fully cover the spec? I don't see how they could have, seeing as they didn't break. |
|
Good point! I've added a new test to cover the spec. |
| if s.Context.serviceTarget.Name == "" { | ||
| return compressedSpanSameKindName + "unknown" | ||
| } else { | ||
| return compressedSpanSameKindName + s.Context.serviceTarget.Name |
There was a problem hiding this comment.
IIANM it's impossible to reach this code path, since we're guaranteed to infer a service.target.type value if service.target.name is set. Is that correct? Perhaps the spec should be updated to remove the pseudo-code path?
There was a problem hiding this comment.
This is correct. Should we merge this and open a followup PR once the spec is updated ?
We could also remove the line since it's never reached. Let me know what you think!
There was a problem hiding this comment.
I think it's fine to leave it and follow up.
|
Verified with 8.7.0 BC9 using the latest main (332875e) All target fields populatedpackage main
import (
"fmt"
"time"
"go.elastic.co/apm/v2"
)
func main() {
tracer := apm.DefaultTracer()
tracer.SetSpanCompressionEnabled(true)
tracer.SetSpanCompressionSameKindMaxDuration(time.Millisecond)
tracer.SetExitSpanMinDuration(0)
currentTime := time.Now()
tx := tracer.StartTransactionOptions("8.7.0", "testplan", apm.TransactionOptions{
Start: currentTime,
})
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM users", "mysql", "db", "myhost"),
)
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM catalog", "mysql", "db", "myhost"),
)
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM orders", "mysql", "db", "myhost"),
)
tx.End()
tracer.Flush(nil)
fmt.Printf("%+v\n", tracer.Stats())
}
func newSpan(tx *apm.Transaction, start time.Time, name, t, targetType, targetName string) time.Duration {
span := tx.StartSpanOptions(name, t, apm.SpanOptions{
ExitSpan: true, Start: start,
})
span.Duration = 2 * time.Microsecond
span.Context.SetServiceTarget(apm.ServiceTargetSpanContext{
Type: targetType,
Name: targetName,
})
span.End()
return span.Duration
}Service.Target.Name emptypackage main
import (
"fmt"
"time"
"go.elastic.co/apm/v2"
)
func main() {
tracer := apm.DefaultTracer()
tracer.SetSpanCompressionEnabled(true)
tracer.SetSpanCompressionSameKindMaxDuration(time.Millisecond)
tracer.SetExitSpanMinDuration(0)
currentTime := time.Now()
tx := tracer.StartTransactionOptions("8.7.0", "testplan", apm.TransactionOptions{
Start: currentTime,
})
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM users", "mysql", "db", ""),
)
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM catalog", "mysql", "db", ""),
)
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM orders", "mysql", "db", ""),
)
tx.End()
tracer.Flush(nil)
fmt.Printf("%+v\n", tracer.Stats())
}
func newSpan(tx *apm.Transaction, start time.Time, name, t, targetType, targetName string) time.Duration {
span := tx.StartSpanOptions(name, t, apm.SpanOptions{
ExitSpan: true, Start: start,
})
span.Duration = 2 * time.Microsecond
span.Context.SetServiceTarget(apm.ServiceTargetSpanContext{
Type: targetType,
Name: targetName,
})
span.End()
return span.Duration
}Service.Target.Type emptypackage main
import (
"fmt"
"time"
"go.elastic.co/apm/v2"
)
func main() {
tracer := apm.DefaultTracer()
tracer.SetSpanCompressionEnabled(true)
tracer.SetSpanCompressionSameKindMaxDuration(time.Millisecond)
tracer.SetExitSpanMinDuration(0)
currentTime := time.Now()
tx := tracer.StartTransactionOptions("8.7.0", "testplan", apm.TransactionOptions{
Start: currentTime,
})
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM users", "mysql", "", "myhost"),
)
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM catalog", "mysql", "", "myhost"),
)
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM orders", "mysql", "", "myhost"),
)
tx.End()
tracer.Flush(nil)
fmt.Printf("%+v\n", tracer.Stats())
}
func newSpan(tx *apm.Transaction, start time.Time, name, t, targetType, targetName string) time.Duration {
span := tx.StartSpanOptions(name, t, apm.SpanOptions{
ExitSpan: true, Start: start,
})
span.Duration = 2 * time.Microsecond
span.Context.SetServiceTarget(apm.ServiceTargetSpanContext{
Type: targetType,
Name: targetName,
})
span.End()
return span.Duration
}Target.Name and Target.Type emptypackage main
import (
"fmt"
"time"
"go.elastic.co/apm/v2"
)
func main() {
tracer := apm.DefaultTracer()
tracer.SetSpanCompressionEnabled(true)
tracer.SetSpanCompressionSameKindMaxDuration(time.Millisecond)
tracer.SetExitSpanMinDuration(0)
currentTime := time.Now()
tx := tracer.StartTransactionOptions("8.7.0", "testplan", apm.TransactionOptions{
Start: currentTime,
})
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM users", "mysql", "", ""),
)
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM catalog", "mysql", "", ""),
)
currentTime.Add(
newSpan(tx, currentTime, "SELECT * FROM orders", "mysql", "", ""),
)
tx.End()
tracer.Flush(nil)
fmt.Printf("%+v\n", tracer.Stats())
}
func newSpan(tx *apm.Transaction, start time.Time, name, t, targetType, targetName string) time.Duration {
span := tx.StartSpanOptions(name, t, apm.SpanOptions{
ExitSpan: true, Start: start,
})
span.Duration = 2 * time.Microsecond
span.Context.SetServiceTarget(apm.ServiceTargetSpanContext{
Type: targetType,
Name: targetName,
})
span.End()
return span.Duration
} |




The logic to infer the compressed span name has been updated to use the service.target.* fields.
Update the code to be compliant with the specification.
Closes #1331
See elastic/apm#697
See elastic/apm#674
Not all the changes to the spec apply to the go agent:
service.target.*fields has been clarified but we are already compliant with the spec