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
... ...
@@ -497,23 +497,15 @@ if [[ -n "$LOGFILE" ]]; then
497 497
     # Copy stdout to fd 3
498 498
     exec 3>&1
499 499
     if [[ "$VERBOSE" == "True" ]]; then
500
-        # Redirect stdout/stderr to tee to write the log file
501
-        exec 1> >( awk '
502
-                {
503
-                    cmd ="date +\"%Y-%m-%d %H:%M:%S.%3N | \""
504
-                    cmd | getline now
505
-                    close("date +\"%Y-%m-%d %H:%M:%S.%3N | \"")
506
-                    sub(/^/, now)
507
-                    print
508
-                    fflush()
509
-                }' | tee "${LOGFILE}" ) 2>&1
510
-        # Set up a second fd for output
511
-        exec 6> >( tee "${SUMFILE}" )
500
+        # Set fd 1 and 2 to write the log file
501
+        exec 1> >( ./tools/outfilter.py -v -o "${LOGFILE}" ) 2>&1
502
+        # Set fd 6 to summary log file
503
+        exec 6> >( ./tools/outfilter.py -o "${SUMFILE}" )
512 504
     else
513 505
         # Set fd 1 and 2 to primary logfile
514
-        exec 1> "${LOGFILE}" 2>&1
506
+        exec 1> >( ./tools/outfilter.py -o "${LOGFILE}" ) 2>&1
515 507
         # Set fd 6 to summary logfile and stdout
516
-        exec 6> >( tee "${SUMFILE}" >&3 )
508
+        exec 6> >( ./tools/outfilter.py -v -o "${SUMFILE}" >&3 )
517 509
     fi
518 510
 
519 511
     echo_summary "stack.sh log $LOGFILE"
... ...
@@ -529,7 +521,7 @@ else
529 529
         exec 1>/dev/null 2>&1
530 530
     fi
531 531
     # Always send summary fd to original stdout
532
-    exec 6>&3
532
+    exec 6> >( ./tools/outfilter.py -v >&3 )
533 533
 fi
534 534
 
535 535
 # Set up logging of screen windows
536 536
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)