1. Les SDK #
Le mode push, le plus riche.
Go #
go get github.com/grafana/pyroscope-goimport "github.com/grafana/pyroscope-go"
func main() {
runtime.SetMutexProfileFraction(5) // active les profils de verrous
runtime.SetBlockProfileRate(5)
pyroscope.Start(pyroscope.Config{
ApplicationName: "checkout",
ServerAddress: "http://pyroscope:4040",
Tags: map[string]string{"env": "prod", "region": os.Getenv("REGION")},
ProfileTypes: []pyroscope.ProfileType{
pyroscope.ProfileCPU,
pyroscope.ProfileAllocObjects, pyroscope.ProfileAllocSpace,
pyroscope.ProfileInuseObjects, pyroscope.ProfileInuseSpace,
pyroscope.ProfileGoroutines,
pyroscope.ProfileMutexCount, pyroscope.ProfileMutexDuration,
pyroscope.ProfileBlockCount, pyroscope.ProfileBlockDuration,
},
})
// ...
}Java #
curl -LO https://github.com/grafana/pyroscope-java/releases/latest/download/pyroscope.jar
PYROSCOPE_APPLICATION_NAME=orders \
PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 \
PYROSCOPE_PROFILER_EVENT=itimer \
PYROSCOPE_LABELS="env=prod" \
java -javaagent:pyroscope.jar -jar orders.jarL'agent Java s'appuie sur async-profiler : CPU, allocations, verrous et wall clock.
Python et Node.js #
# pip install pyroscope-io
import pyroscope
pyroscope.configure(
application_name="billing",
server_address="http://pyroscope:4040",
tags={"env": "prod"},
)// npm install @pyroscope/nodejs
const Pyroscope = require('@pyroscope/nodejs');
Pyroscope.init({ serverAddress: 'http://pyroscope:4040', appName: 'front-api', tags: { env: 'prod' } });
Pyroscope.start();2. Des labels pour découper les profils #
Le vrai pouvoir du profiling continu.
Labels dynamiques #
Les labels permettent de filtrer un flame graph par endpoint, client ou type de tâche. Ils s'ajoutent autour d'un bloc de code :
pyroscope.TagWrapper(ctx, pyroscope.Labels("endpoint", "/checkout"), func(c context.Context) {
processCheckout(c)
})with pyroscope.tag_wrapper({"endpoint": "/invoice"}):
generate_invoice()Erreur Courante : Comme pour les métriques, la cardinalité compte : un label par identifiant de requête ou d'utilisateur crée une série de profils par valeur et fait exploser le stockage.
3. Alloy : pull pprof et eBPF #
Sans toucher (ou presque) au code.
Collecter les points pprof #
Une application Go qui importe net/http/pprof expose déjà ses profils sur /debug/pprof/. Alloy les collecte régulièrement :
pyroscope.write "default" {
endpoint { url = "http://pyroscope:4040" }
}
pyroscope.scrape "go_apps" {
targets = [
{"__address__" = "checkout:6060", "service_name" = "checkout"},
]
forward_to = [pyroscope.write.default.receiver]
profiling_config {
profile.process_cpu { enabled = true }
profile.memory { enabled = true }
profile.goroutine { enabled = true }
profile.mutex { enabled = true }
profile.block { enabled = true }
}
}Profiler tout l'hôte avec eBPF #
Le composant pyroscope.ebpf échantillonne le CPU de tous les processus via le noyau Linux : aucune modification de code, tous les langages compilés (Go, Rust, C/C++) et plusieurs langages interprétés (Python...) sont pris en charge.
discovery.docker "local" { host = "unix:///var/run/docker.sock" }
discovery.relabel "containers" {
targets = discovery.docker.local.targets
rule {
source_labels = ["__meta_docker_container_name"]
regex = "/(.*)"
target_label = "service_name"
}
}
pyroscope.ebpf "host" {
targets = discovery.relabel.containers.output
forward_to = [pyroscope.write.default.receiver]
}Erreur Courante : eBPF exige un noyau Linux récent (4.9+, idéalement 5.x) et un Alloy privilégié (privileged: true,pid: host). Il ne fournit que des profils CPU : pour la mémoire et les verrous, utilisez un SDK.
Choisir #
| Critère | SDK | Alloy pprof | Alloy eBPF |
|---|---|---|---|
| Modification du code | Oui | Minime (pprof) | Non |
| Types de profils | Tous | Tous (Go) | CPU |
| Labels métier | Oui | Non | Non |
| Liens traces → profils | Oui | Non | Non |
