use scim_server::{
RequestContext, ScimOperation, ScimServer, TenantContext, create_user_resource_handler,
providers::StandardResourceProvider, storage::InMemoryStorage,
};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug"))
.format_timestamp_secs()
.init();
log::info!("๐ Starting SCIM Server Logging Example");
log::info!("========================================");
let storage = InMemoryStorage::new();
let provider = StandardResourceProvider::new(storage);
let mut server = ScimServer::new(provider)?;
let user_schema = server
.get_schema_by_id("urn:ietf:params:scim:schemas:core:2.0:User")
.unwrap()
.clone();
let user_handler = create_user_resource_handler(user_schema);
server.register_resource_type(
"User",
user_handler,
vec![
ScimOperation::Create,
ScimOperation::Read,
ScimOperation::Update,
ScimOperation::Delete,
ScimOperation::List,
],
)?;
log::info!("โ
SCIM Server initialized with logging");
log::info!("๐ Demonstrating single-tenant operations...");
let single_context = RequestContext::with_generated_id();
let user_data = json!({
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "john.doe",
"displayName": "John Doe",
"emails": [{
"value": "john.doe@example.com",
"type": "work",
"primary": true
}],
"active": true
});
log::info!("Creating user with structured logging...");
let created_user = server
.create_resource("User", user_data.clone(), &single_context)
.await?;
let user_id = created_user.get_id().unwrap();
log::info!("User created with ID: {}", user_id);
log::info!("Retrieving user...");
let retrieved_user = server
.get_resource("User", &user_id, &single_context)
.await?;
if retrieved_user.is_some() {
log::info!("โ
User retrieved successfully");
}
log::info!("Updating user...");
let update_data = json!({
"id": user_id,
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "john.doe",
"displayName": "John Doe (Updated)",
"active": false
});
let updated_user = server
.update_resource("User", &user_id, update_data, &single_context)
.await?;
log::info!("User updated: active = {}", updated_user.is_active());
log::info!("Listing all users...");
let users = server.list_resources("User", &single_context).await?;
log::info!("Found {} users", users.len());
log::info!("\n๐ Demonstrating multi-tenant operations...");
let tenant_context = TenantContext::new("tenant-1".to_string(), "client-1".to_string());
let multi_context = RequestContext::with_tenant_generated_id(tenant_context);
log::info!("Creating user in tenant context...");
let tenant_user = server
.create_resource("User", user_data, &multi_context)
.await?;
let tenant_user_id = tenant_user.get_id().unwrap();
log::info!("Tenant user created with ID: {}", tenant_user_id);
let tenant_users = server.list_resources("User", &multi_context).await?;
log::info!("Found {} users in tenant", tenant_users.len());
log::info!("\n๐ Demonstrating error scenarios...");
log::info!("Attempting to retrieve non-existent user...");
let missing_user = server
.get_resource("User", "non-existent-id", &single_context)
.await?;
if missing_user.is_none() {
log::warn!("User not found (expected)");
}
log::info!("Attempting to delete non-existent user...");
match server
.delete_resource("User", "non-existent-id", &single_context)
.await
{
Ok(_) => log::info!("Delete succeeded (unexpected)"),
Err(e) => log::warn!("Delete failed as expected: {}", e),
}
log::info!("\n๐งน Cleaning up...");
server
.delete_resource("User", &user_id, &single_context)
.await?;
log::info!("Deleted single-tenant user");
server
.delete_resource("User", &tenant_user_id, &multi_context)
.await?;
log::info!("Deleted multi-tenant user");
log::info!("\nโจ **LOGGING FEATURES DEMONSTRATED**");
log::info!("==================================");
log::info!("โ Structured logging with request IDs");
log::info!("โ Multi-tenant context in logs");
log::info!("โ Different log levels (TRACE, DEBUG, INFO, WARN)");
log::info!("โ Operation-specific logging");
log::info!("โ Error condition logging");
log::info!("โ Resource lifecycle tracking");
log::info!("\n๐ **LOGGING CONFIGURATION OPTIONS**");
log::info!("===================================");
log::info!("Environment Variables:");
log::info!(" RUST_LOG=debug # Enable debug logging");
log::info!(" RUST_LOG=scim_server=trace # Trace SCIM operations");
log::info!(" RUST_LOG=scim_server::providers=debug # Debug provider operations");
log::info!("");
log::info!("Programmatic Configuration:");
log::info!(" env_logger::Builder::from_env(...)");
log::info!(" tracing_subscriber::fmt::init()");
log::info!(" Custom filtering by module/level");
log::info!("\n๐ฏ **PRODUCTION RECOMMENDATIONS**");
log::info!("=================================");
log::info!("โ Use structured logging (JSON format)");
log::info!("โ Set appropriate log levels (INFO+ for production)");
log::info!("โ Include request tracing for debugging");
log::info!("โ Monitor error rates and patterns");
log::info!("โ Use log aggregation systems (ELK, Splunk, etc.)");
Ok(())
}