Grafana Pyroscope is a continuous profiling platform that helps you find performance bottlenecks in your applications. It supports multiple languages, integrates natively with Grafana, and offers both push and pull modes for profile collection.
Installation
Linux/Ubuntu
# Download Pyroscope binary
curl -fL https://github.com/grafana/pyroscope/releases/latest/download/pyroscope_Linux_x86_64.tar.gz | tar xz
sudo mv pyroscope /usr/local/bin/
# Verify
pyroscope --version
# Docker
docker run -d --name pyroscope \
-p 4040:4040 \
grafana/pyroscope:latest
Helm (Kubernetes)
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm install pyroscope grafana/pyroscope -n pyroscope --create-namespace
Server Configuration
# pyroscope-config.yaml
# Start with: pyroscope -config.file=pyroscope-config.yaml
storage:
backend: filesystem
filesystem:
dir: /var/lib/pyroscope/data
server:
http_listen_port: 4040
limits:
max_query_lookback: 720h
max_query_length: 6h
scrape_configs:
- job_name: "my-go-service"
scrape_interval: "15s"
static_configs:
- targets: ["my-service:6060"]
profiling_config:
pprof_config:
process_cpu:
enabled: true
memory:
enabled: true
# Start Pyroscope server
pyroscope -config.file=pyroscope-config.yaml
# Start with default settings
pyroscope
# Access the web UI
# http://localhost:4040
Push Mode — Go SDK
// Install: go get github.com/grafana/pyroscope-go
// Add to your Go application main():
// import "github.com/grafana/pyroscope-go"
//
// pyroscope.Start(pyroscope.Config{
// ApplicationName: "my-go-service",
// ServerAddress: "http://pyroscope:4040",
// ProfileTypes: []pyroscope.ProfileType{
// pyroscope.ProfileCPU,
// pyroscope.ProfileAllocObjects,
// pyroscope.ProfileAllocSpace,
// pyroscope.ProfileInuseObjects,
// pyroscope.ProfileInuseSpace,
// pyroscope.ProfileGoroutines,
// pyroscope.ProfileMutexCount,
// pyroscope.ProfileMutexDuration,
// pyroscope.ProfileBlockCount,
// pyroscope.ProfileBlockDuration,
// },
// })
Push Mode — Python SDK
# Install the Python SDK
pip install pyroscope-io
# Add to your Python application
import pyroscope
pyroscope.configure(
application_name="my-python-service",
server_address="http://pyroscope:4040",
tags={
"region": "us-east-1",
"env": "production",
},
)
# Use tags for dynamic labeling
with pyroscope.tag_wrapper({"endpoint": "/api/users"}):
handle_users_request()
Push Mode — Java SDK
# Add to JVM arguments
# Download the Java agent JAR from GitHub releases
java -javaagent:pyroscope.jar \
-Dpyroscope.application.name=my-java-service \
-Dpyroscope.server.address=http://pyroscope:4040 \
-Dpyroscope.format=jfr \
-jar my-app.jar
Push Mode — Ruby SDK
# Install the Ruby gem
gem install pyroscope
# Add to your Ruby application
require 'pyroscope'
Pyroscope.configure do |config|
config.application_name = "my-ruby-service"
config.server_address = "http://pyroscope:4040"
config.tags = {
"region" => "us-east-1",
"env" => "production",
}
end
Push Mode — Node.js SDK
# Install the Node.js package
npm install @pyroscope/nodejs
// Add to your Node.js application
const Pyroscope = require('@pyroscope/nodejs');
Pyroscope.init({
serverAddress: 'http://pyroscope:4040',
appName: 'my-node-service',
tags: {
region: 'us-east-1',
env: 'production',
},
});
Pyroscope.start();
Push Mode — .NET SDK
# Install the NuGet package
dotnet add package Pyroscope
// Add to your .NET application Program.cs
// Pyroscope.Profiler.Instance.SetTag("region", "us-east-1");
// Use the PYROSCOPE_APPLICATION_NAME and PYROSCOPE_SERVER_ADDRESS
// environment variables to configure
Pull Mode — Scraping pprof Endpoints
# Configure Pyroscope to scrape pprof endpoints (in pyroscope-config.yaml)
scrape_configs:
- job_name: "go-services"
scrape_interval: "15s"
static_configs:
- targets: ["app1:6060", "app2:6060"]
profiling_config:
pprof_config:
process_cpu:
enabled: true
path: "/debug/pprof/profile"
delta: true
memory:
enabled: true
path: "/debug/pprof/heap"
delta: true
goroutine:
enabled: true
path: "/debug/pprof/goroutine"
block:
enabled: true
path: "/debug/pprof/block"
delta: true
mutex:
enabled: true
path: "/debug/pprof/mutex"
delta: true
- job_name: "kubernetes-pods"
scrape_interval: "15s"
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_pyroscope_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_pyroscope_io_port]
action: replace
target_label: __address__
regex: (.+)
replacement: ${1}
Grafana Integration
# Add Pyroscope as a data source in Grafana
# 1. Navigate to Configuration > Data Sources > Add data source
# 2. Search for "Pyroscope" (or "Grafana Pyroscope")
# 3. Set URL to http://pyroscope:4040
# 4. Click "Save & Test"
# Grafana Explore:
# 1. Select the Pyroscope data source
# 2. Choose profile type (cpu, memory, goroutine, etc.)
# 3. Filter by labels (service_name, env, region)
# 4. View flame graph, table, or both
Querying Profiles
# Query profiles via HTTP API
# List available label names
curl -s http://localhost:4040/pyroscope/api/v1/labels | python3 -m json.tool
# List label values
curl -s "http://localhost:4040/pyroscope/api/v1/label-values?label=service_name" | python3 -m json.tool
# Render a profile (returns pprof format)
curl -s "http://localhost:4040/pyroscope/api/v1/profiles/render?query=process_cpu:cpu:nanoseconds:cpu:nanoseconds{service_name=\"my-service\"}&from=now-1h&until=now" -o profile.pb.gz
# Analyze with go tool pprof
go tool pprof -http=:8080 profile.pb.gz
Diff View (Comparing Profiles)
# In the Pyroscope web UI:
# 1. Select "Comparison" mode in the top toolbar
# 2. Set baseline time range on the left
# 3. Set comparison time range on the right
# 4. View differential flame graph
# Red = increased time, Green = decreased time
# Via API — compare two time ranges
curl -s "http://localhost:4040/pyroscope/api/v1/profiles/render-diff?leftQuery=process_cpu:cpu:nanoseconds{service_name=\"my-service\"}&leftFrom=now-2h&leftUntil=now-1h&rightQuery=process_cpu:cpu:nanoseconds{service_name=\"my-service\"}&rightFrom=now-1h&rightUntil=now"
Profile Types
| Profile Type | Description |
|---|
process_cpu | CPU time consumed by the process |
memory | Heap memory allocations |
goroutine | Active goroutine count (Go) |
mutex | Mutex contention (Go) |
block | Blocking operations (Go) |
wall | Wall-clock time |
alloc_objects | Number of allocations |
alloc_space | Bytes allocated |
inuse_objects | Live objects in memory |
inuse_space | Live bytes in memory |
Quick Reference
| Component | Default Port | Purpose |
|---|
| Pyroscope Server | 4040 | Storage, query, web UI |
| Grafana | 3000 | Visualization and dashboards |
| pprof endpoints | 6060 | Go application profiling |
| Feature | Description |
|---|
| Push mode | SDKs send profiles to Pyroscope |
| Pull mode | Pyroscope scrapes pprof endpoints |
| Flame graphs | Interactive CPU/memory visualization |
| Diff view | Compare profiles across time periods |
| Tag filtering | Filter by service, env, region, etc. |
| Grafana native | Built-in Pyroscope data source |