Chapter 7: Error Handling
In Chapter 6: Data Processing Callbacks, we learned how to process data as it arrives over a network. However, when working with complex security imaging systems, things don’t always go as planned. Files might be corrupted, network connections can drop, or algorithms might encounter unexpected data. This is where proper error handling becomes essential.
Why is Error Handling Important?
Imagine you’re operating a security checkpoint at an airport. If a scanner encounters an error, you need to know:
- What exactly went wrong?
- How serious is the problem?
- Should the checkpoint be temporarily closed?
- What steps should be taken to fix the issue?
Without good error handling, you might miss critical security threats or unnecessarily halt operations.
The ErrorLog Class: Your Error Management System
pyDICOS provides a robust error handling system through the ErrorLog
class. Think of it as a digital logbook that records any issues that occur during operation. Just like a pilot’s logbook records flight issues, the ErrorLog
captures problems in your security imaging operations.
from pydicos import ErrorLog, CTLoader
# Create an error log
error_log = ErrorLog()
# Try to load a file that might not exist
ct_loader = CTLoader()
if not ct_loader.read("possibly_missing_file.ct", error_log):
print("Could not load the file")
# Check if we have errors
if error_log.NumErrors() > 0:
print(f"Found {error_log.NumErrors()} errors:")
print(error_log.GetErrorLog()) # Print the full error log
This code creates an ErrorLog
and passes it to the read
method. If the file can’t be loaded, we check for errors and display them. This is much more helpful than just knowing that something failed - we know exactly what went wrong.
Distinguishing Between Errors and Warnings
pyDICOS differentiates between two types of issues:
- Errors: Critical issues that prevent an operation from completing (e.g., missing file)
- Warnings: Non-critical issues that allow operation to continue but might affect results (e.g., unexpected data format)
You can check and handle each type separately:
# Check for both errors and warnings
if error_log.NumErrors() > 0:
print(f"Critical Issues: {error_log.NumErrors()} errors found")
if error_log.NumWarnings() > 0:
print(f"Minor Issues: {error_log.NumWarnings()} warnings found")
# You can decide how to respond based on severity
if error_log.NumErrors() > 0:
print("Operation failed - need administrator attention")
elif error_log.NumWarnings() > 0:
print("Operation completed with warnings - results may be affected")
else:
print("Operation completed successfully")
This approach lets you respond appropriately to different levels of issues - critical errors might require immediate attention, while warnings might just need a note in your report.
Getting Detailed Error Information
To get the full details of what went wrong, you have a few options:
Option 1: Get the complete error log as a string
# Get the complete error log as a string
complete_log = error_log.GetErrorLog()
print(complete_log) # Prints all errors and warnings
Option 2: Get separate lists of errors and warnings
# Create arrays to hold the error and warning messages
error_messages = []
warning_messages = []
# Fill the arrays with messages from the error log
error_log.GetErrorLog(error_messages, warning_messages)
# Now you can process them separately
print("ERRORS:")
for error in error_messages:
print(f"- {error}")
print("\nWARNINGS:")
for warning in warning_messages:
print(f"- {warning}")
This second approach is particularly useful when you need to handle errors and warnings differently or display them in separate sections of a user interface.
Saving Error Logs to File
In production environments, you often want to save error logs to files for later analysis. pyDICOS makes this simple:
# Save the error log to a file
error_log.WriteLog("security_system_errors.log")
print("Error log saved to file for later analysis")
This creates a text file containing all errors and warnings, which can be extremely valuable for:
- Troubleshooting complex issues
- Providing information to technical support
- Creating audit trails for security incidents
Advanced: Redirecting Error Logs
In larger systems, you might want to route error messages to different places - like a central monitoring dashboard or an email alert system. pyDICOS allows you to redirect error logs:
from pydicos import ErrorLog
from pyDICOS import REDIRECT_LOG_TYPE
# Define a function to handle redirected logs
def my_error_handler(message, log_type):
if log_type == REDIRECT_LOG_TYPE.enumRedirect_Error:
print(f"CRITICAL ERROR: {message}")
# You could send an email alert here
else: # It's a warning
print(f"WARNING: {message}")
# You could log to a database here
return True # Return True to indicate successful handling
# Set up the redirect
ErrorLog.SetErrorLogRedirect(my_error_handler)
Once you’ve set up a redirect, all error and warning messages will be sent to your custom handler function. This is particularly useful for integrating pyDICOS with larger monitoring systems.
Under the Hood: How Error Handling Works
Let’s look at what happens behind the scenes when an error occurs in pyDICOS:
sequenceDiagram
participant App as Your Code
participant Func as pyDICOS Function
participant EL as ErrorLog
participant Redirect as Error Redirect
App->>Func: Call function with ErrorLog
Func->>Func: Operation fails
Func->>EL: Add error message
alt Has Redirect
EL->>Redirect: Send to custom handler
Redirect-->>EL: Confirm receipt
end
Func-->>App: Return failure status
App->>EL: Check for errors
EL-->>App: Provide error details
App->>App: Handle error
When you call a pyDICOS function with an ErrorLog
parameter, the function records any errors or warnings in that log. If something goes wrong, the function returns a failure status (usually False
or None
), and you can then check the error log for details about what happened.
Inside the C++ code, the ErrorLog
class maintains two lists: one for errors and one for warnings. Each message gets added to the appropriate list, and if a redirect function is set, the message is also sent to that function.
Let’s look at a simplified version of what happens in the C++ code:
// When an error occurs in a pyDICOS function
void SomeFunction(ErrorLog& log) {
try {
// Try to do something...
}
catch (const std::exception& e) {
// Add the error message to the log
log.AddError(e.what());
return false; // Indicate failure
}
}
// Inside the ErrorLog class
void ErrorLog::AddError(const char* message) {
// Add to internal list
m_errors.push_back(message);
// If redirect is enabled, send to custom handler
if (HasRedirect() && !m_ignoreRedirect) {
m_redirectFunc(message, REDIRECT_LOG_TYPE::enumRedirect_Error);
}
}
This design makes error handling in pyDICOS both flexible and powerful.
Example: Creating a Robust Security Scanner
Let’s put everything together to create a more robust version of the security scanner from previous chapters:
from pydicos import CTLoader, ErrorLog
import os
def scan_luggage(luggage_id):
"""Scan luggage and handle potential errors properly"""
# Create an error log
error_log = ErrorLog()
# Create a filename for this scan
filename = f"luggage_{luggage_id}.ct"
# Try to perform the scan
print(f"Scanning luggage {luggage_id}...")
ct_loader = CTLoader()
# In a real system, this would interface with hardware
# For this example, we'll simulate by checking if file exists
if not os.path.exists(filename):
# Simulate scan error
error_log.AddError(f"Scanner hardware error: Could not complete scan for {luggage_id}")
return None, error_log
# Try to load the scan
if not ct_loader.read(filename, error_log):
return None, error_log
return ct_loader, error_log
We can use this function in a more complete error-handling workflow:
def process_luggage(luggage_id):
# Attempt to scan the luggage
ct_scan, error_log = scan_luggage(luggage_id)
# Check for serious errors
if error_log.NumErrors() > 0:
print(f"Error scanning luggage {luggage_id}:")
print(error_log.GetErrorLog())
# Log the error for later analysis
error_log.WriteLog(f"error_luggage_{luggage_id}.log")
# Handle based on error severity
if "hardware error" in error_log.GetErrorLog():
print("CRITICAL: Hardware failure - system needs maintenance")
return "MAINTENANCE_REQUIRED"
else:
print("ERROR: Scan failed - luggage needs manual inspection")
return "MANUAL_INSPECTION"
# Check for warnings
if error_log.NumWarnings() > 0:
print(f"Scan completed with warnings for luggage {luggage_id}:")
print(error_log.GetErrorLog())
return "PROCEED_WITH_CAUTION"
# All good
print(f"Scan completed successfully for luggage {luggage_id}")
return "PROCEED"
This approach provides a systematic way to handle different error scenarios in a security screening context.
Best Practices for Error Handling
Based on what we’ve learned, here are some best practices for error handling in pyDICOS:
- Always use an ErrorLog: Pass an
ErrorLog
to functions that accept it - Check both errors and warnings: Different severity levels need different responses
- Save logs for critical errors: Use
WriteLog
to keep records of serious issues - Be specific in custom error handlers: Tailor responses to specific error types
- Implement appropriate fallbacks: Have a plan for when errors occur
Summary
In this chapter, we’ve learned about pyDICOS’s error handling system:
- The
ErrorLog
class captures both errors and warnings during operations - You can distinguish between critical errors and non-critical warnings
- Error details can be retrieved as a single string or as separate lists
- Logs can be saved to files for later analysis
- Error messages can be redirected to custom handlers for integration with other systems
Proper error handling is crucial in security imaging applications, where failures can have serious consequences. With pyDICOS’s error handling system, you can build more robust applications that gracefully handle unexpected situations.
In the next chapter, Memory Management, we’ll learn how to efficiently manage memory when working with large security scan data, ensuring your applications run smoothly even with limited resources.
Generated by AI Codebase Knowledge Builder