~wesley-wiedenmeier/curtin/vmtest-webhook-delay

« back to all changes in this revision

Viewing changes to tools/curtin-log-print

mergeĀ fromĀ test-bed

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python3
 
2
#   Copyright (C) 2016 Canonical Ltd.
 
3
#
 
4
#   Author: Ryan Harper <ryan.harper@canonical.com>
 
5
#
 
6
#   Curtin is free software: you can redistribute it and/or modify it under
 
7
#   the terms of the GNU Affero General Public License as published by the
 
8
#   Free Software Foundation, either version 3 of the License, or (at your
 
9
#   option) any later version.
 
10
#
 
11
#   Curtin is distributed in the hope that it will be useful, but WITHOUT ANY
 
12
#   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
13
#   FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
 
14
#   more details.
 
15
#
 
16
#   You should have received a copy of the GNU Affero General Public License
 
17
#   along with Curtin.  If not, see <http://www.gnu.org/licenses/>.
 
18
import argparse
 
19
import datetime
 
20
import json
 
21
import sys
 
22
 
 
23
 
 
24
#  An event:
 
25
'''
 
26
{
 
27
        "description": "executing late commands",
 
28
        "event_type": "start",
 
29
        "level": "INFO",
 
30
        "name": "cmd-install/stage-late"
 
31
        "origin": "curtin",
 
32
        "timestamp": 1461164249.1590767,
 
33
},
 
34
 
 
35
    {
 
36
        "description": "executing late commands",
 
37
        "event_type": "finish",
 
38
        "level": "INFO",
 
39
        "name": "cmd-install/stage-late",
 
40
        "origin": "curtin",
 
41
        "result": "SUCCESS",
 
42
        "timestamp": 1461164249.1590767
 
43
    }
 
44
 
 
45
'''
 
46
format_key = {
 
47
    '%d': 'delta',
 
48
    '%D': 'description',
 
49
    '%e': 'event_type',
 
50
    '%l': 'level',
 
51
    '%n': 'name',
 
52
    '%o': 'origin',
 
53
    '%r': 'result',
 
54
    '%t': 'timestamp',
 
55
}
 
56
 
 
57
formatting_help = " ".join(["{}: {}".format(k.replace('%', '%%'), v)
 
58
                           for k, v in format_key.items()])
 
59
 
 
60
 
 
61
def format_record(msg, event):
 
62
    for i, j in format_key.items():
 
63
        if i in msg:
 
64
            msg = msg.replace(i, "{%s}" % j)
 
65
    return msg.format(**event)
 
66
 
 
67
 
 
68
def generate_records(j, blame_sort=False, print_format="%d seconds in %D"):
 
69
    records = []
 
70
    timestamps = {}
 
71
    total_time = 0
 
72
    for event in j:
 
73
        name = event.get('name')
 
74
        if event['event_type'] == 'start':
 
75
            timestamps[name] = {'start': event['timestamp']}
 
76
        else:
 
77
            timestamps[name].update({'finish': event['timestamp']})
 
78
            start = datetime.datetime.utcfromtimestamp(
 
79
                timestamps[name]['start'])
 
80
            end = datetime.datetime.utcfromtimestamp(
 
81
                timestamps[name]['finish'])
 
82
            delta = end - start
 
83
            total_time += delta.total_seconds()
 
84
            event['delta'] = "{:08.5f}".format(delta.total_seconds())
 
85
            records.append(format_record(print_format, event))
 
86
 
 
87
    records.append(' ---\n%3.5f seconds total time' % total_time)
 
88
    return records
 
89
 
 
90
 
 
91
def main():
 
92
    parser = argparse.ArgumentParser(
 
93
        description='curtin-print-log - pretty print and sort curtin logs',
 
94
        prog='curtin-print-log')
 
95
    parser.add_argument('--blame', action='store_true',
 
96
                        default=False,
 
97
                        dest='blame_sort',
 
98
                        help='sort events by total time.')
 
99
    parser.add_argument('--format', action='store',
 
100
                        dest='print_format',
 
101
                        default='%d seconds in %D',
 
102
                        help='specify formatting of output. ' +
 
103
                        formatting_help)
 
104
    parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
 
105
                        help='Path to log to parse. Use - for stdin')
 
106
 
 
107
    opts = parser.parse_args(sys.argv[1:])
 
108
    if not opts.infile:
 
109
        parser.print_help()
 
110
        sys.exit(1)
 
111
 
 
112
    try:
 
113
        j = json.load(opts.infile)
 
114
    except json.JSONDecodeError:
 
115
        print("Input must be valid JSON")
 
116
        sys.exit(1)
 
117
 
 
118
    records = generate_records(j, blame_sort=opts.blame_sort,
 
119
                               print_format=opts.print_format)
 
120
    summary = []
 
121
    if opts.blame_sort is True:
 
122
        summary = records[-1:]
 
123
        records = sorted(records[:-1], reverse=True)
 
124
 
 
125
    print("\n".join(records + summary))
 
126
 
 
127
 
 
128
if __name__ == '__main__':
 
129
    main()