Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Side by Side Diff: infra/tools/metric_tool/metric_tool.py

Issue 1368583005: Create metric_tool to deal with metric definitions (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Rebase Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « infra/tools/metric_tool/__main__.py ('k') | infra/tools/metric_tool/test/__init__.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4 """Main implementation of metric_tool."""
5
6 import ast
7 import os
8 import logging
9
10
11 # https://chromium.googlesource.com/infra/infra/+/master/infra_libs/logs/README. md
12 LOGGER = logging.getLogger(__name__)
13
14 METRICS_NAMES = set(('StringMetric', 'BooleanMetric',
15 'CounterMetric', 'GaugeMetric', 'CumulativeMetric',
16 'FloatMetric', 'CumulativeDistributionMetric',
17 'NonCumulativeDistributionMetric'))
18
19
20 def extract_metrics_descriptions(filepath):
21 """Parse a python file and return all metrics descriptions it can find.
22
23 A metric description is the value of the 'description' keyword passed to a
24 metric definition (classes deriving from ts_mon.Metric)
25
26 Args:
27 filepath (str): path to a Python file.
28
29 Returns:
30 description (list of tuples): each tuple being
31 (metric name, description string). Metric name is 'DYNAMIC' it something
32 different than a static string is used in the metric creation.
33 If a metric is instanciated without a description, return None.
34 """
35 descriptions = []
36 try:
37 with open(filepath, 'r') as f:
38 content = f.read() # pragma: no branch
39 except IOError:
40 return descriptions
41
42 try:
43 root = ast.parse(content)
44 except SyntaxError: # just ignore invalid / python3 files.
45 return descriptions
46
47 for node in ast.walk(root):
48 if not isinstance(node, ast.Call):
49 continue
50
51 # Look for metrics definitions
52 calls = []
53 if isinstance(node.func, ast.Name):
54 if node.func.id in METRICS_NAMES:
55 LOGGER.debug('Method %s found line %d', node.func.id, node.func.lineno)
56 calls.append(node)
57 elif isinstance(node.func, ast.Attribute): # pragma: no branch
58 if node.func.attr in METRICS_NAMES:
59 LOGGER.debug('Method %s found line %d',
60 node.func.attr, node.func.lineno)
61 calls.append(node)
62
63 # Extract parameters from function call
64 for fcall in calls:
65 # Metric name
66 metric_name = 'DYNAMIC'
67 if fcall.args and isinstance(fcall.args[0], ast.Str):
68 metric_name = fcall.args[0].s
69
70 # Getting descriptions
71 description = None
72 for keyword in fcall.keywords:
73 if keyword.arg == 'description' and isinstance(keyword.value, ast.Str):
74 description = keyword.value.s
75
76 descriptions.append((filepath, fcall.lineno, metric_name, description))
77
78 return descriptions
79
80
81 def main(path):
82 """Recursively walk a directory structure and print metrics documentation.
83
84 For all instanciated metrics in any Python file found under the directory
85 passed as argument, if a 'description' keyword is provided print it
86 alongside the metric name.
87
88 Args:
89 path (str): directory.
90 """
91 documented = []
92 non_documented = []
93
94 for (dirpath, _, filenames) in os.walk(path):
95 for filename in filenames:
96
97 if (not filename.endswith('.py') # pragma: no branch
98 or filename.endswith('_test.py')):
99 continue # pragma: no cover
100
101 full_filename = os.path.join(dirpath, filename)
102 LOGGER.debug('Scanning file %s', full_filename)
103 descriptions = extract_metrics_descriptions(full_filename)
104
105 for description in descriptions:
106 # TODO(pgervais): use namedtuple here instead
107 if description[3]:
108 documented.append(description)
109 else:
110 non_documented.append(description)
111
112 if documented: # pragma: no branch
113 print('\nDocumented metrics found:')
114 for description in documented:
115 print('/chrome/infra/{2} \t"{3}" at {0}:{1}'.format(*description))
116
117 if non_documented: # pragma: no branch
118 print('\nUndocumented metrics found:')
119 for description in non_documented:
120 print('/chrome/infra/{2} \t at {0}:{1}'.format(*description))
OLDNEW
« no previous file with comments | « infra/tools/metric_tool/__main__.py ('k') | infra/tools/metric_tool/test/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698