From ba028a839d8de0545dbbde532113fb45959266ac Mon Sep 17 00:00:00 2001 From: Tolyan Korniltsev Date: Tue, 7 Jul 2026 21:19:55 +0700 Subject: [PATCH 1/2] test: verify otel scope label integration Ensure the Java agent's OTel scope name survives shading and is queryable against the latest Pyroscope image. --- agent/build.gradle | 5 ++++- examples/docker-compose-base.yml | 2 +- examples/docker-compose-expt.yml | 2 +- itest/api/querier/client.go | 1 + itest/integration_test.go | 22 +++++++++++++--------- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/agent/build.gradle b/agent/build.gradle index 6b36b760..47af9d51 100644 --- a/agent/build.gradle +++ b/agent/build.gradle @@ -118,7 +118,10 @@ shadowJar { relocate("okio", "io.pyroscope.vendor.okio") relocate("okhttp3", "io.pyroscope.vendor.okhttp3") relocate("kotlin", "io.pyroscope.vendor.kotlin") - relocate("com", "io.pyroscope.vendor.com") + relocate("com", "io.pyroscope.vendor.com") { + // Keep the public OTel instrumentation scope name stable. + exclude "%regex[com\\.grafana\\.pyroscope/java]" + } dependencies { exclude "org/jetbrains/**" diff --git a/examples/docker-compose-base.yml b/examples/docker-compose-base.yml index 57ac783a..c7ff419f 100644 --- a/examples/docker-compose-base.yml +++ b/examples/docker-compose-base.yml @@ -1,6 +1,6 @@ services: pyroscope: - image: "grafana/pyroscope:1.18.0@sha256:e7edae4fd99dbb8695a1e03d7db96ab247630cf83842407908922b2f66aafc6a" + image: "grafana/pyroscope:2.1.0@sha256:73b23dbb99f154a0803c136abafdff825475f415dd4d4587538d014c672b5a55" ports: - "4040:4040" app: diff --git a/examples/docker-compose-expt.yml b/examples/docker-compose-expt.yml index ab02bfd5..1d61109b 100644 --- a/examples/docker-compose-expt.yml +++ b/examples/docker-compose-expt.yml @@ -1,6 +1,6 @@ services: pyroscope: - image: "grafana/pyroscope:1.18.0@sha256:e7edae4fd99dbb8695a1e03d7db96ab247630cf83842407908922b2f66aafc6a" + image: "grafana/pyroscope:2.1.0@sha256:73b23dbb99f154a0803c136abafdff825475f415dd4d4587538d014c672b5a55" ports: - "4040:4040" app: diff --git a/itest/api/querier/client.go b/itest/api/querier/client.go index 5a1e57bb..10a7140c 100644 --- a/itest/api/querier/client.go +++ b/itest/api/querier/client.go @@ -32,6 +32,7 @@ func (c *Client) SelectMergeStacktraces(ctx context.Context, req *SelectMergeSta return nil, fmt.Errorf("failed to create http request: %w", err) } httpRequest.Header.Set("Content-Type", "application/json") + httpRequest.Header.Set("Accept", "application/json;allow-utf8-labelnames=true") resp, err := c.HTTP.Do(httpRequest) if err != nil { diff --git a/itest/integration_test.go b/itest/integration_test.go index bc40a37d..72e6cc8a 100644 --- a/itest/integration_test.go +++ b/itest/integration_test.go @@ -16,14 +16,17 @@ import ( "pyroscope-java-itest/require" ) -const pyroscopeImage = "grafana/pyroscope:1.18.0@sha256:e7edae4fd99dbb8695a1e03d7db96ab247630cf83842407908922b2f66aafc6a" +const pyroscopeImage = "grafana/pyroscope:2.1.0@sha256:73b23dbb99f154a0803c136abafdff825475f415dd4d4587538d014c672b5a55" const needle = "run;Fib.lambda$appLogic$0;Fib.fib;Fib.fib;Fib.fib;Fib.fib;" +const otelScopeNameLabel = "otel.scope.name" +const expectedOtelScopeName = "com.grafana.pyroscope/java" func startPyroscope(t *testing.T, net *dockertest.Network) string { t.Helper() t.Log("starting pyroscope...") c := dockertest.StartContainer(t, dockertest.ContainerRequest{ Image: pyroscopeImage, + Cmd: []string{"-architecture.storage=v2", "-validation.disable-label-sanitization=true", "-segment-writer.min-ready-duration=0s", "-ingester.min-ready-duration=0s", "-metastore.min-ready-duration=0s"}, ExposedPorts: []string{"4040/tcp"}, Network: net.Name, NetworkAliases: []string{"pyroscope"}, @@ -68,7 +71,7 @@ func startApp(t *testing.T, net *dockertest.Network, image string) { }) } -func queryProfile(t *testing.T, pyroscopeURL string, serviceName string) (string, error) { +func queryProfile(t *testing.T, pyroscopeURL string, labelSelector string) (string, error) { t.Helper() qc := querier.NewClient(http.DefaultClient, pyroscopeURL) @@ -80,7 +83,7 @@ func queryProfile(t *testing.T, pyroscopeURL string, serviceName string) (string ProfileTypeID: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", Start: from.UnixMilli(), End: to.UnixMilli(), - LabelSelector: fmt.Sprintf(`{service_name="%s"}`, serviceName), + LabelSelector: labelSelector, MaxNodes: &maxNodes, Format: querier.ProfileFormat_PROFILE_FORMAT_TREE, }) @@ -128,20 +131,21 @@ func serviceNameFromDockerfile(dockerfile string, imageVersion string, javaVersi func testTarget(t *testing.T, pyroscopeURL string, serviceName string) { t.Helper() + labelSelector := fmt.Sprintf(`{service_name="%s","%s"="%s"}`, serviceName, otelScopeNameLabel, expectedOtelScopeName) var lastCollapsed string var lastErr error ok := require.Eventually(t, func() bool { - lastCollapsed, lastErr = queryProfile(t, pyroscopeURL, serviceName) + lastCollapsed, lastErr = queryProfile(t, pyroscopeURL, labelSelector) if lastErr != nil { - t.Logf("[%s] query error: %s", serviceName, lastErr) + t.Logf("[%s] query %s error: %s", serviceName, labelSelector, lastErr) return false } if lastCollapsed == "" { - t.Logf("[%s] empty profile", serviceName) + t.Logf("[%s] empty profile for %s", serviceName, labelSelector) return false } if !strings.Contains(lastCollapsed, needle) { - t.Logf("[%s] needle not found yet", serviceName) + t.Logf("[%s] needle not found yet for %s", serviceName, labelSelector) return false } return true @@ -149,9 +153,9 @@ func testTarget(t *testing.T, pyroscopeURL string, serviceName string) { if !ok { if lastErr != nil { - t.Logf("[%s] last error: %s", serviceName, lastErr) + t.Logf("[%s] last error for %s: %s", serviceName, labelSelector, lastErr) } - t.Logf("[%s] last collapsed profile:\n%s", serviceName, lastCollapsed) + t.Logf("[%s] last collapsed profile for %s:\n%s", serviceName, labelSelector, lastCollapsed) t.FailNow() } } From 0f396c60f457d1b44d2736b29f43519023dc43ed Mon Sep 17 00:00:00 2001 From: Tolyan Korniltsev Date: Tue, 7 Jul 2026 21:34:45 +0700 Subject: [PATCH 2/2] test: keep example pyroscope image unchanged Leave example compose files out of the scoped-label integration change. --- examples/docker-compose-base.yml | 2 +- examples/docker-compose-expt.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/docker-compose-base.yml b/examples/docker-compose-base.yml index c7ff419f..57ac783a 100644 --- a/examples/docker-compose-base.yml +++ b/examples/docker-compose-base.yml @@ -1,6 +1,6 @@ services: pyroscope: - image: "grafana/pyroscope:2.1.0@sha256:73b23dbb99f154a0803c136abafdff825475f415dd4d4587538d014c672b5a55" + image: "grafana/pyroscope:1.18.0@sha256:e7edae4fd99dbb8695a1e03d7db96ab247630cf83842407908922b2f66aafc6a" ports: - "4040:4040" app: diff --git a/examples/docker-compose-expt.yml b/examples/docker-compose-expt.yml index 1d61109b..ab02bfd5 100644 --- a/examples/docker-compose-expt.yml +++ b/examples/docker-compose-expt.yml @@ -1,6 +1,6 @@ services: pyroscope: - image: "grafana/pyroscope:2.1.0@sha256:73b23dbb99f154a0803c136abafdff825475f415dd4d4587538d014c672b5a55" + image: "grafana/pyroscope:1.18.0@sha256:e7edae4fd99dbb8695a1e03d7db96ab247630cf83842407908922b2f66aafc6a" ports: - "4040:4040" app: