OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 """Extract UserMetrics "actions" strings from the Chrome source. | 7 """Extract UserMetrics "actions" strings from the Chrome source. |
8 | 8 |
9 This program generates the list of known actions we expect to see in the | 9 This program generates the list of known actions we expect to see in the |
10 user behavior logs. It walks the Chrome source, looking for calls to | 10 user behavior logs. It walks the Chrome source, looking for calls to |
11 UserMetrics functions, extracting actions and warning on improper calls, | 11 UserMetrics functions, extracting actions and warning on improper calls, |
12 as well as generating the lists of possible actions in situations where | 12 as well as generating the lists of possible actions in situations where |
13 there are many possible actions. | 13 there are many possible actions. |
14 | 14 |
15 See also: | 15 See also: |
16 base/metrics/user_metrics.h | 16 base/metrics/user_metrics.h |
17 http://wiki.corp.google.com/twiki/bin/view/Main/ChromeUserExperienceMetrics | |
18 | 17 |
19 After extracting all actions, the content will go through a pretty print | 18 After extracting all actions, the content will go through a pretty print |
20 function to make sure it's well formatted. If the file content needs to be | 19 function to make sure it's well formatted. If the file content needs to be |
21 changed, a window will be prompted asking for user's consent. The old version | 20 changed, a window will be prompted asking for user's consent. The old version |
22 will also be saved in a backup file. | 21 will also be saved in a backup file. |
23 """ | 22 """ |
24 | 23 |
25 __author__ = 'evanm (Evan Martin)' | 24 __author__ = 'evanm (Evan Martin)' |
26 | 25 |
27 from HTMLParser import HTMLParser | 26 from HTMLParser import HTMLParser |
28 import logging | 27 import logging |
29 import os | 28 import os |
30 import re | 29 import re |
31 import shutil | 30 import shutil |
32 import sys | 31 import sys |
33 from xml.dom import minidom | 32 from xml.dom import minidom |
34 | 33 |
35 import print_style | 34 import print_style |
36 | 35 |
37 sys.path.insert(1, os.path.join(sys.path[0], '..', '..', 'python')) | 36 sys.path.insert(1, os.path.join(sys.path[0], '..', '..', 'python')) |
38 from google import path_utils | 37 from google import path_utils |
39 | 38 |
40 # Import the metrics/common module for pretty print xml. | 39 # Import the metrics/common module for pretty print xml. |
41 sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common')) | 40 sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common')) |
42 import diff_util | 41 import diff_util |
43 import pretty_print_xml | 42 import pretty_print_xml |
44 | 43 |
44 USER_METRICS_ACTION_RE = re.compile(r'UserMetricsAction\(\s*(.+?)\)') | |
Ilya Sherman
2015/01/09 22:25:43
nit: I think it might be worth using the verbose r
Ilya Sherman
2015/01/09 22:25:44
It looks like you've changed the regexes quite a b
Alexei Svitkine (slow)
2015/01/12 19:58:24
I've re-added it now.
Alexei Svitkine (slow)
2015/01/12 19:58:24
Done.
| |
45 COMPUTED_ACTION_RE = re.compile(r'RecordComputedAction') | |
46 QUOTED_STRING_RE = re.compile(r'\"(.+?)\"') | |
47 | |
45 # Files that are known to use content::RecordComputedAction(), which means | 48 # Files that are known to use content::RecordComputedAction(), which means |
46 # they require special handling code in this script. | 49 # they require special handling code in this script. |
47 # To add a new file, add it to this list and add the appropriate logic to | 50 # To add a new file, add it to this list and add the appropriate logic to |
48 # generate the known actions to AddComputedActions() below. | 51 # generate the known actions to AddComputedActions() below. |
49 KNOWN_COMPUTED_USERS = ( | 52 KNOWN_COMPUTED_USERS = ( |
50 'back_forward_menu_model.cc', | 53 'back_forward_menu_model.cc', |
51 'options_page_view.cc', | 54 'options_page_view.cc', |
52 'render_view_host.cc', # called using webkit identifiers | 55 'render_view_host.cc', # called using webkit identifiers |
53 'user_metrics.cc', # method definition | 56 'user_metrics.cc', # method definition |
54 'new_tab_ui.cc', # most visited clicks 1-9 | 57 'new_tab_ui.cc', # most visited clicks 1-9 |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
403 actions.add('ConnectivityDiagnostics.LaunchSource.WebStore') | 406 actions.add('ConnectivityDiagnostics.LaunchSource.WebStore') |
404 actions.add('ConnectivityDiagnostics.UA.LogsShown') | 407 actions.add('ConnectivityDiagnostics.UA.LogsShown') |
405 actions.add('ConnectivityDiagnostics.UA.PassingTestsShown') | 408 actions.add('ConnectivityDiagnostics.UA.PassingTestsShown') |
406 actions.add('ConnectivityDiagnostics.UA.SettingsShown') | 409 actions.add('ConnectivityDiagnostics.UA.SettingsShown') |
407 actions.add('ConnectivityDiagnostics.UA.TestResultExpanded') | 410 actions.add('ConnectivityDiagnostics.UA.TestResultExpanded') |
408 actions.add('ConnectivityDiagnostics.UA.TestSuiteRun') | 411 actions.add('ConnectivityDiagnostics.UA.TestSuiteRun') |
409 | 412 |
410 # Actions sent by 'Ok Google' Hotwording. | 413 # Actions sent by 'Ok Google' Hotwording. |
411 actions.add('Hotword.HotwordTrigger') | 414 actions.add('Hotword.HotwordTrigger') |
412 | 415 |
416 def FindActionNames(contents, pos): | |
417 """Finds actions from the first UserMetricsAction() call in |contents|. | |
418 | |
419 Arguments: | |
420 contents: string to search through | |
421 pos: position in |contents| to start the search from | |
422 | |
423 Returns: | |
424 The list action names (strings) that was found. | |
Ilya Sherman
2015/01/09 22:25:43
Please update this -- it looks like there are two
Alexei Svitkine (slow)
2015/01/12 19:58:24
Done.
| |
425 """ | |
426 match = USER_METRICS_ACTION_RE.search(contents, pos=pos) | |
427 if not match: | |
428 return None, None | |
429 return QUOTED_STRING_RE.findall(match.group(1)), match.end() | |
430 | |
413 def GrepForActions(path, actions): | 431 def GrepForActions(path, actions): |
414 """Grep a source file for calls to UserMetrics functions. | 432 """Grep a source file for calls to UserMetrics functions. |
415 | 433 |
416 Arguments: | 434 Arguments: |
417 path: path to the file | 435 path: path to the file |
418 actions: set of actions to add to | 436 actions: set of actions to add to |
419 """ | 437 """ |
420 global number_of_files_total | 438 global number_of_files_total |
421 number_of_files_total = number_of_files_total + 1 | 439 number_of_files_total = number_of_files_total + 1 |
422 # we look for the UserMetricsAction structure constructor | 440 |
423 # this should be on one line | 441 contents = open(path).read() |
424 action_re = re.compile(r'[^a-zA-Z]UserMetricsAction\("([^"]*)') | 442 pos = 0 |
425 malformed_action_re = re.compile(r'[^a-zA-Z]UserMetricsAction\([^"]') | 443 while True: |
426 computed_action_re = re.compile(r'RecordComputedAction') | 444 action_names, pos = FindActionNames(contents, pos) |
445 if not action_names: | |
446 break | |
447 actions.update(action_names) | |
448 | |
427 line_number = 0 | 449 line_number = 0 |
428 for line in open(path): | 450 for line in open(path): |
429 line_number = line_number + 1 | 451 line_number = line_number + 1 |
430 match = action_re.search(line) | 452 if COMPUTED_ACTION_RE.search(line): |
431 if match: # Plain call to RecordAction | |
432 actions.add(match.group(1)) | |
433 elif malformed_action_re.search(line): | |
434 # Warn if this line is using RecordAction incorrectly. | |
435 print >>sys.stderr, ('WARNING: %s has malformed call to RecordAction' | |
436 ' at %d' % (path, line_number)) | |
437 elif computed_action_re.search(line): | |
438 # Warn if this file shouldn't be calling RecordComputedAction. | 453 # Warn if this file shouldn't be calling RecordComputedAction. |
439 if os.path.basename(path) not in KNOWN_COMPUTED_USERS: | 454 if os.path.basename(path) not in KNOWN_COMPUTED_USERS: |
440 print >>sys.stderr, ('WARNING: %s has RecordComputedAction at %d' % | 455 print >>sys.stderr, ('WARNING: %s has RecordComputedAction at %d' % |
441 (path, line_number)) | 456 (path, line_number)) |
442 | 457 |
443 class WebUIActionsParser(HTMLParser): | 458 class WebUIActionsParser(HTMLParser): |
444 """Parses an HTML file, looking for all tags with a 'metric' attribute. | 459 """Parses an HTML file, looking for all tags with a 'metric' attribute. |
445 Adds user actions corresponding to any metrics found. | 460 Adds user actions corresponding to any metrics found. |
446 | 461 |
447 Arguments: | 462 Arguments: |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
814 | 829 |
815 with open(actions_xml_path, 'wb') as f: | 830 with open(actions_xml_path, 'wb') as f: |
816 f.write(pretty) | 831 f.write(pretty) |
817 print ('Updated %s. Don\'t forget to add it to your changelist' % | 832 print ('Updated %s. Don\'t forget to add it to your changelist' % |
818 actions_xml_path) | 833 actions_xml_path) |
819 return 0 | 834 return 0 |
820 | 835 |
821 | 836 |
822 if '__main__' == __name__: | 837 if '__main__' == __name__: |
823 sys.exit(main(sys.argv)) | 838 sys.exit(main(sys.argv)) |
OLD | NEW |