Skip to content

Commit 1f18dc2

Browse files
pyroscope.java: add integration tests
fix package name Revert "pyroscope.java: Fix java log level parameter (#4440)" This reverts commit 4909877. move the helper to pyroscope package
1 parent 97f9a65 commit 1f18dc2

File tree

11 files changed

+200
-9
lines changed

11 files changed

+200
-9
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ internal/web/ui/build/
77
packaging/windows/LICENSE
88
packaging/windows/agent-windows-amd64.exe
99
cmd/grafana-agent/Dockerfile
10+
alloy

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ node_modules
3333
# file of the pair will detect a dirty work tree and detect the wrong tag name.
3434
.tag-only
3535
.image-tag
36+
alloy

internal/cmd/integration-tests/docker-compose.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ services:
122122
networks:
123123
- integration-tests
124124

125+
pyroscope:
126+
image: grafana/pyroscope
127+
container_name: pyroscope
128+
ports:
129+
- "4040:4040"
130+
networks:
131+
- integration-tests
132+
125133
networks:
126134
integration-tests:
127135
driver: bridge
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
discovery.docker "d" {
2+
host = "unix:///host-docker.sock"
3+
}
4+
5+
discovery.process "p" {
6+
join = discovery.docker.d.targets
7+
}
8+
9+
discovery.relabel "l" {
10+
targets = discovery.process.p.targets
11+
12+
rule {
13+
source_labels = ["__meta_process_exe"]
14+
regex = "^(.*/java)$"
15+
action = "keep"
16+
}
17+
rule {
18+
source_labels = ["__meta_docker_container_name"]
19+
regex = ".*kafka.*"
20+
action = "keep"
21+
}
22+
rule {
23+
source_labels = ["__meta_docker_container_name"]
24+
target_label = "service_name"
25+
replacement = "integration-test/java$1"
26+
}
27+
}
28+
29+
pyroscope.java "j" {
30+
targets = discovery.relabel.l.output
31+
forward_to = [pyroscope.write.w.receiver]
32+
}
33+
34+
pyroscope.write "w" {
35+
endpoint {
36+
url = "http://pyroscope:4040"
37+
}
38+
}
39+
40+
logging {
41+
level = "debug"
42+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package main
2+
3+
import (
4+
"strings"
5+
"testing"
6+
"time"
7+
8+
"github.com/grafana/alloy/internal/cmd/integration-tests/common"
9+
pyroutil "github.com/grafana/alloy/internal/component/pyroscope/util/test"
10+
querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestPyroscopeJavaKafka(t *testing.T) {
15+
16+
require.Eventually(t, func() bool {
17+
req := &querierv1.SelectMergeProfileRequest{
18+
ProfileTypeID: `process_cpu:cpu:nanoseconds:cpu:nanoseconds`,
19+
LabelSelector: `{service_name="integration-test/java/kafka"}`,
20+
Start: time.Now().Add(-time.Hour).UnixMilli(),
21+
End: time.Now().UnixMilli(),
22+
}
23+
res, err := pyroutil.Query("http://localhost:4040", req)
24+
if err != nil {
25+
return false
26+
}
27+
ss := res.String()
28+
if !strings.Contains(ss, `kafka/server/KafkaRequestHandler.run`) {
29+
return false
30+
}
31+
if !strings.Contains(ss, `libjvm.so.JavaThread::thread_main_inner`) {
32+
return false
33+
}
34+
return true
35+
}, common.DefaultTimeout, common.DefaultRetryInterval)
36+
37+
require.Eventually(t, func() bool {
38+
req := &querierv1.SelectMergeProfileRequest{
39+
ProfileTypeID: `memory:alloc_in_new_tlab_bytes:bytes:space:bytes`,
40+
LabelSelector: `{service_name="integration-test/java/kafka"}`,
41+
Start: time.Now().Add(-time.Hour).UnixMilli(),
42+
End: time.Now().UnixMilli(),
43+
}
44+
res, err := pyroutil.Query("http://localhost:4040", req)
45+
if err != nil {
46+
return false
47+
}
48+
ss := res.String()
49+
if !strings.Contains(ss, `kafka/server/KafkaRequestHandler.run`) {
50+
return false
51+
}
52+
if strings.Contains(ss, `libjvm.so.JavaThread::thread_main_inner`) {
53+
return false
54+
}
55+
return true
56+
}, common.DefaultTimeout, common.DefaultRetryInterval)
57+
}

internal/cmd/integration-tests/utils.go

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"io"
78
"log"
@@ -14,6 +15,7 @@ import (
1415
"time"
1516

1617
"github.com/docker/docker/api/types/container"
18+
"github.com/docker/docker/api/types/mount"
1719
"github.com/docker/go-connections/nat"
1820
"github.com/testcontainers/testcontainers-go"
1921
"github.com/testcontainers/testcontainers-go/wait"
@@ -38,6 +40,45 @@ type fileInfo struct {
3840
relPath string
3941
}
4042

43+
func getDockerSocketPath() (string, error) {
44+
contextCmd := exec.Command("docker", "context", "show")
45+
contextOutput, err := contextCmd.Output()
46+
if err != nil {
47+
return "", fmt.Errorf("failed to get docker context: %w", err)
48+
}
49+
contextName := strings.TrimSpace(string(contextOutput))
50+
51+
inspectCmd := exec.Command("docker", "context", "inspect", contextName)
52+
inspectOutput, err := inspectCmd.Output()
53+
if err != nil {
54+
return "", fmt.Errorf("failed to inspect docker context %s: %w", contextName, err)
55+
}
56+
57+
var contexts []struct {
58+
Endpoints struct {
59+
Docker struct {
60+
Host string `json:"Host"`
61+
} `json:"docker"`
62+
} `json:"Endpoints"`
63+
}
64+
65+
if err := json.Unmarshal(inspectOutput, &contexts); err != nil {
66+
return "", fmt.Errorf("failed to parse docker context inspect output: %w", err)
67+
}
68+
69+
if len(contexts) == 0 {
70+
return "", fmt.Errorf("no docker contexts found")
71+
}
72+
73+
host := contexts[0].Endpoints.Docker.Host
74+
if !strings.HasPrefix(host, "unix://") {
75+
return "", fmt.Errorf("docker host is not a unix socket: %s", host)
76+
}
77+
78+
socketPath := strings.TrimPrefix(host, "unix://")
79+
return socketPath, nil
80+
}
81+
4182
func executeCommand(command string, args []string, taskDescription string) {
4283
fmt.Printf("%s...\n", taskDescription)
4384

@@ -89,6 +130,9 @@ func prepareContainerFiles(absTestDir string) ([]testcontainers.ContainerFile, [
89130

90131
// Create a container request based on the test directory
91132
func createContainerRequest(dirName string, port int, networkName string, containerFiles []testcontainers.ContainerFile) testcontainers.ContainerRequest {
133+
pyroscope := strings.Contains(dirName, "pyroscope")
134+
beyla := dirName == "beyla"
135+
92136
natPort, err := nat.NewPort("tcp", strconv.Itoa(port))
93137
if err != nil {
94138
panic(fmt.Sprintf("failed to build natPort: %v", err))
@@ -108,10 +152,19 @@ func createContainerRequest(dirName string, port int, networkName string, contai
108152
},
109153
Privileged: true,
110154
}
111-
112-
// Apply special configurations for specific tests
113-
if dirName == "beyla" {
155+
dockerSocketPath, err := getDockerSocketPath()
156+
if err != nil {
157+
panic(fmt.Sprintf("failed to get docker socket path: %v", err))
158+
}
159+
if beyla || pyroscope {
114160
req.HostConfigModifier = func(hostConfig *container.HostConfig) {
161+
if pyroscope {
162+
hostConfig.Mounts = append(hostConfig.Mounts, mount.Mount{
163+
Type: mount.TypeBind,
164+
Source: dockerSocketPath,
165+
Target: "/host-docker.sock",
166+
})
167+
}
115168
hostConfig.Privileged = true
116169
hostConfig.CapAdd = []string{"SYS_ADMIN", "SYS_PTRACE", "SYS_RESOURCE"}
117170
hostConfig.SecurityOpt = []string{"apparmor:unconfined"}

internal/component/pyroscope/java/loop.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,10 @@ func (p *profilingLoop) start() error {
242242
argv = append(argv, "--lock", cfg.Lock)
243243
}
244244
if cfg.LogLevel != "" {
245-
argv = append(argv, "-L", cfg.LogLevel)
245+
argv = append(argv, "--loglevel", cfg.LogLevel)
246+
}
247+
if cfg.Quiet {
248+
argv = append(argv, "--quiet")
246249
}
247250

248251
argv = append(argv,

internal/component/pyroscope/receive_http/receive_http.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/go-kit/log"
1515
"github.com/gorilla/mux"
1616
pyroutil "github.com/grafana/alloy/internal/component/pyroscope/util"
17+
"github.com/grafana/alloy/internal/component/pyroscope/util/tracelog"
1718
"github.com/prometheus/client_golang/prometheus"
1819
"github.com/prometheus/prometheus/model/labels"
1920
"go.opentelemetry.io/otel/trace"
@@ -170,7 +171,7 @@ func (c *Component) Push(ctx context.Context, req *connect.Request[pushv1.PushRe
170171

171172
ctx, sp := c.tracer.Start(ctx, "/push.v1.PusherService/Push")
172173
defer sp.End()
173-
l := pyroutil.TraceLog(c.logger, sp)
174+
l := tracelog.TraceLog(c.logger, sp)
174175

175176
var wg sync.WaitGroup
176177
var errs error
@@ -224,7 +225,7 @@ func (c *Component) handleIngest(w http.ResponseWriter, r *http.Request) {
224225
ctx, sp := c.tracer.Start(ctx, "/ingest")
225226
defer sp.End()
226227

227-
l := pyroutil.TraceLog(c.logger, sp)
228+
l := tracelog.TraceLog(c.logger, sp)
228229

229230
// Parse labels early
230231
var lbls labels.Labels
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package test
2+
3+
import (
4+
"context"
5+
"net/http"
6+
7+
"connectrpc.com/connect"
8+
"github.com/google/pprof/profile"
9+
querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1"
10+
"github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect"
11+
)
12+
13+
func Query(url string, q *querierv1.SelectMergeProfileRequest) (*profile.Profile, error) {
14+
client := querierv1connect.NewQuerierServiceClient(http.DefaultClient, url)
15+
res, err := client.SelectMergeProfile(context.Background(), connect.NewRequest(q))
16+
if err != nil {
17+
return nil, err
18+
}
19+
bs, err := res.Msg.MarshalVT()
20+
if err != nil {
21+
return nil, err
22+
}
23+
return profile.ParseData(bs)
24+
}

internal/component/pyroscope/util/log.go renamed to internal/component/pyroscope/util/tracelog/log.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package util
1+
package tracelog
22

33
import (
44
"github.com/go-kit/log"

0 commit comments

Comments
 (0)