Crates.io | pulseengine-mcp-logging |
lib.rs | pulseengine-mcp-logging |
version | 0.10.0 |
created_at | 2025-06-28 08:18:34.568732+00 |
updated_at | 2025-08-15 04:19:17.917872+00 |
description | Structured logging framework for MCP servers - PulseEngine MCP Framework |
homepage | https://github.com/pulseengine/mcp |
repository | https://github.com/pulseengine/mcp |
max_upload_size | |
id | 1729634 |
size | 349,523 |
Structured logging framework for MCP servers
This crate provides structured logging specifically designed for MCP servers, with automatic credential sanitization, request correlation, and security-focused log management.
Structured Logging:
Security Features:
MCP-Specific Features:
This logging system is actively used in the Loxone MCP Server where it:
[dependencies]
pulseengine-mcp-logging = "0.2.0"
tracing = "0.1"
serde_json = "1.0"
use pulseengine_mcp_logging::{LoggingConfig, init_logging};
// Configure structured logging
let config = LoggingConfig {
level: "info".to_string(),
format: mcp_logging::LogFormat::Json,
enable_correlation_ids: true,
enable_sanitization: true,
output_file: Some("/var/log/mcp-server.log".to_string()),
};
// Initialize the logging system
init_logging(config)?;
use tracing::{info, warn, error};
use pulseengine_mcp_logging::log_tool_execution;
// Standard structured logging
info!(
tool = "get_weather",
location = "San Francisco",
duration_ms = 150,
"Tool executed successfully"
);
// MCP-specific logging
log_tool_execution(
"control_device",
&serde_json::json!({"device": "living_room_light", "action": "on"}),
Ok("Device controlled successfully"),
150, // duration in ms
);
use pulseengine_mcp_logging::{CorrelationId, with_correlation_id};
// Generate correlation ID for a request
let correlation_id = CorrelationId::new();
// All logs within this scope will include the correlation ID
with_correlation_id(correlation_id, async {
info!("Processing MCP request");
// Your request handling logic
handle_tool_call().await?;
info!("Request completed successfully");
}).await;
Solid foundation with good security practices. The logging system handles the most important concerns well and integrates cleanly with the rest of the framework.
What works well:
Areas for improvement:
use pulseengine_mcp_logging::sanitize_for_logging;
// Automatically removes sensitive data
let safe_params = sanitize_for_logging(&serde_json::json!({
"username": "admin",
"password": "secret123", // Will be redacted
"api_key": "abc123", // Will be redacted
"device": "living_room_light"
}));
info!(params = ?safe_params, "Tool called");
// Logs: {"params": {"username": "admin", "password": "[REDACTED]", "api_key": "[REDACTED]", "device": "living_room_light"}}
use pulseengine_mcp_logging::{SanitizationConfig, SanitizationRule};
let sanitization_config = SanitizationConfig {
rules: vec![
SanitizationRule::field_name("password"),
SanitizationRule::field_name("token"),
SanitizationRule::field_name("secret"),
SanitizationRule::pattern(r"(?i)api[_-]?key"),
SanitizationRule::custom("device_credential", |value| {
// Custom scrubbing logic
"[DEVICE_CREDENTIAL]".to_string()
}),
],
redaction_text: "[SANITIZED]".to_string(),
};
use pulseengine_mcp_logging::audit_log;
// Log security-relevant events
audit_log!(
event = "authentication_attempt",
client_ip = "192.168.1.100",
api_key_id = "key_123",
success = true,
"Client authenticated successfully"
);
audit_log!(
event = "privileged_tool_access",
tool = "control_all_devices",
user_role = "admin",
client_ip = "192.168.1.100",
"Admin executed system-wide control"
);
use pulseengine_mcp_logging::{log_tool_start, log_tool_success, log_tool_error};
// Start tool execution
let execution_id = log_tool_start("get_device_status", ¶ms);
// Tool execution logic...
match execute_tool().await {
Ok(result) => {
log_tool_success(execution_id, &result, duration_ms);
}
Err(error) => {
log_tool_error(execution_id, &error, duration_ms);
}
}
use pulseengine_mcp_logging::{log_request, log_response};
// Log incoming requests
log_request(&mcp_request, correlation_id, client_info);
// Log outgoing responses
log_response(&mcp_response, correlation_id, response_time_ms);
use pulseengine_mcp_logging::log_transport_event;
// Log transport-specific events
log_transport_event!(
transport = "http",
event = "connection_established",
client_ip = "192.168.1.100",
user_agent = "MCP-Inspector/1.0",
"New HTTP connection"
);
log_transport_event!(
transport = "websocket",
event = "message_received",
message_type = "tool_call",
size_bytes = 256,
"WebSocket message processed"
);
use pulseengine_mcp_logging::LoggingConfig;
let config = LoggingConfig {
level: "info".to_string(),
module_filters: vec![
("mcp_server".to_string(), "debug".to_string()),
("hyper".to_string(), "warn".to_string()),
("tokio".to_string(), "error".to_string()),
],
// ... other config
};
let config = LoggingConfig {
outputs: vec![
LogOutput::Stdout,
LogOutput::File {
path: "/var/log/mcp-server.log".to_string(),
rotate_size_mb: 100,
max_files: 10,
},
LogOutput::Syslog {
facility: "daemon".to_string(),
identifier: "mcp-server".to_string(),
},
],
// ... other config
};
// For production - structured JSON
let prod_config = LoggingConfig {
format: LogFormat::Json,
include_timestamps: true,
include_correlation_ids: true,
// ...
};
// For development - human-readable
let dev_config = LoggingConfig {
format: LogFormat::Pretty,
enable_colors: true,
// ...
};
use mcp_server::ServerConfig;
use pulseengine_mcp_logging::LoggingConfig;
let logging_config = LoggingConfig {
level: "info".to_string(),
format: LogFormat::Json,
enable_sanitization: true,
// ... other config
};
// Initialize logging before starting server
mcp_logging::init_logging(logging_config)?;
let server = McpServer::new(backend, config).await?;
server.run().await?;
use mcp_auth::AuthManager;
use pulseengine_mcp_logging::audit_log;
// Log authentication events
let auth_result = auth_manager.validate_request(&request).await;
match auth_result {
Ok(auth_info) => {
audit_log!(
event = "auth_success",
key_id = auth_info.key_id,
role = ?auth_info.role,
client_ip = ?request.client_ip,
"Authentication successful"
);
}
Err(e) => {
audit_log!(
event = "auth_failure",
error = %e,
client_ip = ?request.client_ip,
"Authentication failed"
);
}
}
// Log home automation commands
info!(
tool = "control_rolladen",
room = "living_room",
action = "down",
device_count = 3,
duration_ms = 1200,
"Rolladen control completed"
);
// Log device status queries
debug!(
tool = "get_climate_status",
room_count = 6,
sensor_count = 12,
cache_hit = true,
duration_ms = 45,
"Climate status retrieved"
);
// Log security events
audit_log!(
event = "device_control",
tool = "control_all_lights",
action = "off",
affected_devices = 15,
client_ip = "192.168.1.50",
"System-wide light control executed"
);
Logging is fundamental to operational visibility. Most valuable contributions:
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Repository: https://github.com/avrabe/mcp-loxone