Skip to content

Commit 9717a60

Browse files
Add extract_logs action to concatenate logs after log rotate (#471)
1 parent 578f1a0 commit 9717a60

2 files changed

Lines changed: 259 additions & 0 deletions

File tree

ansible/library/extract_log.py

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
#!/usr/bin/python
2+
3+
DOCUMENTATION = '''
4+
module: extract_log
5+
version_added: "1.0"
6+
short_description: Unrotate logs and extract information starting from a row with predefined string
7+
description: The module scans the 'directory' in search of files which filenames start with 'file_prefix'.
8+
The found files are ungzipped and combined together in the rotation order. After that all lines after
9+
'start_string' are copied into a file with name 'target_filename'.
10+
11+
Options:
12+
- option-name: directory
13+
description: a name of a directory with target log files
14+
required: True
15+
Default: None
16+
17+
- option-name: file_prefix
18+
description: a prefix of target log files
19+
required: True
20+
Default: None
21+
22+
- option-name: start_string
23+
description: a string which last copy is used as a start tag for extracting log information
24+
required: True
25+
Default: None
26+
27+
- option-name: target_filename
28+
description: a filename of a file where the extracted lines will be saved
29+
required: True
30+
Default: None
31+
32+
'''
33+
34+
EXAMPLES = '''
35+
- name: Extract all syslog entries since the last reboot
36+
extract_log:
37+
directory: '/var/log'
38+
file_prefix: 'syslog'
39+
start_string: 'Initializing cgroup subsys cpuset'
40+
target_filename: '/tmp/syslog'
41+
42+
- name: Copy the exctracted syslog entries to the local machine
43+
fetch:
44+
src: '/tmp/syslog'
45+
dest: '/tmp/'
46+
flat: yes
47+
48+
- name: Extract all sairedis.rec entries since the last reboot
49+
extract_log:
50+
directory: '/var/log/swss'
51+
file_prefix: 'sairedis.rec'
52+
start_string: 'recording on:'
53+
target_filename: '/tmp/sairedis.rec'
54+
55+
- name: Copy the exctracted sairedis.rec entries to the local machine
56+
fetch:
57+
src: '/tmp/sairedis.rec'
58+
dest: '/tmp/'
59+
flat: yes
60+
61+
- name: Extract all swss.rec entries since the last reboot
62+
extract_log:
63+
directory: '/var/log/swss'
64+
file_prefix: 'swss.rec'
65+
start_string: 'recording started'
66+
target_filename: '/tmp/swss.rec'
67+
68+
- name: Copy the exctracted swss.rec entries to the local machine
69+
fetch:
70+
src: '/tmp/swss.rec'
71+
dest: '/tmp/'
72+
flat: yes
73+
'''
74+
75+
import os
76+
import gzip
77+
import re
78+
import sys
79+
from datetime import datetime
80+
from ansible.module_utils.basic import *
81+
82+
from pprint import pprint
83+
84+
85+
def extract_line(directory, filename, target_string):
86+
path = os.path.join(directory, filename)
87+
file = None
88+
if 'gz' in path:
89+
file = gzip.GzipFile(path)
90+
else:
91+
file = open(path)
92+
result = None
93+
with file:
94+
result = [(filename, line) for line in file if target_string in line]
95+
return result
96+
97+
98+
def list_files(directory, prefixname):
99+
return [filename for filename in os.listdir(directory) if filename.startswith(prefixname)]
100+
101+
102+
def extract_number(s):
103+
ns = re.findall(r'\d+', s)
104+
if len(ns) == 0:
105+
return 0
106+
else:
107+
return int(ns[0])
108+
109+
110+
def convert_date(s):
111+
str_date = re.findall(r'^\S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}\.?\d*', s)[0]
112+
dt = None
113+
try:
114+
dt = datetime.strptime(str_date, '%b %d %X.%f')
115+
except ValueError:
116+
pass
117+
if dt is None:
118+
dt = datetime.strptime(str_date, '%b %d %X')
119+
120+
return dt
121+
122+
123+
def comparator(l, r):
124+
nl = extract_number(l[0])
125+
nr = extract_number(r[0])
126+
if nl == nr:
127+
dl = convert_date(l[1])
128+
dr = convert_date(r[1])
129+
if dl == dr:
130+
return 0
131+
elif dl < dr:
132+
return -1
133+
else:
134+
return 1
135+
elif nl > nr:
136+
return -1
137+
else:
138+
return 1
139+
140+
141+
def filename_comparator(l, r):
142+
nl = extract_number(l)
143+
nr = extract_number(r)
144+
if nl == nr:
145+
return 0
146+
elif nl > nr:
147+
return -1
148+
else:
149+
return 1
150+
151+
152+
def extract_latest_line_with_string(directory, filenames, start_string):
153+
target_lines = []
154+
for filename in filenames:
155+
target_lines.extend(extract_line(directory, filename, start_string))
156+
157+
sorted_target_lines = sorted(target_lines, cmp=comparator)
158+
159+
return sorted_target_lines[-1]
160+
161+
162+
def calculate_files_to_copy(filenames, file_with_latest_line):
163+
sorted_filenames = sorted(filenames, cmp=filename_comparator)
164+
files_to_copy = []
165+
do_copy = False
166+
for filename in sorted_filenames:
167+
if filename == file_with_latest_line:
168+
do_copy = True
169+
if do_copy:
170+
files_to_copy.append(filename)
171+
172+
return files_to_copy
173+
174+
175+
def combine_logs_and_save(directory, filenames, start_string, target_filename):
176+
do_copy = False
177+
with open(target_filename, 'w') as fp:
178+
for filename in filenames:
179+
path = os.path.join(directory, filename)
180+
file = None
181+
if 'gz' in path:
182+
file = gzip.GzipFile(path)
183+
else:
184+
file = open(path)
185+
with file:
186+
for line in file:
187+
if line == start_string:
188+
do_copy = True
189+
if do_copy:
190+
fp.write(line)
191+
192+
193+
def extract_log(directory, prefixname, target_string, target_filename):
194+
filenames = list_files(directory, prefixname)
195+
file_with_latest_line, latest_line = extract_latest_line_with_string(directory, filenames, target_string)
196+
files_to_copy = calculate_files_to_copy(filenames, file_with_latest_line)
197+
combine_logs_and_save(directory, files_to_copy, latest_line, target_filename)
198+
199+
200+
def main():
201+
module = AnsibleModule(
202+
argument_spec=dict(
203+
directory=dict(required=True, type='str'),
204+
file_prefix=dict(required=True, type='str'),
205+
start_string=dict(required=True, type='str'),
206+
target_filename=dict(required=True, type='str'),
207+
),
208+
supports_check_mode=False)
209+
210+
p = module.params;
211+
try:
212+
extract_log(p['directory'], p['file_prefix'], p['start_string'], p['target_filename'])
213+
except:
214+
err = str(sys.exc_info())
215+
module.fail_json(msg="Error: %s" % err)
216+
module.exit_json()
217+
218+
219+
if __name__ == '__main__':
220+
main()

ansible/roles/test/tasks/fast-reboot.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,42 @@
134134
- name: Remove existing ip from ptf host
135135
script: roles/test/files/helpers/remove_ip.sh
136136
delegate_to: "{{ ptf_host }}"
137+
138+
- name: Extract all syslog entries since the last reboot
139+
extract_log:
140+
directory: '/var/log'
141+
file_prefix: 'syslog'
142+
start_string: 'Initializing cgroup subsys cpuset'
143+
target_filename: '/tmp/syslog'
144+
145+
- name: Copy the exctracted syslog entries to the local machine
146+
fetch:
147+
src: '/tmp/syslog'
148+
dest: '/tmp/'
149+
flat: yes
150+
151+
- name: Extract all sairedis.rec entries since the last reboot
152+
extract_log:
153+
directory: '/var/log/swss'
154+
file_prefix: 'sairedis.rec'
155+
start_string: 'recording on:'
156+
target_filename: '/tmp/sairedis.rec'
157+
158+
- name: Copy the exctracted sairedis.rec entries to the local machine
159+
fetch:
160+
src: '/tmp/sairedis.rec'
161+
dest: '/tmp/'
162+
flat: yes
163+
164+
- name: Extract all swss.rec entries since the last reboot
165+
extract_log:
166+
directory: '/var/log/swss'
167+
file_prefix: 'swss.rec'
168+
start_string: 'recording started'
169+
target_filename: '/tmp/swss.rec'
170+
171+
- name: Copy the exctracted swss.rec entries to the local machine
172+
fetch:
173+
src: '/tmp/swss.rec'
174+
dest: '/tmp/'
175+
flat: yes

0 commit comments

Comments
 (0)