use std::path::Path;
use std::path::PathBuf;
use axum::body::Body;
use http::Response;
use http::StatusCode;
use serde_json::json;
use crate::plugins::diagnostics::DiagnosticsResult;
use crate::plugins::diagnostics::archive_utils::ArchiveUtils;
use crate::plugins::diagnostics::response_builder::CacheControl;
use crate::plugins::diagnostics::response_builder::ResponseBuilder;
#[derive(Clone)]
pub(crate) struct MemoryService {
#[allow(dead_code)]
pub output_directory: PathBuf,
}
impl MemoryService {
pub(crate) fn new(output_directory: &Path) -> Self {
Self {
output_directory: output_directory.to_path_buf(),
}
}
fn json_response(
&self,
status: StatusCode,
data: serde_json::Value,
) -> DiagnosticsResult<Response<Body>> {
ResponseBuilder::json_response(status, &data, CacheControl::NoCache)
}
fn unsupported_platform_response(&self) -> DiagnosticsResult<Response<Body>> {
let response = json!({
"status": "not_supported",
"message": format!("Memory profiling not supported: requires Linux platform with jemalloc global allocator enabled (current: {})", std::env::consts::OS),
"platform": std::env::consts::OS
});
self.json_response(StatusCode::NOT_IMPLEMENTED, response)
}
pub(crate) async fn handle_status(&self) -> DiagnosticsResult<Response<Body>> {
let status = json!({
"profiling_active": false,
"status": "not_available",
"platform": std::env::consts::OS,
"heap_dumps_available": false,
"message": "Memory profiling requires Linux platform with jemalloc global allocator enabled"
});
self.json_response(StatusCode::OK, status)
}
pub(crate) async fn handle_start(&self) -> DiagnosticsResult<Response<Body>> {
self.unsupported_platform_response()
}
pub(crate) async fn handle_stop(&self) -> DiagnosticsResult<Response<Body>> {
self.unsupported_platform_response()
}
pub(crate) async fn handle_dump(&self) -> DiagnosticsResult<Response<Body>> {
tracing::info!("Memory dump requested");
let response = json!({
"status": "not_supported",
"message": format!("Heap dumps not supported: requires Linux platform with jemalloc global allocator enabled (current: {})", std::env::consts::OS),
"platform": std::env::consts::OS
});
self.json_response(StatusCode::NOT_IMPLEMENTED, response)
}
pub(crate) async fn add_to_archive<W: tokio::io::AsyncWrite + Unpin + Send + Sync>(
tar: &mut tokio_tar::Builder<W>,
_output_directory: &Path,
) -> DiagnosticsResult<()> {
tracing::warn!("Memory diagnostic archiving not supported on this platform");
let readme_content = format!(
"MEMORY PROFILING NOT AVAILABLE\n\
==============================\n\n\
Memory profiling with heap dumps is only available on Linux platforms\n\
with jemalloc global allocator enabled.\n\n\
Current platform: {}\n\n\
To enable memory profiling:\n\
1. Use a Linux platform (Ubuntu, CentOS, etc.)\n\
2. Ensure jemalloc is compiled with the 'global-allocator' feature\n\
3. Build the router with memory profiling support\n\n\
For more information, see the Apollo Router documentation.\n",
std::env::consts::OS
);
ArchiveUtils::add_text_file(tar, "memory/README.txt", &readme_content)
.await
.map_err(|e| format!("Failed to add README.txt: {}", e))?;
Ok(())
}
pub(crate) async fn handle_list_dumps(&self) -> DiagnosticsResult<Response<Body>> {
self.json_response(StatusCode::OK, serde_json::json!([]))
}
pub(crate) async fn handle_download_dump(
&self,
_filename: &str,
) -> DiagnosticsResult<Response<Body>> {
self.unsupported_platform_response()
}
pub(crate) async fn handle_delete_dump(
&self,
_filename: &str,
) -> DiagnosticsResult<Response<Body>> {
self.unsupported_platform_response()
}
pub(crate) async fn handle_clear_all_dumps(&self) -> DiagnosticsResult<Response<Body>> {
self.unsupported_platform_response()
}
}