In production systems, silent failures or vague error messages can cause major downstream issues. Instead of just printing errors, we can log them for diagnostics and raise custom exceptions that provide clear, context-aware feedback to higher-level code — e.g., an API response handler.
import math
import logging
# Configure logging to file
logging.basicConfig(filename='errors.log', level=logging.ERROR,
format='%(asctime)s - %(levelname)s - %(message)s')
# Define a custom exception
class InvalidLogInputError(Exception):
def __init__(self, message):
super().__init__(message)
def safe_log(x):
if not isinstance(x, (int, float)):
message = f"Invalid type: expected int or float, got {type(x).__name__}"
logging.error(message)
raise TypeError(message)
if x <= 0:
message = f"Invalid value: logarithm undefined for {x}"
logging.error(message)
raise InvalidLogInputError(message)
try:
return math.log(x)
except ValueError as ve:
logging.error(f"Unexpected math domain error: {ve}")
raise InvalidLogInputError("Unexpected math domain error.") from ve
# --- Usage Example ---
# Valid input
try:
print("log(10) =", safe_log(10))
except Exception as e:
print(f"Handled error: {e}")
# Invalid input (zero)
try:
print("log(0) =", safe_log(0))
except Exception as e:
print(f"Handled error: {e}")
# Invalid input (string)
try:
print("log('abc') =", safe_log("abc"))
except Exception as e:
print(f"Handled error: {e}")
InvalidLogInputError
)Exception
, can be caught specifically by API consumers or calling codeValueError
in large applicationserrors.log
with timestamps, which is essential for postmortem debugginglogging.error()
is used instead of print()
— a best practice for scalable apps