/

Exception Handling

Exception Handling

Proper exception logging is critical for diagnosing production issues. The ByteHide Logs SDK captures exception details automatically and provides context to understand what went wrong.

Basic Exception Logging

Use the exception parameter to log exceptions with full details:

Python
from bytehide_logs import Log

try:
    file = open("/path/to/file.txt")
except FileNotFoundError as e:
    Log.error("Configuration file not found", exception=e)

The SDK automatically captures:

  • Exception type (FileNotFoundError)
  • Error message
  • Complete stack trace
  • Exception chain (nested exceptions)

Exception Logging with Context

Combine exception information with contextual data:

Python
try:
    database.connect(host=db_host, port=db_port)
except ConnectionError as e:
    Log.error(
        "Database connection failed",
        exception=e,
        context={
            "host": db_host,
            "port": db_port,
            "timeout_seconds": 30,
            "environment": "production"
        }
    )

Context is essential for understanding:

  • What operation was being performed
  • Which resources were involved
  • Environmental factors that may have contributed

Try-Except Pattern with Logging

Handle exceptions while providing diagnostic information:

Python
def fetch_user_data(user_id):
    """Fetch user from API with error handling and logging."""
    try:
        response = api.get(f"/users/{user_id}")
        user_data = response.json()
        Log.info(f"User data retrieved for user {user_id}")
        return user_data
        
    except requests.Timeout as e:
        Log.warning(
            f"API timeout retrieving user {user_id}",
            exception=e,
            context={"user_id": user_id, "timeout": "30s"}
        )
        return None
        
    except requests.HTTPError as e:
        if e.response.status_code == 404:
            Log.warning(f"User not found: {user_id}", exception=e)
        else:
            Log.error(
                f"API error retrieving user {user_id}",
                exception=e,
                context={"status_code": e.response.status_code}
            )
        return None

Exception Chaining

Log exceptions that cause other exceptions:

Python
try:
    try:
        result = risky_operation()
    except OperationError as original_error:
        raise ProcessingException("Failed to process data") from original_error
except ProcessingException as e:
    Log.error(
        "Processing failed with chained exceptions",
        exception=e,
        context={"operation": "data_processing"}
    )

The SDK preserves the full exception chain for debugging.

Selective Error Handling

Log different exception types with appropriate levels:

Python
def process_payment(payment_data):
    """Process payment with appropriate error logging levels."""
    try:
        return payment_processor.charge(payment_data)
        
    except CardDeclinedError as e:
        # User error - warning level
        Log.warning(
            "Payment card declined",
            exception=e,
            context={
                "card_last_four": payment_data.get("card_last_four"),
                "amount": payment_data.get("amount")
            }
        )
        
    except InvalidCardError as e:
        # Validation error - warning level
        Log.warning(
            "Invalid card details provided",
            exception=e,
            context={"field": e.field}
        )
        
    except PaymentGatewayError as e:
        # System error - error level
        Log.error(
            "Payment gateway error",
            exception=e,
            context={
                "gateway": "stripe",
                "retry_available": True
            }
        )

Traceback Information

Exception tracebacks are automatically included:

Python
import traceback

try:
    deeply_nested_function()
except Exception as e:
    # Full traceback is captured automatically
    Log.error("Unexpected error in nested function call", exception=e)
    # No need to manually capture traceback

The SDK captures:

  • Function names and line numbers
  • Local variables (where applicable)
  • File paths and code context
  • Complete call stack

Best Practices

Always include context when logging exceptions:

Python
# Good - includes context
try:
    user = fetch_user(user_id)
except Exception as e:
    Log.error("User fetch failed", exception=e, context={"user_id": user_id})

# Avoid - no context
try:
    user = fetch_user(user_id)
except Exception as e:
    Log.error("User fetch failed", exception=e)

Use appropriate log levels based on severity:

Python
# Recoverable errors - use warning or info
Log.warning("Retrying failed request", exception=retry_error)

# Unexpected system errors - use error
Log.error("Unhandled database error", exception=db_error)

# Critical failures - use critical
Log.critical("Payment system offline", exception=critical_error)

Log early and specifically rather than catching broadly:

Python
# Good - specific exception with details
try:
    database.execute(query)
except DatabaseError as e:
    Log.error("Query execution failed", exception=e, context={"query_id": query.id})
    raise

# Avoid - catching everything vaguely
try:
    entire_request_handler()
except Exception as e:
    Log.error("Something went wrong", exception=e)

Next Steps

Previous
Tags