Skip to content

fix: update compressed span name logic for spec change#1336

Merged
kruskall merged 7 commits intoelastic:mainfrom
kruskall:fix/update-compressed-span-name
Dec 5, 2022
Merged

fix: update compressed span name logic for spec change#1336
kruskall merged 7 commits intoelastic:mainfrom
kruskall:fix/update-compressed-span-name

Conversation

@kruskall
Copy link
Member

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:

  • ot bridge is not fully implemented (See [META 524] OpenTelemetry Bridge #1140)
  • the logic to infer the service.target.* fields has been clarified but we are already compliant with the spec
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.
@ghost
Copy link

ghost commented Oct 19, 2022

💚 Build Succeeded

the below badges are clickable and redirect to their specific view in the CI or DOCS
Pipeline View Test View Changes Artifacts preview preview

Expand to view the summary

Build stats

  • Start Time: 2022-12-05T01:17:38.568+0000

  • Duration: 61 min 32 sec

Test stats 🧪

Test Results
Failed 0
Passed 8767
Skipped 222
Total 8989

🤖 GitHub comments

Expand to view the GitHub comments

To re-run your PR in the CI, just comment with:

  • /test : Re-trigger the build.

  • run benchmark tests : Run the benchmark test.

  • run elasticsearch-ci/docs : Re-trigger the docs validation. (use unformatted text in the comment!)

@ghost
Copy link

ghost commented Oct 19, 2022

🌐 Coverage report

Name Metrics % (covered/total) Diff
Packages 100.0% (60/60) 💚
Files 99.355% (154/155) 👍
Classes 96.317% (340/353) 👍
Methods 90.349% (983/1088) 👍 0.009
Lines 82.148% (11440/13926) 👎 -0.064
Conditionals 100.0% (0/0) 💚
Copy link
Member

@axw axw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks fine. Are we missing some tests?

@kruskall
Copy link
Member Author

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 kruskall requested a review from axw November 18, 2022 05:44
@axw
Copy link
Member

axw commented Nov 18, 2022

@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.

@kruskall
Copy link
Member Author

kruskall commented Dec 4, 2022

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine to leave it and follow up.

@kruskall kruskall requested a review from axw December 5, 2022 01:17
@kruskall kruskall merged commit e0b492f into elastic:main Dec 5, 2022
@kruskall kruskall deleted the fix/update-compressed-span-name branch December 5, 2022 03:33
@marclop marclop self-assigned this Mar 29, 2023
@marclop
Copy link
Contributor

marclop commented Mar 29, 2023

Verified with 8.7.0 BC9 using the latest main (332875e)

All target fields populated

package 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
}

image

Service.Target.Name empty

package 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
}

image

Service.Target.Type empty

package 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
}

image

Target.Name and Target.Type empty

package 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
}

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

3 participants