mirror of
https://github.com/grafana/alloy.git
synced 2025-11-05 13:28:02 +08:00
* pyroscope.java: decouple archive extraction from the profiler, remove Profiler(use Distribution).
* playground
* fix args
* cleanup
* todo
* review fix
* review fixes
* pyroscope.java: add integration tests (#4454)
* pyroscope.java: add integration tests
fix package name
Revert "pyroscope.java: Fix java log level parameter (#4440)"
This reverts commit 4909877427.
move the helper to pyroscope package
* second integration test
* revert compose tests
* revert unneeded changes
* fix buildtag
* fix buildtag
* improve start time for pyroscope container
* skip integration test if it's not pyoroscope job
* update makefile
* pyroscope.java: Fix java log level parameter (#4440)
* pyroscope.java: Fix java log level parameter
The version bundled of the async profiler has no loglevel parameter:
```
ts=2025-09-16T08:16:50.898924708Z level=error component_path=/profiling.feature component_id=pyroscope.java.java_pods pid=1184752 err="failed to start: asprof failed to run: asprof failed to run /tmp/alloy-asprof-ae0261b1093f2bc4df44a87300fef98dcdebccb5/bin/asprof: exit status 1 Unrecognized option: --loglevel\n"
```
* Quiet is not a valid argument for the async-profiler cli
It can only be used for attaching using agent
* remove comments
* fix
---------
Co-authored-by: Christian Simon <simon@swine.de>
---------
Co-authored-by: Christian Simon <simon@swine.de>
122 lines
2.7 KiB
Go
122 lines
2.7 KiB
Go
//go:build (linux || darwin) && (amd64 || arm64)
|
|
|
|
package asprof
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha1"
|
|
_ "embed"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
var fsMutex sync.Mutex
|
|
|
|
type Distribution struct {
|
|
extractedDir string
|
|
}
|
|
|
|
func NewExtractedDistribution(extractedDir string) (Distribution, error) {
|
|
d := Distribution{extractedDir: extractedDir}
|
|
if _, err := os.Stat(d.LauncherPath()); err != nil {
|
|
return d, fmt.Errorf("asprof launcher not found: %w", err)
|
|
}
|
|
if _, err := os.Stat(d.LibPath()); err != nil {
|
|
return d, fmt.Errorf("asprof lib not found: %w", err)
|
|
}
|
|
return d, nil
|
|
}
|
|
|
|
func (d Distribution) LauncherPath() string {
|
|
return filepath.Join(d.extractedDir, "bin/asprof")
|
|
}
|
|
|
|
type Archive struct {
|
|
data []byte
|
|
format int
|
|
}
|
|
|
|
func (a *Archive) sha1() string {
|
|
sum := sha1.Sum(a.data)
|
|
return hex.EncodeToString(sum[:])
|
|
}
|
|
|
|
func (a *Archive) DistName() string {
|
|
return fmt.Sprintf("alloy-asprof-%s", a.sha1())
|
|
}
|
|
|
|
const (
|
|
ArchiveFormatTarGz = iota
|
|
ArchiveFormatZip
|
|
)
|
|
|
|
func (d Distribution) Execute(argv []string) (string, string, error) {
|
|
stdout := bytes.NewBuffer(nil)
|
|
stderr := bytes.NewBuffer(nil)
|
|
|
|
exe := d.LauncherPath()
|
|
cmd := exec.Command(exe, argv...)
|
|
|
|
cmd.Stdout = stdout
|
|
cmd.Stderr = stderr
|
|
err := cmd.Start()
|
|
if err != nil {
|
|
return stdout.String(), stderr.String(), fmt.Errorf("asprof failed to start %s: %w", exe, err)
|
|
}
|
|
err = cmd.Wait()
|
|
if err != nil {
|
|
return stdout.String(), stderr.String(), fmt.Errorf("asprof failed to run %s: %w", exe, err)
|
|
}
|
|
return stdout.String(), stderr.String(), nil
|
|
}
|
|
|
|
func ExtractDistribution(a Archive, tmpDir, distName string) (Distribution, error) {
|
|
d := Distribution{}
|
|
fsMutex.Lock()
|
|
defer fsMutex.Unlock()
|
|
|
|
var launcher, lib []byte
|
|
err := readArchive(a.data, a.format, func(name string, fi fs.FileInfo, data []byte) error {
|
|
if strings.Contains(name, "asprof") {
|
|
launcher = data
|
|
}
|
|
if strings.Contains(name, "libasyncProfiler") {
|
|
lib = data
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return d, err
|
|
}
|
|
if launcher == nil || lib == nil {
|
|
return d, fmt.Errorf("failed to find libasyncProfiler in archive %s", distName)
|
|
}
|
|
|
|
fileMap := map[string][]byte{}
|
|
fileMap[filepath.Join(distName, d.LauncherPath())] = launcher
|
|
fileMap[filepath.Join(distName, d.LibPath())] = lib
|
|
tmpDirFile, err := os.Open(tmpDir)
|
|
if err != nil {
|
|
return d, fmt.Errorf("failed to open tmp dir %s: %w", tmpDir, err)
|
|
}
|
|
defer tmpDirFile.Close()
|
|
|
|
if err = checkTempDirPermissions(tmpDirFile); err != nil {
|
|
return d, err
|
|
}
|
|
|
|
for path, data := range fileMap {
|
|
if err = writeFile(tmpDirFile, path, data, true); err != nil {
|
|
return d, err
|
|
}
|
|
}
|
|
d.extractedDir = filepath.Join(tmpDir, distName)
|
|
return d, nil
|
|
}
|