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

Side by Side Diff: tools/metrics/actions/extract_actions.py

Issue 848453002: Improve script to find user actions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address comments. Created 5 years, 11 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 | « no previous file | tools/metrics/actions/extract_actions_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"""
45 [^a-zA-Z] # Preceded by a non-alphabetical character.
46 UserMetricsAction # Name of the function.
47 \( # Opening parenthesis.
48 \s* # Any amount of whitespace, including new lines.
49 (.+?) # A sequence of characters for the param.
Ilya Sherman 2015/01/12 22:17:19 Ah, I see now that "+?" means non-greedy. Okay, t
Alexei Svitkine (slow) 2015/01/13 18:06:17 Right. It will also catch base::UserMetricsAction(
Ilya Sherman 2015/01/13 23:05:37 I guess this is where we disagree -- I would much
Alexei Svitkine (slow) 2015/01/14 18:32:05 OK, I caved in and changed the code to not support
50 \) # Closing parenthesis.
51 """, re.VERBOSE)
52 COMPUTED_ACTION_RE = re.compile(r'RecordComputedAction')
53 QUOTED_STRING_RE = re.compile(r'\"(.+?)\"')
54
45 # Files that are known to use content::RecordComputedAction(), which means 55 # Files that are known to use content::RecordComputedAction(), which means
46 # they require special handling code in this script. 56 # 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 57 # To add a new file, add it to this list and add the appropriate logic to
48 # generate the known actions to AddComputedActions() below. 58 # generate the known actions to AddComputedActions() below.
49 KNOWN_COMPUTED_USERS = ( 59 KNOWN_COMPUTED_USERS = (
50 'back_forward_menu_model.cc', 60 'back_forward_menu_model.cc',
51 'options_page_view.cc', 61 'options_page_view.cc',
52 'render_view_host.cc', # called using webkit identifiers 62 'render_view_host.cc', # called using webkit identifiers
53 'user_metrics.cc', # method definition 63 'user_metrics.cc', # method definition
54 'new_tab_ui.cc', # most visited clicks 1-9 64 'new_tab_ui.cc', # most visited clicks 1-9
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 actions.add('ConnectivityDiagnostics.LaunchSource.WebStore') 413 actions.add('ConnectivityDiagnostics.LaunchSource.WebStore')
404 actions.add('ConnectivityDiagnostics.UA.LogsShown') 414 actions.add('ConnectivityDiagnostics.UA.LogsShown')
405 actions.add('ConnectivityDiagnostics.UA.PassingTestsShown') 415 actions.add('ConnectivityDiagnostics.UA.PassingTestsShown')
406 actions.add('ConnectivityDiagnostics.UA.SettingsShown') 416 actions.add('ConnectivityDiagnostics.UA.SettingsShown')
407 actions.add('ConnectivityDiagnostics.UA.TestResultExpanded') 417 actions.add('ConnectivityDiagnostics.UA.TestResultExpanded')
408 actions.add('ConnectivityDiagnostics.UA.TestSuiteRun') 418 actions.add('ConnectivityDiagnostics.UA.TestSuiteRun')
409 419
410 # Actions sent by 'Ok Google' Hotwording. 420 # Actions sent by 'Ok Google' Hotwording.
411 actions.add('Hotword.HotwordTrigger') 421 actions.add('Hotword.HotwordTrigger')
412 422
423 def FindActionNames(contents, pos):
424 """Finds actions from the first UserMetricsAction() call in |contents|.
425
426 Arguments:
427 contents: string to search through
428 pos: position in |contents| to start the search from
429
430 Returns:
431 A tuple consisting of:
432 - The list action names (strings) that was found.
Ilya Sherman 2015/01/12 22:17:19 nit: "list action names" -> "list of action names"
Alexei Svitkine (slow) 2015/01/13 18:06:17 Done.
433 - The index in |content| indicating the end of the matching string.
434 """
435 match = USER_METRICS_ACTION_RE.search(contents, pos=pos)
436 if not match:
437 return None, None
438 return QUOTED_STRING_RE.search(match.group(1)), match.end()
439
413 def GrepForActions(path, actions): 440 def GrepForActions(path, actions):
414 """Grep a source file for calls to UserMetrics functions. 441 """Grep a source file for calls to UserMetrics functions.
415 442
416 Arguments: 443 Arguments:
417 path: path to the file 444 path: path to the file
418 actions: set of actions to add to 445 actions: set of actions to add to
419 """ 446 """
420 global number_of_files_total 447 global number_of_files_total
421 number_of_files_total = number_of_files_total + 1 448 number_of_files_total = number_of_files_total + 1
422 # we look for the UserMetricsAction structure constructor 449
423 # this should be on one line 450 contents = open(path).read()
424 action_re = re.compile(r'[^a-zA-Z]UserMetricsAction\("([^"]*)') 451 pos = 0
425 malformed_action_re = re.compile(r'[^a-zA-Z]UserMetricsAction\([^"]') 452 while True:
426 computed_action_re = re.compile(r'RecordComputedAction') 453 action_names, pos = FindActionNames(contents, pos)
454 if not action_names:
455 break
456 actions.update(action_names)
457
427 line_number = 0 458 line_number = 0
428 for line in open(path): 459 for line in open(path):
429 line_number = line_number + 1 460 line_number = line_number + 1
430 match = action_re.search(line) 461 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. 462 # Warn if this file shouldn't be calling RecordComputedAction.
439 if os.path.basename(path) not in KNOWN_COMPUTED_USERS: 463 if os.path.basename(path) not in KNOWN_COMPUTED_USERS:
440 print >>sys.stderr, ('WARNING: %s has RecordComputedAction at %d' % 464 print >>sys.stderr, ('WARNING: %s has RecordComputedAction at %d' %
441 (path, line_number)) 465 (path, line_number))
442 466
443 class WebUIActionsParser(HTMLParser): 467 class WebUIActionsParser(HTMLParser):
444 """Parses an HTML file, looking for all tags with a 'metric' attribute. 468 """Parses an HTML file, looking for all tags with a 'metric' attribute.
445 Adds user actions corresponding to any metrics found. 469 Adds user actions corresponding to any metrics found.
446 470
447 Arguments: 471 Arguments:
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after
814 838
815 with open(actions_xml_path, 'wb') as f: 839 with open(actions_xml_path, 'wb') as f:
816 f.write(pretty) 840 f.write(pretty)
817 print ('Updated %s. Don\'t forget to add it to your changelist' % 841 print ('Updated %s. Don\'t forget to add it to your changelist' %
818 actions_xml_path) 842 actions_xml_path)
819 return 0 843 return 0
820 844
821 845
822 if '__main__' == __name__: 846 if '__main__' == __name__:
823 sys.exit(main(sys.argv)) 847 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « no previous file | tools/metrics/actions/extract_actions_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698