0
# Error Handling
1
2
Exception classes for handling parsing errors that can occur when processing Eliot message dictionaries and JSON text. These exceptions provide detailed error context and debugging information to help identify and resolve issues with malformed or invalid log data.
3
4
## Capabilities
5
6
### Eliot Parse Error Handling
7
8
Exception raised when parsing fails for Eliot message dictionaries during task processing.
9
10
```python { .api }
11
class EliotParseError(RuntimeError):
12
"""
13
An error occurred while parsing a particular Eliot message dictionary.
14
15
Attributes:
16
- message_dict: dict - The problematic Eliot message dictionary that caused the error
17
- exc_info: tuple - Exception information tuple from sys.exc_info()
18
"""
19
20
def __init__(self, message_dict, exc_info):
21
"""
22
Initialize EliotParseError with context information.
23
24
Parameters:
25
- message_dict: dict - The Eliot message dictionary that failed to parse
26
- exc_info: tuple - Exception information from sys.exc_info()
27
"""
28
```
29
30
**Usage Example:**
31
32
```python
33
from eliottree import tasks_from_iterable, EliotParseError
34
import sys
35
36
def safe_task_parsing(messages):
37
"""Parse tasks with error handling."""
38
try:
39
tasks = list(tasks_from_iterable(messages))
40
return tasks
41
except EliotParseError as e:
42
print(f"Failed to parse Eliot message: {e.message_dict}")
43
print(f"Original exception: {e.exc_info[1]}")
44
45
# Log full exception details
46
import traceback
47
traceback.print_exception(*e.exc_info)
48
49
return []
50
51
# Usage with potentially malformed messages
52
messages = [
53
{"timestamp": 1425356936.278875, "action_status": "started"}, # Missing required fields
54
{"task_uuid": "invalid", "malformed": True} # Invalid structure
55
]
56
57
tasks = safe_task_parsing(messages)
58
```
59
60
### JSON Parse Error Handling
61
62
Exception raised when JSON parsing fails during file processing, providing context about the specific location and content of the parsing failure.
63
64
```python { .api }
65
class JSONParseError(RuntimeError):
66
"""
67
An error occurred while parsing JSON text from a file or input stream.
68
69
Attributes:
70
- file_name: str - Name of the file being parsed when error occurred
71
- line_number: int - Line number in the file where parsing failed
72
- line: str - The actual line content that caused the parsing error
73
- exc_info: tuple - Exception information tuple from sys.exc_info()
74
"""
75
76
def __init__(self, file_name, line_number, line, exc_info):
77
"""
78
Initialize JSONParseError with detailed context.
79
80
Parameters:
81
- file_name: str - Name of the file being parsed
82
- line_number: int - Line number where error occurred
83
- line: str - Content of the problematic line
84
- exc_info: tuple - Exception information from sys.exc_info()
85
"""
86
```
87
88
**Usage Example:**
89
90
```python
91
import json
92
from eliottree import JSONParseError
93
94
def parse_eliot_log_file(file_path):
95
"""Parse Eliot log file with comprehensive error handling."""
96
messages = []
97
98
try:
99
with open(file_path, 'r') as f:
100
for line_num, line in enumerate(f, 1):
101
line = line.strip()
102
if not line:
103
continue
104
105
try:
106
message = json.loads(line)
107
messages.append(message)
108
except json.JSONDecodeError as e:
109
# Wrap in JSONParseError with context
110
import sys
111
raise JSONParseError(
112
file_name=file_path,
113
line_number=line_num,
114
line=line,
115
exc_info=sys.exc_info()
116
)
117
118
except JSONParseError as e:
119
print(f"JSON parsing failed in {e.file_name} at line {e.line_number}")
120
print(f"Problematic line: {e.line}")
121
print(f"JSON error: {e.exc_info[1]}")
122
return []
123
124
except IOError as e:
125
print(f"File error: {e}")
126
return []
127
128
return messages
129
130
# Usage
131
messages = parse_eliot_log_file('eliot.log')
132
```
133
134
## Complete Error Handling Pipeline
135
136
```python
137
import json
138
import sys
139
from eliottree import (
140
tasks_from_iterable, render_tasks, get_theme,
141
EliotParseError, JSONParseError
142
)
143
144
def robust_eliot_processing(file_path):
145
"""
146
Complete error-handling pipeline for Eliot log processing.
147
"""
148
149
def parse_json_file(file_path):
150
"""Parse JSON file with line-by-line error handling."""
151
messages = []
152
errors = []
153
154
try:
155
with open(file_path, 'r') as f:
156
for line_num, line in enumerate(f, 1):
157
line = line.strip()
158
if not line:
159
continue
160
161
try:
162
message = json.loads(line)
163
messages.append(message)
164
except json.JSONDecodeError as json_err:
165
error = {
166
'type': 'JSON',
167
'line_number': line_num,
168
'line': line,
169
'error': str(json_err)
170
}
171
errors.append(error)
172
continue
173
174
except IOError as io_err:
175
print(f"Cannot read file {file_path}: {io_err}")
176
return [], []
177
178
return messages, errors
179
180
def parse_eliot_tasks(messages):
181
"""Parse Eliot tasks with error collection."""
182
tasks = []
183
errors = []
184
185
try:
186
for task in tasks_from_iterable(messages):
187
tasks.append(task)
188
except EliotParseError as e:
189
error = {
190
'type': 'Eliot',
191
'message_dict': e.message_dict,
192
'error': str(e.exc_info[1])
193
}
194
errors.append(error)
195
196
return tasks, errors
197
198
# Main processing
199
print(f"Processing {file_path}...")
200
201
# Parse JSON
202
messages, json_errors = parse_json_file(file_path)
203
204
if json_errors:
205
print(f"JSON parsing errors: {len(json_errors)}")
206
for error in json_errors[:5]: # Show first 5 errors
207
print(f" Line {error['line_number']}: {error['error']}")
208
209
if not messages:
210
print("No valid messages found")
211
return
212
213
# Parse Eliot tasks
214
tasks, eliot_errors = parse_eliot_tasks(messages)
215
216
if eliot_errors:
217
print(f"Eliot parsing errors: {len(eliot_errors)}")
218
for error in eliot_errors[:3]: # Show first 3 errors
219
print(f" Message: {error['message_dict']}")
220
print(f" Error: {error['error']}")
221
222
if not tasks:
223
print("No valid tasks generated")
224
return
225
226
# Render with error handling
227
def error_writer(text):
228
print(f"RENDER ERROR: {text}", file=sys.stderr)
229
230
theme = get_theme(dark_background=True)
231
232
try:
233
render_tasks(
234
sys.stdout.write,
235
tasks,
236
theme=theme,
237
write_err=error_writer,
238
human_readable=True
239
)
240
print(f"\nSuccessfully processed {len(tasks)} tasks")
241
242
except Exception as e:
243
print(f"Rendering failed: {e}")
244
245
# Usage
246
robust_eliot_processing('eliot.log')
247
```
248
249
## Error Context and Debugging
250
251
### EliotParseError Context
252
253
```python
254
try:
255
tasks = list(tasks_from_iterable(messages))
256
except EliotParseError as e:
257
print("=== Eliot Parse Error Details ===")
258
print(f"Problematic message: {json.dumps(e.message_dict, indent=2)}")
259
print(f"Exception type: {e.exc_info[0].__name__}")
260
print(f"Exception message: {e.exc_info[1]}")
261
262
# Full traceback
263
import traceback
264
print("Full traceback:")
265
traceback.print_exception(*e.exc_info)
266
```
267
268
### JSONParseError Context
269
270
```python
271
try:
272
# JSON parsing code
273
pass
274
except JSONParseError as e:
275
print("=== JSON Parse Error Details ===")
276
print(f"File: {e.file_name}")
277
print(f"Line number: {e.line_number}")
278
print(f"Problematic content: {repr(e.line)}")
279
print(f"JSON error: {e.exc_info[1]}")
280
281
# Show surrounding context
282
with open(e.file_name, 'r') as f:
283
lines = f.readlines()
284
start = max(0, e.line_number - 3)
285
end = min(len(lines), e.line_number + 2)
286
287
print("Context:")
288
for i in range(start, end):
289
marker = ">>> " if i + 1 == e.line_number else " "
290
print(f"{marker}{i+1:4d}: {lines[i].rstrip()}")
291
```
292
293
## Common Error Scenarios
294
295
### Malformed Eliot Messages
296
297
```python
298
# Missing required fields
299
{"timestamp": 1425356936.278875} # Missing task_uuid, action_type
300
301
# Invalid field types
302
{"task_uuid": 123, "timestamp": "invalid"} # Wrong types
303
304
# Corrupted task structure
305
{"task_level": "not_a_list", "action_status": None}
306
```
307
308
### Invalid JSON Content
309
310
```python
311
# Truncated JSON
312
{"timestamp": 1425356936.278875, "action_type": "incomplete"
313
314
# Invalid escape sequences
315
{"message": "Invalid \x unicode"}
316
317
# Mixed content
318
Valid JSON line
319
Not JSON content here
320
{"another": "valid line"}
321
```
322
323
### File System Issues
324
325
- File not found or permission denied
326
- Corrupted file content or encoding issues
327
- Very large files causing memory problems
328
- Network interruptions during file access
329
330
These error classes provide the necessary context to identify, debug, and resolve issues that commonly occur when processing Eliot log data in production environments.