Skip to content

Commit a6e322a

Browse files
authored
[storyteller] Enhance the storyteller utility (sonic-net#1400)
- Sanitize user inputs - Add support for specifying a time period - Add basic ACL regex Signed-off-by: Danny Allen <[email protected]>
1 parent 5cff775 commit a6e322a

File tree

1 file changed

+40
-15
lines changed

1 file changed

+40
-15
lines changed

scripts/storyteller

+40-15
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
#!/usr/bin/env python3
22

3-
'''
4-
Story Teller:
5-
Utility to help analyze log for certain sequence of events.
6-
e.g.: reboot (including warm/fast reboot), interface flapping, etc.
3+
'''Story Teller: Utility to help analyze log for certain sequence of events.
4+
5+
e.g.: reboot (including warm/fast reboot), interface flapping, etc.
76
'''
87

98
import argparse
9+
import os
1010
import subprocess
11+
import sys
12+
13+
from shlex import quote
1114

1215
regex_dict = {
16+
'acl' : r'acl\|ACL\|Acl',
1317
'bgp' : 'bgpcfgd',
14-
'crash' : 'what\|unexpected exception\|notify_OA_about_syncd_exception\|SIG\|not expected',
15-
'interface' : 'updatePortOperStatus\|Configure .* to',
16-
'lag' : 'link becomes\|addLag',
17-
'reboot' : 'BOOT\|rc.local\|old_config\|minigraph.xml\|Rebooting\|reboot\|executeOperationsOnAsic\|getAsicView\|dumpVidToAsicOperatioId\|neighbor_adv\|Pausing\|shutdown\|warm',
18-
'service' : 'Starting\|Stopping\|Started\|Stopped',
18+
'crash' : r'what\|unexpected exception\|notify_OA_about_syncd_exception\|SIG\|not expected',
19+
'interface' : r'updatePortOperStatus\|Configure .* to',
20+
'lag' : r'link becomes\|addLag',
21+
'reboot' : r'BOOT\|rc.local\|old_config\|minigraph.xml\|Rebooting\|reboot\|executeOperationsOnAsic\|getAsicView\|dumpVidToAsicOperatioId\|neighbor_adv\|Pausing\|shutdown\|warm',
22+
'service' : r'Starting\|Stopping\|Started\|Stopped',
1923
}
2024

2125

26+
reference_file = '/tmp/storyteller_time_reference'
27+
2228
def exec_cmd(cmd):
2329
# Use universal_newlines (instead of text) so that this tool can work with any python versions.
2430
out = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, universal_newlines=True)
@@ -40,13 +46,12 @@ def build_options(after=0, before=0, context=0):
4046

4147
def find_log(logpath, log, regex, after=0, before=0, context=0):
4248
options = build_options(after, before, context)
43-
cmd = 'ls -rt {}/{}* | xargs zgrep -a {} "{}"'.format(logpath, log, options, regex)
49+
cmd = 'find -L {}/{}* -newer {} | xargs zgrep -a {} "{}"'.format(logpath, log, reference_file, options, regex)
4450
_, out, _ = exec_cmd(cmd)
4551
'''
4652
Opportunity to improve:
4753
output (out) can be split to lines and send to a filter to
4854
decide if a line should be printed out or not.
49-
e.g. limited to a certain time span.
5055
'''
5156
print(out)
5257

@@ -57,10 +62,22 @@ def build_regex(category):
5762
# if c is not found, add c to grep list directly
5863
regex.append(regex_dict[c] if c in regex_dict else c)
5964

60-
return '\|'.join(x for x in regex)
65+
return r'\|'.join(x for x in regex)
66+
67+
68+
def configure_time_filter(since):
69+
ret_code, _, _ = exec_cmd('date --date {}'.format(since))
70+
if ret_code:
71+
print('invalid date "{}"'.format(since))
72+
sys.exit(1)
73+
74+
exec_cmd('touch --date "{}" {}'.format(since, reference_file))
6175

6276

6377
def main():
78+
if os.geteuid() != 0:
79+
exit("Root privileges are required for this operation")
80+
6481
parser = argparse.ArgumentParser(description='Story Teller')
6582

6683
parser.add_argument('-l', '--log', help='log file prefix, e.g. syslog; default: syslog',
@@ -75,13 +92,21 @@ def main():
7592
type=int, required=False, default=0)
7693
parser.add_argument('-C', '--context', help='Show N lines before and after match',
7794
type=int, required=False, default=0)
95+
parser.add_argument('-S', '--since', help='Filter logs since the given date',
96+
type=str, required=False, default="@0")
7897

7998
args = parser.parse_args()
8099

81-
log = args.log
82-
reg = build_regex(args.category)
100+
# sanitize all string inputs
101+
log = quote(args.log)
102+
log_path = quote(args.logpath)
103+
category = quote(args.category)
104+
since = quote(args.since)
105+
106+
reg = build_regex(category)
107+
configure_time_filter(since)
83108

84-
find_log(args.logpath, log, reg, args.after, args.before, args.context)
109+
find_log(log_path, log, reg, args.after, args.before, args.context)
85110

86111

87112
if __name__ == '__main__':

0 commit comments

Comments
 (0)