Send Pyroscope profiles to sigiro
Send pprof profiles from the verified Pyroscope Rust SDK to sigiro over Pyroscope-compatible HTTP, then confirm the profile rows with SQL.
This guide shows you how to send application CPU profiles to sigiro. It uses the verified first-party Pyroscope Rust SDK and its pprof backend.
This is different from sending your agent’s own telemetry, which records agent sessions with OpenTelemetry. Use this guide when the process that you want to inspect produces pprof profiles.
Before you start
You need a sigiro server. Start one with sigiro serve, or use the Docker command
in the quickstart.
Pyroscope-compatible HTTP is available on the main sigiro port, 9999, and on
the OTLP HTTP port, 4318. Use the main port unless you deliberately separate
ingest traffic. Sigiro does not listen for profiles on port 4040.
A self-hosted server in Open auth mode needs no key. A server in Better Auth OAuth/JWT mode,
including hosted sigiro, requires Authorization: Bearer YOUR_TENANT_KEY.
Configure pyroscope-rs
Sigiro verifies the first-party pyroscope crate with its pprof backend. This
repository currently pins version 2.0.4:
[dependencies]
pyroscope = { version = "=2.0.4", features = ["backend-pprof-rs"] }
For self-hosted sigiro, use this target and no headers:
let endpoint = "http://localhost:9999";
let http_headers = None;
For hosted sigiro, use the HTTPS origin with no port and add the OAuth access token:
use std::collections::HashMap;
let endpoint = "https://api.sigiro.com";
let mut headers = HashMap::new();
headers.insert(
"Authorization".to_string(),
format!("Bearer {}", std::env::var("SIGIRO_ACCESS_TOKEN")?),
);
let http_headers = Some(headers);
Pass that target and optional header map to the SDK at application startup:
use pyroscope::backend::pprof::PprofConfig;
use pyroscope::backend::{BackendConfig, pprof_backend};
use pyroscope::pyroscope::PyroscopeAgentBuilder;
let backend = pprof_backend(PprofConfig::default(), BackendConfig::default());
let mut builder = PyroscopeAgentBuilder::new(
endpoint,
"checkout",
100,
"pyroscope-rs",
env!("CARGO_PKG_VERSION"),
backend,
);
if let Some(headers) = http_headers {
builder = builder.http_headers(headers);
}
let _profile_agent = builder.build()?.start()?;
Keep _profile_agent in scope for the life of the process. The SDK sends a batch
every 10 seconds. If the handle is dropped early, no later batch reaches sigiro.
Do not put the OAuth access token in source control. Set SIGIRO_ACCESS_TOKEN in the
environment that starts the process.
HTTP contract
The SDK can post to any of these equivalent paths:
//push.v1.PusherService/Push/ingest/ingest/pyroscope
The Rust SDK appends /push.v1.PusherService/Push to the target above. A target
that already includes that path can therefore send to the wrong URL without an
obvious error in sigiro. Give this SDK the origin only.
Sigiro accepts these request forms:
application/proto,binary/octet-stream, or no content type for a gzipped PyroscopePushRequestmultipart/form-datawith a file field named exactlyprofilefor either raw pprof bytes or aPushRequest
The name query parameter changes how sigiro decodes the body. If name is
present, sigiro treats the profile bytes as raw pprof and uses the text before
the first { as the service name. If name is absent, the body must decode as a
PushRequest, and each series must contain a non-empty service_name label.
Sending raw pprof without name, or a PushRequest without service_name,
returns 400 and stores nothing.
Sigiro accepts gzip and limits each request to 8 MiB after decompression by
default. A request over the HTTP body limit returns 413. A malformed or
unsupported profile returns 400, a missing or invalid Better Auth OAuth/JWT bearer token
returns 401, and a capacity gate returns 507. A 200 response means sigiro
accepted the batch.
Send pprof data only. Sigiro does not decode Java Flight Recorder data, so this guide does not claim Java or JFR compatibility. Other language SDK setups are omitted until they have a runnable end-to-end verification.
Confirm that it works
Start the application and let it do some work for at least 10 seconds. Then read the profile rows back from the main HTTP API:
curl -s -X POST http://localhost:9999/v1/query \
--data "SELECT service_name, profile_type, unit, count(*) AS samples
FROM sigiro_profiles
WHERE service_name = 'checkout'
AND timestamp > now() - INTERVAL '1 hour'
GROUP BY 1, 2, 3
ORDER BY samples DESC"
For hosted sigiro, change the origin and add
-H "Authorization: Bearer YOUR_TENANT_KEY". A non-empty result confirms the SDK
push, profile decoding, and HTTP readback. An empty result after one full SDK
interval usually means the profile handle was dropped, the target includes an
extra path, or the service name in the query does not match the SDK configuration.
Next
- Send telemetry to hosted sigiro — configure hosted authentication and the other telemetry signals
- About the tables — see which stored telemetry each table contains