Browse code

convert devstack from awk to outfilter

The complexity of the awk script was pretty high, and it would
be good to do it in summaries as well, which starts to get a bit
squirelly. Instead bring over the outfilter.py from grenade and
use it for the timestamping.

Any additional overhead from python should be offset from not
shelling out to date on every line of output.

(cherry picked from commit 62cb563ddc5f6923a9734a96d394ff2c27c320ca)

Conflicts:
stack.sh

Change-Id: Ic2b86ddba3e7f6520a0fd35599b01143936c6deb

Sean Dague authored on 2014/06/12 00:06:32
Showing 2 changed files
... ...
@@ -542,26 +542,15 @@ if [[ -n "$LOGFILE" ]]; then
542 542
     # Copy stdout to fd 3
543 543
     exec 3>&1
544 544
     if [[ "$VERBOSE" == "True" ]]; then
545
-        # Redirect stdout/stderr to tee to write the log file
546
-        exec 1> >( awk -v logfile=${LOGFILE} '
547
-                /((set \+o$)|xtrace)/ { next }
548
-                {
549
-                    cmd ="date +\"%Y-%m-%d %H:%M:%S.%3N | \""
550
-                    cmd | getline now
551
-                    close("date +\"%Y-%m-%d %H:%M:%S.%3N | \"")
552
-                    sub(/^/, now)
553
-                    print > logfile
554
-                    fflush(logfile)
555
-                    print
556
-                    fflush("")
557
-                }' ) 2>&1
558
-        # Set up a second fd for output
559
-        exec 6> >( tee "${SUMFILE}" )
545
+        # Set fd 1 and 2 to write the log file
546
+        exec 1> >( ./tools/outfilter.py -v -o "${LOGFILE}" ) 2>&1
547
+        # Set fd 6 to summary log file
548
+        exec 6> >( ./tools/outfilter.py -o "${SUMFILE}" )
560 549
     else
561 550
         # Set fd 1 and 2 to primary logfile
562
-        exec 1> "${LOGFILE}" 2>&1
551
+        exec 1> >( ./tools/outfilter.py -o "${LOGFILE}" ) 2>&1
563 552
         # Set fd 6 to summary logfile and stdout
564
-        exec 6> >( tee "${SUMFILE}" >&3 )
553
+        exec 6> >( ./tools/outfilter.py -v -o "${SUMFILE}" >&3 )
565 554
     fi
566 555
 
567 556
     echo_summary "stack.sh log $LOGFILE"
... ...
@@ -577,7 +566,7 @@ else
577 577
         exec 1>/dev/null 2>&1
578 578
     fi
579 579
     # Always send summary fd to original stdout
580
-    exec 6>&3
580
+    exec 6> >( ./tools/outfilter.py -v >&3 )
581 581
 fi
582 582
 
583 583
 # Set up logging of screen windows
584 584
new file mode 100755
... ...
@@ -0,0 +1,87 @@
0
+#!/usr/bin/env python
1
+#
2
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
3
+#
4
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+# not use this file except in compliance with the License. You may obtain
6
+# a copy of the License at
7
+#
8
+#      http://www.apache.org/licenses/LICENSE-2.0
9
+#
10
+# Unless required by applicable law or agreed to in writing, software
11
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+# License for the specific language governing permissions and limitations
14
+# under the License.
15
+
16
+# This is an output filter to filter and timestamp the logs from grenade and
17
+# devstack. Largely our awk filters got beyond the complexity level which were
18
+# sustainable, so this provides us much more control in a single place.
19
+#
20
+# The overhead of running python should be less than execing `date` a million
21
+# times during a run.
22
+
23
+import argparse
24
+import datetime
25
+import re
26
+import sys
27
+
28
+IGNORE_LINES = re.compile('(set \+o|xtrace)')
29
+HAS_DATE = re.compile('^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} \|')
30
+
31
+
32
+def get_options():
33
+    parser = argparse.ArgumentParser(
34
+        description='Filter output by devstack and friends')
35
+    parser.add_argument('-o', '--outfile',
36
+                        help='Output file for content',
37
+                        default=None)
38
+    parser.add_argument('-v', '--verbose', action='store_true',
39
+                        default=False)
40
+    return parser.parse_args()
41
+
42
+
43
+def skip_line(line):
44
+    """Should we skip this line."""
45
+    return IGNORE_LINES.search(line) is not None
46
+
47
+
48
+def main():
49
+    opts = get_options()
50
+    outfile = None
51
+    if opts.outfile:
52
+        outfile = open(opts.outfile, 'a', 0)
53
+
54
+    # otherwise fileinput reprocess args as files
55
+    sys.argv = []
56
+    while True:
57
+        line = sys.stdin.readline()
58
+        if not line:
59
+            return 0
60
+
61
+        # put skip lines here
62
+        if skip_line(line):
63
+            continue
64
+
65
+        # this prevents us from nesting date lines, because
66
+        # we'd like to pull this in directly in grenade and not double
67
+        # up on devstack lines
68
+        if HAS_DATE.search(line) is None:
69
+            now = datetime.datetime.utcnow()
70
+            line = ("%s | %s" % (
71
+                now.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3],
72
+                line))
73
+
74
+        if opts.verbose:
75
+            sys.stdout.write(line)
76
+            sys.stdout.flush()
77
+        if outfile:
78
+            outfile.write(line)
79
+            outfile.flush()
80
+
81
+
82
+if __name__ == '__main__':
83
+    try:
84
+        sys.exit(main())
85
+    except KeyboardInterrupt:
86
+        sys.exit(1)