use claude_code_sdk::{
query, AssistantMessage, ClaudeCodeOptions, ContentBlock, Message, PermissionMode,
ResultMessage, TextBlock,
};
use tokio_stream::StreamExt;
use tracing::{info, debug, error};
async fn basic_example() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Basic Example ===");
info!("Starting basic example");
let mut stream = query("What is 2 + 2?", None).await?;
let mut message_count = 0;
while let Some(message) = stream.next().await {
message_count += 1;
debug!(message_count, "Received message from stream");
match message {
Message::Assistant(AssistantMessage { content }) => {
info!("Received assistant message with {} content blocks", content.len());
for block in content {
if let ContentBlock::Text(TextBlock { text }) = block {
println!("Claude: {}", text);
}
}
}
Message::System(msg) => {
debug!(subtype = %msg.subtype, "Received system message");
}
Message::Result(msg) => {
info!(
duration_ms = msg.duration_ms,
num_turns = msg.num_turns,
is_error = msg.is_error,
"Query completed"
);
if let Some(cost) = msg.total_cost_usd {
info!(cost_usd = cost, "Query cost");
}
}
_ => {
debug!("Received other message type");
}
}
}
info!(total_messages = message_count, "Basic example completed");
println!();
Ok(())
}
async fn with_options_example() -> Result<(), Box<dyn std::error::Error>> {
println!("=== With Options Example ===");
info!("Starting options example with custom configuration");
let options = ClaudeCodeOptions {
system_prompt: Some("You are a helpful assistant that explains things simply.".to_string()),
max_turns: Some(1),
..Default::default()
};
debug!(?options, "Using custom options");
let mut stream = query("Explain what Rust is in one sentence.", Some(options)).await?;
while let Some(message) = stream.next().await {
match message {
Message::Assistant(AssistantMessage { content }) => {
info!("Assistant response received");
for block in content {
if let ContentBlock::Text(TextBlock { text }) = block {
debug!(response_length = text.len(), "Response text length");
println!("Claude: {}", text);
}
}
}
Message::Result(msg) => {
if msg.is_error {
error!("Query failed: {:?}", msg.result);
} else {
info!("Query succeeded");
}
}
_ => {
debug!("Received non-assistant message");
}
}
}
info!("Options example completed");
println!();
Ok(())
}
async fn with_tools_example() -> Result<(), Box<dyn std::error::Error>> {
println!("=== With Tools Example ===");
info!("Starting tools example with file operations");
let options = ClaudeCodeOptions {
allowed_tools: vec!["Read".to_string(), "Write".to_string()],
system_prompt: Some("You are a helpful file assistant.".to_string()),
permission_mode: Some(PermissionMode::AcceptEdits),
..Default::default()
};
info!(
allowed_tools = ?options.allowed_tools,
permission_mode = ?options.permission_mode,
"Configured tools and permissions"
);
let mut stream = query(
"Create a file called hello.txt with 'Hello, World!' in it",
Some(options),
)
.await?;
let mut tool_use_count = 0;
while let Some(message) = stream.next().await {
match message {
Message::Assistant(AssistantMessage { content }) => {
debug!("Processing assistant message with {} content blocks", content.len());
for block in content {
match block {
ContentBlock::Text(TextBlock { text }) => {
println!("Claude: {}", text);
}
ContentBlock::ToolUse(tool_use_block) => {
tool_use_count += 1;
info!(
tool_name = %tool_use_block.name,
tool_count = tool_use_count,
"Tool used by assistant"
);
debug!(tool_input = ?tool_use_block.input, "Tool input details");
println!("Tool used: {} with input: {:?}", tool_use_block.name, tool_use_block.input);
}
_ => {
debug!("Other content block type received");
}
}
}
}
Message::System(msg) => {
debug!(system_subtype = %msg.subtype, "System message received");
}
Message::Result(ResultMessage {
total_cost_usd: Some(cost),
duration_ms,
num_turns,
is_error,
..
}) => {
if is_error {
error!(duration_ms, num_turns, "Query failed");
} else {
info!(
cost_usd = cost,
duration_ms,
num_turns,
tools_used = tool_use_count,
"Query completed successfully"
);
if cost > 0.0 {
println!("\nCost: ${:.4}", cost);
}
}
}
_ => {
debug!("Other message type received");
}
}
}
info!(total_tools_used = tool_use_count, "Tools example completed");
println!();
Ok(())
}
fn setup_custom_logging() {
println!("=== Custom Logging Setup Demo ===");
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, fmt, EnvFilter};
let env_filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("claude_code_sdk=info"));
tracing_subscriber::registry()
.with(env_filter)
.with(
fmt::layer()
.with_target(true)
.with_thread_ids(true)
.with_file(true)
.with_line_number(true)
)
.init();
info!("Custom logging initialized");
println!("Custom logging setup complete!");
println!();
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
claude_code_sdk::init_tracing();
info!("Starting Claude Code SDK examples with logging");
println!("Claude Code SDK - Logging Examples");
println!("==================================");
println!("💡 Tip: Set RUST_LOG=claude_code_sdk=debug for detailed logs");
println!("💡 Tip: Set RUST_LOG=claude_code_sdk=trace for all logs");
println!();
match basic_example().await {
Ok(()) => info!("Basic example completed successfully"),
Err(e) => error!(error = %e, "Basic example failed"),
}
match with_options_example().await {
Ok(()) => info!("Options example completed successfully"),
Err(e) => error!(error = %e, "Options example failed"),
}
match with_tools_example().await {
Ok(()) => info!("Tools example completed successfully"),
Err(e) => error!(error = %e, "Tools example failed"),
}
info!("All examples completed");
println!("Examples completed! Check the logs above for detailed information.");
println!("\nLogging features demonstrated:");
println!("✓ Structured logging with fields");
println!("✓ Different log levels (info, debug, warn, error)");
println!("✓ Message counting and metrics");
println!("✓ Tool usage tracking");
println!("✓ Performance monitoring (duration, cost)");
println!("✓ Error handling and reporting");
Ok(())
}