"""Example 3: HTTP Request Logging
Demonstrates logging external API calls (like ComfyUI client) with structured logging.
Includes timing, status codes, and error handling using the project's logging utilities.
"""
import asyncio
import logging
import time
from src.utils import get_global_logger, setup_correlation_logging
# Initialize logging with correlation support
setup_correlation_logging()
# Get module logger
logger = get_global_logger("http_example")
class ComfyUIClient:
"""Example ComfyUI client with comprehensive HTTP logging."""
def __init__(self, base_url: str = "http://localhost:8188"):
self.logger = get_global_logger("comfyui_client")
self.base_url = base_url
async def queue_workflow(self, workflow: dict) -> str:
"""Queue workflow with detailed HTTP logging."""
url = f"{self.base_url}/prompt"
start_time = time.time()
node_count = len(workflow.get("nodes", []))
self.logger.debug(
f"Queuing workflow to ComfyUI: POST {url} (nodes={node_count})"
)
try:
# Simulate HTTP request
await asyncio.sleep(0.2)
# Simulate success response
prompt_id = "abc-123-def-456"
response_size = 150 # bytes
duration_ms = int((time.time() - start_time) * 1000)
self.logger.info(
f"Workflow queued successfully: {prompt_id} "
f"(POST {url}, 200 OK, {duration_ms}ms, {response_size} bytes)"
)
return prompt_id
except Exception as e:
duration_ms = int((time.time() - start_time) * 1000)
self.logger.error(
f"Failed to queue workflow: {type(e).__name__}: {str(e)} "
f"(POST {url}, {duration_ms}ms)",
exc_info=True
)
raise
async def get_history(self, prompt_id: str) -> dict:
"""Get workflow history with HTTP logging."""
url = f"{self.base_url}/history/{prompt_id}"
start_time = time.time()
self.logger.debug(
f"Fetching workflow history: job={prompt_id} (GET {url})"
)
try:
# Simulate HTTP request
await asyncio.sleep(0.1)
# Simulate response
history = {
"prompt_id": prompt_id,
"status": "completed",
"outputs": {"images": ["output.png"]},
}
response_size = 500 # bytes
duration_ms = int((time.time() - start_time) * 1000)
self.logger.info(
f"History fetched successfully: job={prompt_id} status={history['status']} "
f"(GET {url}, 200 OK, {duration_ms}ms, {response_size} bytes)"
)
return history
except Exception as e:
duration_ms = int((time.time() - start_time) * 1000)
self.logger.error(
f"Failed to fetch history: job={prompt_id} {type(e).__name__}: {str(e)} "
f"(GET {url}, {duration_ms}ms)",
exc_info=True
)
raise
async def download_asset(self, filename: str, subfolder: str = "") -> bytes:
"""Download asset with progress logging."""
encoded_filename = filename.replace(" ", "%20")
url = f"{self.base_url}/view?filename={encoded_filename}&subfolder={subfolder}&type=output"
start_time = time.time()
self.logger.debug(
f"Downloading asset: {filename} subfolder='{subfolder}' (GET {url})"
)
try:
# Simulate download
await asyncio.sleep(0.3)
# Simulate response
asset_bytes = b"fake_image_data" * 100
response_size = len(asset_bytes)
duration_ms = int((time.time() - start_time) * 1000)
size_kb = response_size / 1024
self.logger.info(
f"Asset downloaded successfully: {filename} "
f"(GET {url}, 200 OK, {duration_ms}ms, {size_kb:.1f}KB)"
)
return asset_bytes
except Exception as e:
duration_ms = int((time.time() - start_time) * 1000)
self.logger.error(
f"Failed to download asset: {filename} subfolder='{subfolder}' "
f"{type(e).__name__}: {str(e)} (GET {url}, {duration_ms}ms)",
exc_info=True
)
raise
async def cancel_job(self, prompt_id: str) -> bool:
"""Cancel job with HTTP logging."""
url = f"{self.base_url}/queue"
start_time = time.time()
self.logger.info(
f"Cancelling job: {prompt_id} (POST {url})"
)
try:
# Simulate cancel request
await asyncio.sleep(0.1)
duration_ms = int((time.time() - start_time) * 1000)
self.logger.info(
f"Job cancelled successfully: {prompt_id} "
f"(POST {url}, 200 OK, {duration_ms}ms)"
)
return True
except Exception as e:
duration_ms = int((time.time() - start_time) * 1000)
self.logger.error(
f"Failed to cancel job: {prompt_id} {type(e).__name__}: {str(e)} "
f"(POST {url}, {duration_ms}ms)",
exc_info=True
)
raise
async def main():
"""Run HTTP logging examples."""
# Set logging level for visibility
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
client = ComfyUIClient()
print("\n=== Example 1: Queue workflow ===")
workflow = {"nodes": [{"id": 1}, {"id": 2}]}
prompt_id = await client.queue_workflow(workflow)
print(f"Prompt ID: {prompt_id}\n")
print("\n=== Example 2: Get history ===")
history = await client.get_history(prompt_id)
print(f"History: {history['status']}\n")
print("\n=== Example 3: Download asset ===")
asset_data = await client.download_asset("output.png", subfolder="")
print(f"Downloaded {len(asset_data)} bytes\n")
print("\n=== Example 4: Cancel job ===")
cancelled = await client.cancel_job(prompt_id)
print(f"Cancelled: {cancelled}\n")
print("\n✅ All HTTP logging examples completed!")
if __name__ == "__main__":
asyncio.run(main())