0
# Logging System
1
2
Configurable logging system with debug output, color support, and structured error reporting for troubleshooting metadata extraction issues. The logging system provides detailed information about EXIF processing steps and errors.
3
4
## Capabilities
5
6
### Logger Configuration
7
8
Functions for setting up and configuring the ExifRead logging system.
9
10
```python { .api }
11
def get_logger():
12
"""
13
Get logger instance for ExifRead.
14
15
Returns the standard logger instance used throughout the ExifRead
16
library for consistent logging output.
17
18
Returns:
19
logging.Logger: Logger instance named 'exifread'
20
"""
21
22
def setup_logger(debug, color):
23
"""
24
Configure logger with debug and color options.
25
26
Sets up the logging system with appropriate handlers, formatters,
27
and output levels for the ExifRead library.
28
29
Parameters:
30
- debug: bool, enable debug level logging (INFO level if False)
31
- color: bool, enable colored output on POSIX systems (requires debug=True)
32
"""
33
```
34
35
### Custom Logging Classes
36
37
Specialized formatter and handler classes for ExifRead logging output.
38
39
```python { .api }
40
class Formatter:
41
"""
42
Custom log formatter with color support.
43
44
Provides formatted log output with optional color coding for different
45
log levels and customizable format strings for debug vs normal output.
46
"""
47
48
def __init__(self, debug=False, color=False):
49
"""
50
Initialize custom formatter.
51
52
Parameters:
53
- debug: bool, use debug format with level names
54
- color: bool, enable ANSI color codes for log levels
55
"""
56
57
def format(self, record) -> str:
58
"""
59
Format log record with optional color coding.
60
61
Parameters:
62
- record: logging.LogRecord, log record to format
63
64
Returns:
65
str: Formatted log message
66
"""
67
68
class Handler:
69
"""
70
Custom log handler for ExifRead output.
71
72
Extends logging.StreamHandler with ExifRead-specific formatting
73
and configuration for stdout output.
74
"""
75
76
def __init__(self, log_level, debug=False, color=False):
77
"""
78
Initialize custom log handler.
79
80
Parameters:
81
- log_level: int, logging level (logging.DEBUG, logging.INFO, etc.)
82
- debug: bool, enable debug formatting
83
- color: bool, enable color output
84
"""
85
```
86
87
## Usage Examples
88
89
### Basic Logging Setup
90
91
```python
92
import exifread
93
from exifread.exif_log import get_logger, setup_logger
94
95
# Configure logging for debug output with colors
96
setup_logger(debug=True, color=True)
97
98
# Get the logger instance
99
logger = get_logger()
100
101
# Process file with logging enabled
102
with open('photo.jpg', 'rb') as f:
103
tags = exifread.process_file(f, debug=True)
104
105
# The debug=True parameter in process_file() will generate detailed logging output
106
```
107
108
### Custom Logging Configuration
109
110
```python
111
import logging
112
from exifread.exif_log import get_logger, setup_logger
113
114
# Setup with different configurations
115
def configure_exif_logging(level='info', enable_color=False):
116
"""Configure ExifRead logging with custom settings."""
117
debug_mode = level.lower() == 'debug'
118
setup_logger(debug=debug_mode, color=enable_color)
119
120
logger = get_logger()
121
122
# Add file logging in addition to console
123
file_handler = logging.FileHandler('exif_processing.log')
124
file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
125
file_handler.setFormatter(file_formatter)
126
logger.addHandler(file_handler)
127
128
return logger
129
130
# Usage
131
logger = configure_exif_logging(level='debug', enable_color=True)
132
133
with open('photo.jpg', 'rb') as f:
134
tags = exifread.process_file(f, debug=True)
135
logger.info(f"Extracted {len(tags)} EXIF tags")
136
```
137
138
### Debug Output Example
139
140
When debug mode is enabled, ExifRead produces detailed logging output:
141
142
```python
143
import exifread
144
from exifread.exif_log import setup_logger
145
146
# Enable debug logging with colors
147
setup_logger(debug=True, color=True)
148
149
with open('photo.jpg', 'rb') as f:
150
tags = exifread.process_file(f, debug=True)
151
152
# Example debug output:
153
# DEBUG JPEG format recognized in data[0:2]
154
# DEBUG APP1 at base 0x14
155
# DEBUG Length: 0x22 0x5E
156
# DEBUG Code: Exif
157
# DEBUG Endian format is I (Intel)
158
# DEBUG IFD 0 (Image) at offset 18:
159
# DEBUG Make: (0x010F) ASCII=Canon @ 150
160
# DEBUG Model: (0x0110) ASCII=Canon EOS 5D Mark IV @ 156
161
# DEBUG Exif SubIFD at offset 180:
162
# DEBUG DateTimeOriginal: (0x9003) ASCII=2023:08:15 14:30:22 @ 344
163
# INFO Opening: photo.jpg
164
# INFO File has JPEG thumbnail
165
```
166
167
### Logging Levels and Colors
168
169
```python
170
import logging
171
from exifread.exif_log import setup_logger, get_logger
172
173
# Setup with color support
174
setup_logger(debug=True, color=True)
175
logger = get_logger()
176
177
# Different log levels produce different colors (on POSIX systems):
178
logger.debug("Debug message") # Cyan
179
logger.info("Info message") # Green
180
logger.warning("Warning message") # Yellow
181
logger.error("Error message") # Red
182
logger.critical("Critical message") # Red
183
184
# Color codes used:
185
# TEXT_NORMAL = 0, TEXT_BOLD = 1, TEXT_RED = 31, TEXT_GREEN = 32
186
# TEXT_YELLOW = 33, TEXT_BLUE = 34, TEXT_MAGENTA = 35, TEXT_CYAN = 36
187
```
188
189
### Capturing Log Output
190
191
```python
192
import io
193
import logging
194
import sys
195
from exifread.exif_log import get_logger, setup_logger
196
197
def capture_exif_logs(filename):
198
"""Capture ExifRead log output for analysis."""
199
200
# Create string buffer to capture output
201
log_capture = io.StringIO()
202
203
# Setup logging to capture output
204
setup_logger(debug=True, color=False)
205
logger = get_logger()
206
207
# Add handler to capture logs
208
string_handler = logging.StreamHandler(log_capture)
209
string_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
210
logger.addHandler(string_handler)
211
212
# Process file
213
with open(filename, 'rb') as f:
214
tags = exifread.process_file(f, debug=True)
215
216
# Get captured output
217
log_output = log_capture.getvalue()
218
log_capture.close()
219
220
return tags, log_output
221
222
# Usage
223
tags, logs = capture_exif_logs('photo.jpg')
224
print("Captured logs:")
225
print(logs)
226
```
227
228
### Integration with Application Logging
229
230
```python
231
import logging
232
import exifread
233
from exifread.exif_log import get_logger
234
235
# Configure application-wide logging
236
logging.basicConfig(
237
level=logging.INFO,
238
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
239
handlers=[
240
logging.FileHandler('app.log'),
241
logging.StreamHandler()
242
]
243
)
244
245
# Get application logger
246
app_logger = logging.getLogger('myapp')
247
248
# Get ExifRead logger and configure it to use same format
249
exif_logger = get_logger()
250
exif_logger.setLevel(logging.INFO)
251
252
def process_image_with_logging(filename):
253
"""Process image with integrated logging."""
254
app_logger.info(f"Starting EXIF processing for {filename}")
255
256
try:
257
with open(filename, 'rb') as f:
258
tags = exifread.process_file(f, debug=False)
259
260
app_logger.info(f"Successfully processed {filename}: {len(tags)} tags")
261
return tags
262
263
except Exception as e:
264
app_logger.error(f"Failed to process {filename}: {e}")
265
return None
266
267
# Usage
268
tags = process_image_with_logging('photo.jpg')
269
```
270
271
### Filtering Log Messages
272
273
```python
274
import logging
275
from exifread.exif_log import setup_logger, get_logger
276
277
class ExifLogFilter(logging.Filter):
278
"""Custom filter for ExifRead log messages."""
279
280
def __init__(self, include_tags=None, exclude_tags=None):
281
super().__init__()
282
self.include_tags = include_tags or []
283
self.exclude_tags = exclude_tags or []
284
285
def filter(self, record):
286
message = record.getMessage()
287
288
# Include only specific tag types
289
if self.include_tags:
290
return any(tag in message for tag in self.include_tags)
291
292
# Exclude specific tag types
293
if self.exclude_tags:
294
return not any(tag in message for tag in self.exclude_tags)
295
296
return True
297
298
# Setup logging with filtering
299
setup_logger(debug=True, color=False)
300
logger = get_logger()
301
302
# Filter to only show GPS and DateTime tags
303
gps_filter = ExifLogFilter(include_tags=['GPS', 'DateTime'])
304
logger.addFilter(gps_filter)
305
306
# Process file - only GPS and DateTime debug messages will appear
307
with open('photo.jpg', 'rb') as f:
308
tags = exifread.process_file(f, debug=True)
309
```
310
311
### Performance Logging
312
313
```python
314
import time
315
from exifread.exif_log import setup_logger, get_logger
316
317
def process_with_timing(filename):
318
"""Process file with detailed timing information."""
319
setup_logger(debug=True, color=False)
320
logger = get_logger()
321
322
start_time = time.time()
323
logger.info(f"Starting processing: {filename}")
324
325
try:
326
with open(filename, 'rb') as f:
327
file_read_start = time.time()
328
tags = exifread.process_file(f, debug=True)
329
processing_time = time.time() - file_read_start
330
331
total_time = time.time() - start_time
332
333
logger.info(f"Processing completed in {processing_time:.3f}s")
334
logger.info(f"Total time: {total_time:.3f}s")
335
logger.info(f"Tags extracted: {len(tags)}")
336
337
return tags
338
339
except Exception as e:
340
logger.error(f"Processing failed after {time.time() - start_time:.3f}s: {e}")
341
return None
342
343
# Usage
344
tags = process_with_timing('large_photo.jpg')
345
```