class PerformanceLogger
A context manager class that measures and logs the execution time of code blocks, with support for custom metrics and automatic error handling.
/tf/active/vicechatdev/contract_validity_analyzer/utils/logging_utils.py
80 - 126
simple
Purpose
PerformanceLogger is designed to track and log performance metrics for operations in Python applications. It uses the context manager protocol (with statement) to automatically start timing when entering a code block and log results when exiting. It captures execution duration, handles both successful and failed operations differently, and allows adding custom metrics during execution. This is useful for monitoring application performance, debugging slow operations, and collecting runtime statistics.
Source Code
class PerformanceLogger:
"""Context manager for logging performance metrics."""
def __init__(self, operation_name: str, logger: Optional[logging.Logger] = None):
"""
Initialize performance logger.
Args:
operation_name: Name of the operation being timed
logger: Logger instance (optional)
"""
self.operation_name = operation_name
self.logger = logger or get_logger(__name__)
self.start_time = None
self.end_time = None
self.metrics = {}
def __enter__(self):
"""Start timing."""
self.start_time = time.time()
self.logger.debug(f"Starting operation: {self.operation_name}")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""End timing and log results."""
self.end_time = time.time()
duration = self.end_time - self.start_time
if exc_type is None:
# Success
self.logger.info(f"Completed operation: {self.operation_name} in {duration:.2f}s")
if self.metrics:
metrics_str = ", ".join(f"{k}={v}" for k, v in self.metrics.items())
self.logger.info(f"Metrics for {self.operation_name}: {metrics_str}")
else:
# Error occurred
self.logger.error(f"Operation failed: {self.operation_name} after {duration:.2f}s - {exc_val}")
def add_metric(self, key: str, value: Any):
"""Add a metric to be logged."""
self.metrics[key] = value
def get_duration(self) -> Optional[float]:
"""Get the duration of the operation."""
if self.start_time and self.end_time:
return self.end_time - self.start_time
return None
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
- | - |
Parameter Details
operation_name: A descriptive string identifier for the operation being timed. This name appears in all log messages to identify which operation's performance is being measured. Should be meaningful and unique enough to distinguish different operations in logs.
logger: An optional logging.Logger instance to use for output. If not provided, the class will obtain a logger using get_logger(__name__). This allows integration with existing logging configurations or use of a default logger.
Return Value
The __init__ method returns a PerformanceLogger instance. The __enter__ method returns self, allowing the instance to be bound to a variable in the 'with' statement. The get_duration() method returns a float representing the elapsed time in seconds if both start and end times are set, otherwise returns None. The add_metric() method returns None.
Class Interface
Methods
__init__(self, operation_name: str, logger: Optional[logging.Logger] = None)
Purpose: Initialize the PerformanceLogger with an operation name and optional logger
Parameters:
operation_name: Name of the operation being timedlogger: Optional logger instance; if None, uses get_logger(__name__)
Returns: None (constructor)
__enter__(self)
Purpose: Context manager entry point that starts the timer and logs operation start
Returns: Returns self to allow binding to a variable in the with statement
__exit__(self, exc_type, exc_val, exc_tb)
Purpose: Context manager exit point that stops the timer and logs results or errors
Parameters:
exc_type: Exception type if an exception occurred, None otherwiseexc_val: Exception value if an exception occurred, None otherwiseexc_tb: Exception traceback if an exception occurred, None otherwise
Returns: None (implicitly returns None, allowing exceptions to propagate)
add_metric(self, key: str, value: Any)
Purpose: Add a custom metric to be logged when the operation completes successfully
Parameters:
key: String identifier for the metricvalue: Value of the metric (can be any type that converts to string)
Returns: None
get_duration(self) -> Optional[float]
Purpose: Retrieve the duration of the operation in seconds
Returns: Float representing duration in seconds if timing is complete, None if timing hasn't started or finished
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
operation_name |
str | Name of the operation being timed, used in log messages | instance |
logger |
logging.Logger | Logger instance used for outputting performance information | instance |
start_time |
Optional[float] | Timestamp when the operation started (from time.time()), None before __enter__ is called | instance |
end_time |
Optional[float] | Timestamp when the operation ended (from time.time()), None before __exit__ is called | instance |
metrics |
Dict[str, Any] | Dictionary storing custom metrics added during operation execution, logged on successful completion | instance |
Dependencies
loggingtimetyping
Required Imports
import logging
import time
from typing import Optional, Any
Usage Example
import logging
import time
from typing import Optional, Any
# Assuming get_logger is defined or use standard logger
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
# Basic usage
with PerformanceLogger('data_processing', logger) as perf:
# Simulate some work
time.sleep(1)
# Add custom metrics
perf.add_metric('records_processed', 1000)
perf.add_metric('cache_hits', 45)
# Get duration after completion
print(f"Duration: {perf.get_duration():.2f}s")
# Usage with error handling
try:
with PerformanceLogger('risky_operation') as perf:
# This will be logged as failed
raise ValueError('Something went wrong')
except ValueError:
pass
Best Practices
- Always use as a context manager with the 'with' statement to ensure proper timing and cleanup
- Provide descriptive operation names that clearly identify what is being measured
- Add metrics using add_metric() during the operation, not after the context exits
- Call get_duration() only after the context has exited to get accurate timing
- The logger should be configured before use to ensure log messages are captured
- Metrics are logged only on successful completion (no exception); failed operations log the error but not metrics
- The class does not suppress exceptions - they propagate normally after logging
- Instance can be reused but timing will reflect only the most recent context entry/exit
- Thread-safe for independent instances but not for shared instances across threads
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function log_performance 72.9% similar
-
class ProgressLogger 65.0% similar
-
function setup_logging_v3 48.8% similar
-
function setup_test_logging 47.4% similar
-
function setup_test_logging_v3 46.9% similar