0
# Logging and Debugging
1
2
Enhanced logging capabilities with DEBUG2 level support and environment introspection tools for development and troubleshooting.
3
4
## Capabilities
5
6
### Enhanced Logging
7
8
Get loggers with extended debugging capabilities.
9
10
```python { .api }
11
def get_logger(name: str, logger_class=None) -> Logger:
12
"""
13
Get standard or custom logger instance.
14
15
Args:
16
name (str): Logger name (typically __name__)
17
logger_class: Optional logger class (defaults to standard Logger)
18
19
Returns:
20
Logger: Configured logger instance
21
"""
22
23
def get_extended_debug_logger(name: str) -> ExtendedDebugLogger:
24
"""
25
Get logger with DEBUG2 level support.
26
27
Args:
28
name (str): Logger name
29
30
Returns:
31
ExtendedDebugLogger: Logger with debug2() method
32
"""
33
34
def setup_DEBUG2_logging():
35
"""Configure DEBUG2 logging level in logging system."""
36
```
37
38
### Logger Classes and Mixins
39
40
Enhanced logger classes and mixins for automatic logger setup.
41
42
```python { .api }
43
class ExtendedDebugLogger(logging.Logger):
44
"""Logger class with DEBUG2 level support."""
45
46
def debug2(self, message, *args, **kwargs):
47
"""Log at DEBUG2 level (more verbose than DEBUG)."""
48
49
class HasLogger:
50
"""Mixin class providing logger property."""
51
52
@property
53
def logger(self) -> Logger:
54
"""Get logger for this class."""
55
56
class HasExtendedDebugLogger:
57
"""Mixin class providing extended debug logger property."""
58
59
@property
60
def logger(self) -> ExtendedDebugLogger:
61
"""Get extended debug logger for this class."""
62
63
class HasLoggerMeta(type):
64
"""Metaclass for automatic logger setup."""
65
66
class HasExtendedDebugLoggerMeta(type):
67
"""Metaclass for automatic extended logger setup."""
68
```
69
70
### Environment Debugging
71
72
Environment introspection tools for troubleshooting.
73
74
```python { .api }
75
def get_environment_summary() -> str:
76
"""
77
Get comprehensive environment information.
78
79
Returns:
80
str: Detailed environment summary including Python version,
81
platform info, installed packages, and system details
82
"""
83
84
def python_version() -> str:
85
"""Get Python version information."""
86
87
def platform_info() -> str:
88
"""Get detailed platform information."""
89
90
def pip_freeze() -> str:
91
"""Get pip freeze output for dependency tracking."""
92
```
93
94
### Logging Constants
95
96
```python { .api }
97
DEBUG2_LEVEL_NUM = 8 # Numeric value for DEBUG2 logging level
98
```
99
100
## Usage Examples
101
102
### Basic Logging Setup
103
104
```python
105
from eth_utils import get_logger, get_extended_debug_logger
106
107
# Standard logger
108
logger = get_logger(__name__)
109
logger.info("Application started")
110
logger.debug("Debug information")
111
112
# Extended debug logger
113
debug_logger = get_extended_debug_logger(__name__)
114
debug_logger.info("Application started")
115
debug_logger.debug("Standard debug info")
116
debug_logger.debug2("Very detailed debug info") # More verbose than debug
117
```
118
119
### Logger Mixins
120
121
```python
122
from eth_utils import HasLogger, HasExtendedDebugLogger
123
124
class EthereumClient(HasLogger):
125
"""Ethereum client with automatic logging."""
126
127
def connect(self, url):
128
self.logger.info(f"Connecting to {url}")
129
try:
130
# Connection logic here
131
self.logger.info("Connected successfully")
132
except Exception as e:
133
self.logger.error(f"Connection failed: {e}")
134
135
class DetailedEthereumClient(HasExtendedDebugLogger):
136
"""Ethereum client with detailed debugging."""
137
138
def send_transaction(self, tx):
139
self.logger.info("Sending transaction")
140
self.logger.debug(f"Transaction data: {tx}")
141
self.logger.debug2(f"Raw transaction bytes: {tx.raw_data}")
142
143
# Send logic here
144
self.logger.debug2("Transaction sent, waiting for receipt")
145
146
# Usage
147
client = EthereumClient()
148
client.connect("https://mainnet.infura.io/v3/...")
149
150
detailed_client = DetailedEthereumClient()
151
detailed_client.send_transaction(some_transaction)
152
```
153
154
### DEBUG2 Level Configuration
155
156
```python
157
from eth_utils import setup_DEBUG2_logging, get_extended_debug_logger
158
import logging
159
160
# Setup DEBUG2 level
161
setup_DEBUG2_logging()
162
163
# Configure logging level
164
logging.basicConfig(level=8) # DEBUG2_LEVEL_NUM
165
166
# Use extended logger
167
logger = get_extended_debug_logger(__name__)
168
169
logger.info("Info level message") # Always shown
170
logger.debug("Debug level message") # Shown if level <= DEBUG
171
logger.debug2("Debug2 level message") # Shown if level <= DEBUG2 (8)
172
```
173
174
### Environment Debugging
175
176
```python
177
from eth_utils import get_environment_summary, python_version, platform_info, pip_freeze
178
179
def diagnose_environment():
180
"""Generate comprehensive environment diagnostic."""
181
print("=== Environment Diagnostic ===")
182
183
# Complete environment summary
184
print("Full Environment Summary:")
185
print(get_environment_summary())
186
print()
187
188
# Specific components
189
print(f"Python Version: {python_version()}")
190
print(f"Platform: {platform_info()}")
191
192
print("\nInstalled Packages:")
193
print(pip_freeze())
194
195
# Run diagnostic
196
diagnose_environment()
197
```
198
199
### Development Logging Patterns
200
201
```python
202
from eth_utils import get_extended_debug_logger
203
import json
204
205
class TransactionProcessor(HasExtendedDebugLogger):
206
"""Transaction processor with comprehensive logging."""
207
208
def process_transaction(self, tx_hash):
209
self.logger.info(f"Processing transaction {tx_hash}")
210
211
try:
212
# Fetch transaction
213
self.logger.debug(f"Fetching transaction data for {tx_hash}")
214
tx_data = self.fetch_transaction(tx_hash)
215
self.logger.debug2(f"Raw transaction data: {json.dumps(tx_data, indent=2)}")
216
217
# Validate transaction
218
self.logger.debug("Validating transaction")
219
if not self.validate_transaction(tx_data):
220
self.logger.warning(f"Transaction validation failed: {tx_hash}")
221
return False
222
223
# Process transaction
224
self.logger.debug("Processing validated transaction")
225
result = self.execute_transaction(tx_data)
226
self.logger.debug2(f"Transaction execution result: {result}")
227
228
self.logger.info(f"Successfully processed transaction {tx_hash}")
229
return True
230
231
except Exception as e:
232
self.logger.error(f"Error processing transaction {tx_hash}: {e}", exc_info=True)
233
return False
234
235
def fetch_transaction(self, tx_hash):
236
"""Fetch transaction with detailed logging."""
237
self.logger.debug2(f"Making RPC call for transaction {tx_hash}")
238
# RPC call logic here
239
return {"hash": tx_hash, "value": "0x1"}
240
241
def validate_transaction(self, tx_data):
242
"""Validate transaction with debug logging."""
243
self.logger.debug2(f"Validating fields: {list(tx_data.keys())}")
244
# Validation logic here
245
return True
246
247
def execute_transaction(self, tx_data):
248
"""Execute transaction with detailed tracing."""
249
self.logger.debug2("Starting transaction execution")
250
# Execution logic here
251
return {"status": "success"}
252
253
# Usage
254
processor = TransactionProcessor()
255
processor.process_transaction("0x123...")
256
```
257
258
### Custom Logger Configuration
259
260
```python
261
from eth_utils import get_logger, get_extended_debug_logger, setup_DEBUG2_logging
262
import logging
263
264
def setup_application_logging(log_level="INFO", enable_debug2=False):
265
"""Setup application-wide logging configuration."""
266
267
# Configure basic logging
268
logging.basicConfig(
269
level=getattr(logging, log_level.upper()),
270
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
271
handlers=[
272
logging.StreamHandler(),
273
logging.FileHandler('application.log')
274
]
275
)
276
277
# Enable DEBUG2 if requested
278
if enable_debug2:
279
setup_DEBUG2_logging()
280
if log_level.upper() == "DEBUG2":
281
logging.getLogger().setLevel(8) # DEBUG2_LEVEL_NUM
282
283
# Create application loggers
284
app_logger = get_logger("application")
285
286
if enable_debug2:
287
debug_logger = get_extended_debug_logger("application.debug")
288
return app_logger, debug_logger
289
else:
290
return app_logger, None
291
292
# Setup logging
293
app_logger, debug_logger = setup_application_logging(log_level="DEBUG", enable_debug2=True)
294
295
app_logger.info("Application logging configured")
296
if debug_logger:
297
debug_logger.debug2("Extended debugging enabled")
298
```
299
300
### Error Tracking and Reporting
301
302
```python
303
from eth_utils import get_logger, get_environment_summary
304
import traceback
305
306
class ErrorReporter(HasLogger):
307
"""Error reporting with environment context."""
308
309
def report_error(self, error, context=None):
310
"""Report error with full context."""
311
error_id = f"ERR_{hash(str(error)) % 10000:04d}"
312
313
self.logger.error(f"Error {error_id}: {error}")
314
315
if context:
316
self.logger.error(f"Error context: {context}")
317
318
# Log full traceback
319
self.logger.error(f"Traceback:\n{traceback.format_exc()}")
320
321
# Log environment for debugging
322
self.logger.debug(f"Environment at error time:\n{get_environment_summary()}")
323
324
return error_id
325
326
def report_transaction_error(self, tx_hash, error):
327
"""Report transaction-specific error."""
328
context = {
329
"transaction_hash": tx_hash,
330
"error_type": type(error).__name__,
331
"timestamp": "2024-01-01T00:00:00Z" # Would use actual timestamp
332
}
333
334
return self.report_error(error, context)
335
336
# Usage
337
reporter = ErrorReporter()
338
339
try:
340
# Some operation that might fail
341
process_transaction("0x123...")
342
except Exception as e:
343
error_id = reporter.report_transaction_error("0x123...", e)
344
print(f"Error reported with ID: {error_id}")
345
```
346
347
### Performance Logging
348
349
```python
350
from eth_utils import get_extended_debug_logger
351
import time
352
from functools import wraps
353
354
def log_performance(logger_name=None):
355
"""Decorator to log function performance."""
356
def decorator(func):
357
@wraps(func)
358
def wrapper(*args, **kwargs):
359
logger = get_extended_debug_logger(logger_name or func.__module__)
360
361
start_time = time.time()
362
logger.debug2(f"Starting {func.__name__} with args={args}, kwargs={kwargs}")
363
364
try:
365
result = func(*args, **kwargs)
366
execution_time = time.time() - start_time
367
368
logger.debug(f"{func.__name__} completed in {execution_time:.4f}s")
369
logger.debug2(f"{func.__name__} result: {result}")
370
371
return result
372
373
except Exception as e:
374
execution_time = time.time() - start_time
375
logger.error(f"{func.__name__} failed after {execution_time:.4f}s: {e}")
376
raise
377
378
return wrapper
379
return decorator
380
381
# Usage
382
class BlockchainAnalyzer(HasExtendedDebugLogger):
383
384
@log_performance("blockchain.analyzer")
385
def analyze_transaction(self, tx_hash):
386
"""Analyze transaction with performance logging."""
387
self.logger.info(f"Analyzing transaction {tx_hash}")
388
389
# Simulate analysis work
390
time.sleep(0.1)
391
392
return {"status": "analyzed", "gas_used": 21000}
393
394
# Usage
395
analyzer = BlockchainAnalyzer()
396
result = analyzer.analyze_transaction("0x123...")
397
```