1485.2.4
by Christopher Lee
Initial log chunking. |
1 |
from datetime import datetime, timedelta |
2 |
import gzip |
|
3 |
||
4 |
LOG_BREAKDOWN_SECONDS = 20 |
|
5 |
dt_format = '%Y-%m-%d %H:%M:%S' |
|
6 |
||
7 |
||
1485.2.25
by Christopher Lee
log breakdown details revamp |
8 |
def breakdown_log_by_timeframes(log_file, event_timestamps): |
9 |
"""event_timestamps is a list of TimingData objects."""
|
|
10 |
# for each event break the time span into chunks of x seconds. the result
|
|
11 |
# being a list of tuples of start/end timestamps
|
|
12 |
||
1485.2.4
by Christopher Lee
Initial log chunking. |
13 |
all_log_breakdown = dict() |
1485.2.25
by Christopher Lee
log breakdown details revamp |
14 |
for event in event_timestamps: |
15 |
event_range_breakdown = _chunk_event_range(event) |
|
16 |
breakdown = get_timerange_logs(log_file, event_range_breakdown) |
|
17 |
range_name = _render_ds_string(event.start, event.end) |
|
1485.2.4
by Christopher Lee
Initial log chunking. |
18 |
all_log_breakdown[range_name] = breakdown |
19 |
||
20 |
return all_log_breakdown |
|
21 |
||
22 |
||
1485.2.25
by Christopher Lee
log breakdown details revamp |
23 |
def _chunk_event_range(event): |
24 |
range_breakdown = [] |
|
25 |
range_start = datetime.strptime(event.start, dt_format) |
|
26 |
range_end = datetime.strptime(event.end, dt_format) |
|
27 |
||
28 |
next_step = range_start + timedelta(seconds=LOG_BREAKDOWN_SECONDS) |
|
29 |
||
30 |
if next_step > range_end: |
|
31 |
range_breakdown.append((range_start, range_end)) |
|
32 |
else: |
|
33 |
while next_step < range_end: |
|
34 |
range_breakdown.append((range_start, next_step)) |
|
35 |
||
36 |
range_start = next_step |
|
37 |
next_step = range_start + timedelta( |
|
38 |
seconds=LOG_BREAKDOWN_SECONDS) |
|
39 |
# Otherwise there will be overlap.
|
|
40 |
range_start += timedelta(seconds=1) |
|
41 |
||
42 |
if next_step >= range_end: |
|
43 |
range_breakdown.append((range_start, range_end)) |
|
44 |
||
45 |
return range_breakdown |
|
46 |
||
47 |
||
48 |
def _render_ds_string(start, end): |
|
49 |
return '{} - {}'.format(start, end) |
|
50 |
||
51 |
||
1485.2.4
by Christopher Lee
Initial log chunking. |
52 |
def get_timerange_logs(log_file, timestamps): |
53 |
log_breakdown = dict() |
|
54 |
previous_line = None |
|
1485.2.6
by Christopher Lee
Compressed chunks of logs that contain no details. |
55 |
no_content = None |
1485.2.4
by Christopher Lee
Initial log chunking. |
56 |
with gzip.open(log_file, 'rt') as f: |
1485.2.6
by Christopher Lee
Compressed chunks of logs that contain no details. |
57 |
log_lines = [] |
1485.2.4
by Christopher Lee
Initial log chunking. |
58 |
for log_range in timestamps: |
59 |
range_end = log_range[1] |
|
1485.2.6
by Christopher Lee
Compressed chunks of logs that contain no details. |
60 |
if no_content is not None: |
61 |
# Extend the range until we get something in the logs.
|
|
62 |
range_start = no_content |
|
63 |
no_content = None |
|
64 |
range_str = '{} - {} (condensed)'.format( |
|
1485.2.8
by Christopher Lee
Remove daet from log chunks, only time. |
65 |
range_start.strftime('%T'), range_end.strftime('%T')) |
1485.2.6
by Christopher Lee
Compressed chunks of logs that contain no details. |
66 |
# Don't reset log_lines as it may contain previous details.
|
67 |
else: |
|
68 |
log_lines = [] |
|
69 |
range_start = log_range[0] |
|
1485.2.8
by Christopher Lee
Remove daet from log chunks, only time. |
70 |
range_str = '{} - {}'.format( |
71 |
range_start.strftime('%T'), range_end.strftime('%T')) |
|
1485.2.4
by Christopher Lee
Initial log chunking. |
72 |
|
73 |
if previous_line: |
|
74 |
if log_line_within_start_range(previous_line, range_start): |
|
75 |
log_lines.append(previous_line) |
|
76 |
previous_line = None |
|
77 |
||
78 |
for line in f: |
|
79 |
if log_line_within_start_range(line, range_start): |
|
80 |
break
|
|
81 |
else: |
|
1485.2.6
by Christopher Lee
Compressed chunks of logs that contain no details. |
82 |
# Likely because the log cuts off before the action is
|
83 |
# considered complete (i.e. teardown).
|
|
84 |
print('LOG: failed to find start line.') |
|
1485.2.4
by Christopher Lee
Initial log chunking. |
85 |
break
|
86 |
||
87 |
# It it's out of range of the end range then there is nothing for
|
|
88 |
# this time period.
|
|
89 |
if not log_line_within_end_range(line, range_end): |
|
90 |
previous_line = line |
|
1485.2.6
by Christopher Lee
Compressed chunks of logs that contain no details. |
91 |
no_content = range_start |
1485.2.4
by Christopher Lee
Initial log chunking. |
92 |
continue
|
93 |
||
94 |
log_lines.append(line) |
|
95 |
||
96 |
for line in f: |
|
97 |
if log_line_within_end_range(line, range_end): |
|
98 |
log_lines.append(line) |
|
99 |
else: |
|
100 |
previous_line = line |
|
101 |
break
|
|
102 |
log_breakdown[range_str] = log_lines |
|
103 |
||
104 |
return log_breakdown |
|
105 |
||
106 |
||
107 |
def log_line_within_start_range(line, range_start): |
|
1485.2.26
by Christopher Lee
Touch up and tests for logbreakdown |
108 |
datestamp = extract_date_from_line(line) |
1485.2.4
by Christopher Lee
Initial log chunking. |
109 |
try: |
110 |
ds = datetime.strptime(datestamp, dt_format) |
|
111 |
except ValueError: |
|
112 |
# Don't want an early entry point to the logging.
|
|
113 |
return False |
|
114 |
||
115 |
if ds > range_start or ds == range_start: |
|
116 |
return True |
|
117 |
return False |
|
118 |
||
119 |
||
1485.2.26
by Christopher Lee
Touch up and tests for logbreakdown |
120 |
def log_line_within_end_range(line, range_end): |
121 |
datestamp = extract_date_from_line(line) |
|
1485.2.4
by Christopher Lee
Initial log chunking. |
122 |
try: |
123 |
ds = datetime.strptime(datestamp, dt_format) |
|
124 |
except ValueError: |
|
1485.2.26
by Christopher Lee
Touch up and tests for logbreakdown |
125 |
# Fine to collect this line as the line doesn't start with a date and
|
126 |
# is thus a continuation or undated message.
|
|
1485.2.4
by Christopher Lee
Initial log chunking. |
127 |
return True |
128 |
||
1485.2.26
by Christopher Lee
Touch up and tests for logbreakdown |
129 |
if ds < range_end or ds == range_end: |
1485.2.4
by Christopher Lee
Initial log chunking. |
130 |
return True |
131 |
return False |
|
1485.2.26
by Christopher Lee
Touch up and tests for logbreakdown |
132 |
|
133 |
||
134 |
def extract_date_from_line(line): |
|
135 |
return " ".join(line.split()[0:2]) |