pyroscope
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGrafana Pyroscope - Continuous Profiling
Grafana Pyroscope - 持续剖析
Continuous profiling aggregation system — understand resource usage down to source code line numbers.
持续剖析聚合系统——深入到源代码行级别了解资源使用情况。
Instrumentation Methods
插桩方式
Three ways to send profiles to Pyroscope:
- Grafana Alloy (preferred): eBPF auto-instrumentation, no code changes
- SDK: Push profiles directly from your application
- SDK → Alloy: SDK sends to Alloy's , Alloy forwards to Pyroscope
pyroscope.receive_http
向Pyroscope发送剖析数据的三种方式:
- Grafana Alloy(推荐):eBPF自动插桩,无需修改代码
- SDK:从应用直接推送剖析数据
- SDK → Alloy:SDK将数据发送至Alloy的,再由Alloy转发至Pyroscope
pyroscope.receive_http
SDK Examples
SDK示例
Python
Python
bash
pip install pyroscope-iopython
import pyroscope, os
pyroscope.configure(
application_name = "my.python.app",
server_address = "http://pyroscope:4040",
sample_rate = 100,
oncpu = True,
tags = {"region": os.getenv("REGION"), "env": "prod"},
)bash
pip install pyroscope-iopython
import pyroscope, os
pyroscope.configure(
application_name = "my.python.app",
server_address = "http://pyroscope:4040",
sample_rate = 100,
oncpu = True,
tags = {"region": os.getenv("REGION"), "env": "prod"},
)Dynamic labels for specific code sections
针对特定代码段的动态标签
with pyroscope.tag_wrapper({"controller": "slow_controller"}):
slow_code()
**Grafana Cloud:**
```python
pyroscope.configure(
application_name = "my.python.app",
server_address = "https://profiles-prod-xxx.grafana.net",
basic_auth_username = "123456",
basic_auth_password = os.getenv("GRAFANA_API_KEY"),
)with pyroscope.tag_wrapper({"controller": "slow_controller"}):
slow_code()
**Grafana Cloud配置:**
```python
pyroscope.configure(
application_name = "my.python.app",
server_address = "https://profiles-prod-xxx.grafana.net",
basic_auth_username = "123456",
basic_auth_password = os.getenv("GRAFANA_API_KEY"),
)Java
Java
xml
<!-- Maven -->
<dependency>
<groupId>io.pyroscope</groupId>
<artifactId>agent</artifactId>
<version>2.1.2</version>
</dependency>java
// Method 1: Application code
PyroscopeAgent.start(
new Config.Builder()
.setApplicationName("my-java-app")
.setProfilingEvent(EventType.ITIMER)
.setFormat(Format.JFR) // required for multiple events
.setServerAddress("http://pyroscope:4040")
.build()
);
// Dynamic labels
Pyroscope.LabelsWrapper.run(new LabelsSet("controller", "slow_controller"), () -> {
slowCode();
});bash
undefinedxml
<!-- Maven -->
<dependency>
<groupId>io.pyroscope</groupId>
<artifactId>agent</artifactId>
<version>2.1.2</version>
</dependency>java
// 方式1:在应用代码中配置
PyroscopeAgent.start(
new Config.Builder()
.setApplicationName("my-java-app")
.setProfilingEvent(EventType.ITIMER)
.setFormat(Format.JFR) // 多事件场景下必填
.setServerAddress("http://pyroscope:4040")
.build()
);
// 动态标签
Pyroscope.LabelsWrapper.run(new LabelsSet("controller", "slow_controller"), () -> {
slowCode();
});bash
undefinedMethod 2: Java Agent (no code changes)
方式2:Java Agent(无需修改代码)
export PYROSCOPE_APPLICATION_NAME=my.java.app
export PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040
java -javaagent:pyroscope.jar -jar app.jar
**Key Java config:**
| Env Var | Description | Default |
|---------|-------------|---------|
| `PYROSCOPE_FORMAT` | `jfr` for multiple events | `collapsed` |
| `PYROSCOPE_PROFILER_EVENT` | `itimer`, `cpu`, `wall` | `itimer` |
| `PYROSCOPE_PROFILER_ALLOC` | Allocation bytes threshold; `0` = all | disabled |
| `PYROSCOPE_PROFILER_LOCK` | Lock contention threshold (ns) | disabled |
| `PYROSCOPE_UPLOAD_INTERVAL` | Upload frequency | `10s` |export PYROSCOPE_APPLICATION_NAME=my.java.app
export PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040
java -javaagent:pyroscope.jar -jar app.jar
**Java关键配置:**
| 环境变量 | 描述 | 默认值 |
|---------|-------------|---------|
| `PYROSCOPE_FORMAT` | 多事件场景使用`jfr` | `collapsed` |
| `PYROSCOPE_PROFILER_EVENT` | 可选值:`itimer`, `cpu`, `wall` | `itimer` |
| `PYROSCOPE_PROFILER_ALLOC` | 内存分配字节阈值;`0`表示采集所有 | 禁用 |
| `PYROSCOPE_PROFILER_LOCK` | 锁竞争阈值(纳秒) | 禁用 |
| `PYROSCOPE_UPLOAD_INTERVAL` | 上传频率 | `10s` |Node.js
Node.js
bash
npm install @pyroscope/nodejsjavascript
const Pyroscope = require('@pyroscope/nodejs');
Pyroscope.init({
serverAddress: 'http://pyroscope:4040',
appName: 'my-node-service',
tags: { region: process.env.REGION },
basicAuthUser: process.env.PYROSCOPE_USER,
basicAuthPassword: process.env.PYROSCOPE_PASSWORD,
flushIntervalMs: 60000,
});
Pyroscope.start();
// Dynamic labels
Pyroscope.wrapWithLabels({ vehicle: 'bike' }, () => slowCode());bash
npm install @pyroscope/nodejsjavascript
const Pyroscope = require('@pyroscope/nodejs');
Pyroscope.init({
serverAddress: 'http://pyroscope:4040',
appName: 'my-node-service',
tags: { region: process.env.REGION },
basicAuthUser: process.env.PYROSCOPE_USER,
basicAuthPassword: process.env.PYROSCOPE_PASSWORD,
flushIntervalMs: 60000,
});
Pyroscope.start();
// 动态标签
Pyroscope.wrapWithLabels({ vehicle: 'bike' }, () => slowCode());Ruby
Ruby
bash
bundle add pyroscoperuby
require 'pyroscope'
Pyroscope.configure do |config|
config.application_name = "my.ruby.app"
config.server_address = "http://pyroscope:4040"
config.tags = { hostname: ENV["HOSTNAME"] }
endbash
bundle add pyroscoperuby
require 'pyroscope'
Pyroscope.configure do |config|
config.application_name = "my.ruby.app"
config.server_address = "http://pyroscope:4040"
config.tags = { hostname: ENV["HOSTNAME"] }
end
// 动态标签
Pyroscope.tag_wrapper({ controller: "slow_controller" }) do
slow_code
endDynamic tags
.NET
Pyroscope.tag_wrapper({ controller: "slow_controller" }) do
slow_code
end
undefinedbash
undefined.NET
系统要求:Linux amd64、.NET 6+
bash
undefinedexport PYROSCOPE_APPLICATION_NAME=my.dotnet.app
export PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040
export PYROSCOPE_PROFILING_ENABLED=1
export CORECLR_ENABLE_PROFILING=1
export CORECLR_PROFILER={BD1A650D-AC5D-4896-B64F-D6FA25D6B26A}
export CORECLR_PROFILER_PATH=/dotnet/Pyroscope.Profiler.Native.so
export LD_PRELOAD=/dotnet/Pyroscope.Linux.ApiWrapper.x64.so
```csharp
// 动态标签
var labels = Pyroscope.LabelSet.Empty.BuildUpon()
.Add("controller", "slow")
.Build();
Pyroscope.LabelsWrapper.Do(labels, () => SlowCode());System requirements: Linux amd64, .NET 6+
Rust
export PYROSCOPE_APPLICATION_NAME=my.dotnet.app
export PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040
export PYROSCOPE_PROFILING_ENABLED=1
export CORECLR_ENABLE_PROFILING=1
export CORECLR_PROFILER={BD1A650D-AC5D-4896-B64F-D6FA25D6B26A}
export CORECLR_PROFILER_PATH=/dotnet/Pyroscope.Profiler.Native.so
export LD_PRELOAD=/dotnet/Pyroscope.Linux.ApiWrapper.x64.so
```csharp
// Dynamic labels
var labels = Pyroscope.LabelSet.Empty.BuildUpon()
.Add("controller", "slow")
.Build();
Pyroscope.LabelsWrapper.Do(labels, () => SlowCode());bash
cargo add pyroscope pyroscope_pprofrsrust
let pprof_config = PprofConfig::new().sample_rate(100);
let agent = PyroscopeAgent::builder("http://pyroscope:4040", "my-rust-app")
.backend(pprof_backend(pprof_config))
.tags([("env", "prod"), ("region", "us-east")].to_vec())
.basic_auth(user, password)
.build()?;
let agent_running = agent.start().unwrap();
// ... 应用运行中 ...
let agent_ready = agent_running.stop().unwrap();
agent_ready.shutdown();Rust
通过Alloy实现eBPF自动插桩
bash
cargo add pyroscope pyroscope_pprofrsrust
let pprof_config = PprofConfig::new().sample_rate(100);
let agent = PyroscopeAgent::builder("http://pyroscope:4040", "my-rust-app")
.backend(pprof_backend(pprof_config))
.tags([("env", "prod"), ("region", "us-east")].to_vec())
.basic_auth(user, password)
.build()?;
let agent_running = agent.start().unwrap();
// ... app runs ...
let agent_ready = agent_running.stop().unwrap();
agent_ready.shutdown();无需修改代码。支持:C/C++、Go、Rust、Java(Hotspot JVM)、Python、Ruby、Node.js、PHP、.NET、V8。
alloy
discovery.kubernetes "all_pods" {
role = "pod"
selectors {
field = "spec.nodeName=" + sys.env("HOSTNAME")
}
}
discovery.relabel "local_pods" {
targets = discovery.kubernetes.all_pods.targets
rule {
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
}
pyroscope.ebpf "local_pods" {
forward_to = [pyroscope.write.cloud.receiver]
targets = discovery.relabel.local_pods.output
sample_rate = 97 // 每秒采样次数
collect_interval = "15s"
}
pyroscope.write "cloud" {
endpoint {
url = "https://profiles-prod-xxx.grafana.net"
basic_auth {
username = sys.env("PYROSCOPE_USER")
password = sys.env("GRAFANA_API_KEY")
}
}
}使用eBPF的要求:
- 以root身份运行Alloy,且处于主机PID命名空间
- Linux 5.8+版本并启用BTF(或RHEL 4.18+)
eBPF Auto-Instrumentation via Alloy
ProfileQL查询
No code changes needed. Supports: C/C++, Go, Rust, Java (Hotspot JVM), Python, Ruby, Node.js, PHP, .NET, V8.
alloy
discovery.kubernetes "all_pods" {
role = "pod"
selectors {
field = "spec.nodeName=" + sys.env("HOSTNAME")
}
}
discovery.relabel "local_pods" {
targets = discovery.kubernetes.all_pods.targets
rule {
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
}
pyroscope.ebpf "local_pods" {
forward_to = [pyroscope.write.cloud.receiver]
targets = discovery.relabel.local_pods.output
sample_rate = 97 // samples per second
collect_interval = "15s"
}
pyroscope.write "cloud" {
endpoint {
url = "https://profiles-prod-xxx.grafana.net"
basic_auth {
username = sys.env("PYROSCOPE_USER")
password = sys.env("GRAFANA_API_KEY")
}
}
}Requirements for eBPF:
- Run Alloy as root, in host PID namespace
- Linux 5.8+ with BTF enabled (or RHEL 4.18+)
undefinedProfileQL Queries
某个服务的所有CPU剖析数据
undefined{service_name="myapp", profile_type="process_cpu:cpu:nanoseconds:cpu:nanoseconds"}
All CPU profiles for a service
按标签过滤
{service_name="myapp", profile_type="process_cpu:cpu:nanoseconds:cpu:nanoseconds"}
{service_name="myapp", env="prod"}
Filter by label
剖析类型格式:<类型>:<值类型>:<值单位>:<跨度名称>:<跨度单位>
{service_name="myapp", env="prod"}
**常见剖析类型:**
- `process_cpu:cpu:nanoseconds:cpu:nanoseconds` - CPU耗时
- `memory:inuse_space:bytes:space:bytes` - 堆内存使用量
- `memory:alloc_space:bytes:space:bytes` - 堆内存分配量
- `goroutine:goroutine:count::` - Goroutine数量(Go)
- `mutex:contentions:count::` - 锁竞争次数Profile types format: <type>:<value_type>:<value_unit>:<span_name>:<span_unit>
各语言支持的剖析类型
**Common profile types:**
- `process_cpu:cpu:nanoseconds:cpu:nanoseconds` - CPU time
- `memory:inuse_space:bytes:space:bytes` - Heap in use
- `memory:alloc_space:bytes:space:bytes` - Heap allocations
- `goroutine:goroutine:count::` - Goroutine count (Go)
- `mutex:contentions:count::` - Mutex contentions| 语言 | CPU剖析 | 内存剖析 | Goroutine剖析 | 内存分配剖析 |
|---|---|---|---|---|
| Go | ✓ | ✓ | ✓ | ✓ |
| Java | ✓ | ✓ | ✓ | ✓ |
| Python | ✓ | - | - | - |
| Node.js | ✓ | ✓ | - | ✓ |
| Ruby | ✓ | ✓ | - | - |
| .NET | ✓ | ✓ | - | ✓ |
| Rust | ✓ | - | - | - |
| eBPF | ✓ | - | - | - |
Profile Types by Language
标签规则
| Language | CPU | Memory | Goroutines | Allocations |
|---|---|---|---|---|
| Go | ✓ | ✓ | ✓ | ✓ |
| Java | ✓ | ✓ | ✓ | ✓ |
| Python | ✓ | - | - | - |
| Node.js | ✓ | ✓ | - | ✓ |
| Ruby | ✓ | ✓ | - | - |
| .NET | ✓ | ✓ | - | ✓ |
| Rust | ✓ | - | - | - |
| eBPF | ✓ | - | - | - |
合法标签格式: — 不允许使用句号。
[a-zA-Z_][a-zA-Z0-9_]*Tag Rules
参考文档
Valid tags: — periods NOT allowed.
[a-zA-Z_][a-zA-Z0-9_]*- SDK参考文档
- ProfileQL文档
- 服务器配置文档
References
—
- SDKs Reference
- ProfileQL
- Server Config
—