Files
qiming/qiming-rcoder/crates/agent_runner/src/profiler.rs
2026-06-01 13:54:52 +08:00

112 lines
3.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Pyroscope Profiler 集成模块
//!
//! 提供连续性能分析功能,包括:
//! - CPU Profiling
//! - Memory Profiling (Heap/Allocs)
//! - Stack trace sampling
use anyhow::{Context, Result};
use pyroscope::PyroscopeAgent;
use pyroscope_pprofrs::{PprofConfig, pprof_backend};
use tracing::{debug, info};
/// Profiler 配置
#[derive(Debug, Clone)]
pub struct ProfilerConfig {
/// Pyroscope Server 地址
pub server_url: String,
/// 应用名称(支持标签格式)
pub application_name: String,
/// 采样频率Hz
pub sample_rate: u32,
/// 是否启用内存 profiling
pub enable_memory: bool,
/// 是否启用 CPU profiling
pub enable_cpu: bool,
}
impl Default for ProfilerConfig {
fn default() -> Self {
Self {
server_url: "http://pyroscope:4040".to_string(),
application_name: "agent_runner{env=dev}".to_string(),
sample_rate: 100,
enable_memory: true,
enable_cpu: true,
}
}
}
impl ProfilerConfig {
/// 从环境变量加载配置
pub fn from_env() -> Self {
let mut config = Self::default();
if let Ok(url) = std::env::var("PYROSCOPE_URL") {
config.server_url = url;
}
if let Ok(name) = std::env::var("PYROSCOPE_APP_NAME") {
config.application_name = name;
}
if let Ok(project_id) = std::env::var("PROJECT_ID") {
config.application_name = format!("agent_runner{{project_id={}}}", project_id);
}
config
}
}
/// Profiler Guard
///
/// 当 dropped 时自动停止 profiler
pub struct ProfilerGuard {
_agent: Option<pyroscope::PyroscopeAgent<pyroscope::pyroscope::PyroscopeAgentRunning>>,
}
/// 初始化并启动 Pyroscope Profiler
///
/// # Errors
///
/// 如果 profiler 初始化失败,返回错误
pub fn init_pyroscope_profiler(config: ProfilerConfig) -> Result<ProfilerGuard> {
if !config.enable_cpu && !config.enable_memory {
debug!("Pyroscope profiler disabled, skipping initialization");
return Ok(ProfilerGuard { _agent: None });
}
info!(
"Initializing Pyroscope profiler: {}",
config.application_name
);
info!(" Server URL: {}", config.server_url);
info!(" Sample rate: {} Hz", config.sample_rate);
info!(" CPU profiling: {}", config.enable_cpu);
info!(" Memory profiling: {}", config.enable_memory);
// 使用正确的 API: builder() -> backend() -> build()
let agent = PyroscopeAgent::builder(config.server_url, config.application_name)
.backend(pprof_backend(
PprofConfig::new().sample_rate(config.sample_rate),
))
.build()
.context("Failed to build Pyroscope agent")?;
// 启动 profiling返回 PyroscopeAgent<PyroscopeAgentRunning>
let agent_running = agent
.start()
.context("Failed to start Pyroscope profiler")?;
info!("Pyroscope profiler started successfully");
Ok(ProfilerGuard {
_agent: Some(agent_running),
})
}
/// 便捷函数:使用默认配置初始化 profiler
pub fn init_pyroscope_profiler_default() -> Result<ProfilerGuard> {
init_pyroscope_profiler(ProfilerConfig::from_env())
}