or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdcore-processing.mddata-structures.mdexceptions.mdheic.mdindex.mdlogging.mdutilities.md

logging.mddocs/

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

```