Add clearcut metrics tool to log start event
- Import asuite_cc_client lib to log start and exit event.
- By default silence root logger's stream handler since 3p libs
(asuite_cc_client) may initial root logger no matter what level
we're using.
- Remove workaround for oauth2client unexpceted warning message.
Bug: 131658799
Bug: 112803893
Test: atest acloud_test --host &
m acloud & any acloud-dev commands & check the clearcut dashboard
Change-Id: I84ade2863d2f29b1122729f5109f665b6c4e4ac4
diff --git a/Android.bp b/Android.bp
index 65b7b79..ef42197 100644
--- a/Android.bp
+++ b/Android.bp
@@ -73,6 +73,7 @@
"public/*_test.py",
"public/actions/*_test.py",
"internal/lib/*_test.py",
+ "metrics/*.py",
],
libs: [
"acloud_create",
@@ -83,6 +84,7 @@
"acloud_proto",
"acloud_public",
"acloud_setup",
+ "asuite_cc_client",
"py-apitools",
"py-dateutil",
"py-google-api-python-client",
@@ -180,6 +182,7 @@
"metrics/*.py",
],
libs: [
+ "asuite_cc_client",
"asuite_metrics",
],
}
diff --git a/create/create.py b/create/create.py
index 0769593..9dfba02 100644
--- a/create/create.py
+++ b/create/create.py
@@ -183,7 +183,7 @@
setup.Run(args)
else:
print("Please run '#acloud setup' so we can get your host setup")
- sys.exit()
+ sys.exit(constants.EXIT_BY_USER)
def PreRunCheck(args):
diff --git a/create/local_image_local_instance.py b/create/local_image_local_instance.py
index 147cd3a..8850329 100644
--- a/create/local_image_local_instance.py
+++ b/create/local_image_local_instance.py
@@ -168,8 +168,7 @@
delete.CleanupSSVncviewer(constants.CF_TARGET_VNC_PORT)
else:
- print("Exiting out")
- sys.exit()
+ sys.exit(constants.EXIT_BY_USER)
self._LaunchCvd(cmd)
@staticmethod
diff --git a/create/remote_image_local_instance.py b/create/remote_image_local_instance.py
index 319fa08..08f0255 100644
--- a/create/remote_image_local_instance.py
+++ b/create/remote_image_local_instance.py
@@ -222,8 +222,7 @@
if answer.lower() == "y":
os.makedirs(download_dir)
else:
- print("Exiting acloud!")
- sys.exit()
+ sys.exit(constants.EXIT_BY_USER)
stat = os.statvfs(download_dir)
available_space = stat.f_bavail*stat.f_bsize/(1024)**3
@@ -233,7 +232,6 @@
"available_space":available_space,
"required_space":_REQUIRED_SPACE})
if download_dir.lower() == "q":
- print("Exiting acloud!")
- sys.exit()
+ sys.exit(constants.EXIT_BY_USER)
else:
return download_dir
diff --git a/internal/constants.py b/internal/constants.py
index b5cb4f2..c5e064b 100755
--- a/internal/constants.py
+++ b/internal/constants.py
@@ -143,3 +143,6 @@
LOCAL_INS_NAME = "local-instance"
TEMP_ARTIFACTS_FOLDER = "acloud_image_artifacts"
+TOOL_NAME = "acloud"
+EXIT_BY_USER = 1
+EXIT_BY_ERROR = -99
diff --git a/internal/lib/utils.py b/internal/lib/utils.py
index 6f527a3..0b496d1 100755
--- a/internal/lib/utils.py
+++ b/internal/lib/utils.py
@@ -874,8 +874,7 @@
continue
# Filter out choices
if choice == 0:
- print("Exiting acloud.")
- sys.exit()
+ sys.exit(constants.EXIT_BY_USER)
if enable_choose_all and choice == max_choice:
return answer_list
if choice < 0 or choice > max_choice:
diff --git a/metrics/metrics.py b/metrics/metrics.py
index 5ec7027..1d8b1a3 100644
--- a/metrics/metrics.py
+++ b/metrics/metrics.py
@@ -26,9 +26,24 @@
logger = logging.getLogger(__name__)
+# pylint: disable=broad-except
+def LogUsage(argv):
+ """Log acloud start event.
-def LogUsage():
- """Log acloud run."""
+ Log acloud start event and the usage, following are the data we log:
+ - tool_name: All asuite tools are storing event in the same database. This
+ property is provided to distinguish different tools.
+ - command_line: Log all command arguments.
+ - test_references: Should be a list, we record the acloud sub-command.
+ e.g. create/delete/reconnect/..etc. We could use this property as filter
+ criteria to speed up query time.
+ - cwd: User's current working directory.
+ - os: The platform that users are working at.
+
+ Args:
+ argv: A list of system arguments.
+ """
+ # TODO(b131867764): We could remove this metics tool after we apply clearcut.
try:
from asuite import asuite_metrics
asuite_metrics.log_event(_METRICS_URL, dummy_key_fallback=False,
@@ -36,8 +51,19 @@
except ImportError:
logger.debug("No metrics recorder available, not sending metrics.")
+ #Log start event via clearcut tool.
+ try:
+ from asuite import atest_utils
+ from asuite.metrics import metrics_utils
+ atest_utils.print_data_collection_notice()
+ metrics_utils.send_start_event(tool_name=constants.TOOL_NAME,
+ command_line=' '.join(argv),
+ test_references=[argv[0]])
+ except Exception as e:
+ logger.debug("Failed to send start event:%s", str(e))
+#TODO(b131867764): We could remove this metics tool after we apply clearcut.
def _GetLdap():
"""Return string email username for valid domains only, None otherwise."""
try:
@@ -52,3 +78,23 @@
except Exception as e:
logger.debug("error retrieving email: %s", e)
return None
+
+# pylint: disable=broad-except
+def LogExitEvent(exit_code, stacktrace="", logs=""):
+ """Log acloud exit event.
+
+ A start event should followed by an exit event to calculate the consuming
+ time. This function will be run at the end of acloud main process or
+ at the init of the error object.
+
+ Args:
+ exit_code: Integer, the exit code of acloud main process.
+ stacktrace: A string of stacktrace.
+ logs: A string of logs.
+ """
+ try:
+ from asuite.metrics import metrics_utils
+ metrics_utils.send_exit_event(exit_code, stacktrace=stacktrace,
+ logs=logs)
+ except Exception as e:
+ logger.debug("Failed to send exit event:%s", str(e))
diff --git a/public/acloud_main.py b/public/acloud_main.py
index 25a23e0..55b5735 100644
--- a/public/acloud_main.py
+++ b/public/acloud_main.py
@@ -51,6 +51,7 @@
import logging
import platform
import sys
+import traceback
# TODO: Remove this once we switch over to embedded launcher.
# Exit out if python version is < 2.7.13 due to b/120883119.
@@ -72,13 +73,14 @@
print(" POSIXLY_CORRECT=1 port -N install python27")
sys.exit(1)
-# Needed to silence oauth2client.
-# This is a workaround to get rid of below warning message:
+# By Default silence root logger's stream handler since 3p lib may initial
+# root logger no matter what level we're using. The acloud logger behavior will
+# be defined in _SetupLogging(). This also could workaround to get rid of below
+# oauth2client warning:
# 'No handlers could be found for logger "oauth2client.contrib.multistore_file'
-# TODO(b/112803893): Remove this code once bug is fixed.
-OAUTH2_LOGGER = logging.getLogger('oauth2client.contrib.multistore_file')
-OAUTH2_LOGGER.setLevel(logging.CRITICAL)
-OAUTH2_LOGGER.addHandler(logging.FileHandler("/dev/null"))
+DEFAULT_STREAM_HANDLER = logging.StreamHandler()
+DEFAULT_STREAM_HANDLER.setLevel(logging.CRITICAL)
+logging.getLogger().addHandler(DEFAULT_STREAM_HANDLER)
# pylint: disable=wrong-import-position
from acloud import errors
@@ -86,6 +88,7 @@
from acloud.create import create_args
from acloud.delete import delete
from acloud.delete import delete_args
+from acloud.internal import constants
from acloud.reconnect import reconnect
from acloud.reconnect import reconnect_args
from acloud.list import list as list_instances
@@ -341,7 +344,6 @@
# Check access.
# device_driver.CheckAccess(cfg)
- metrics.LogUsage()
report = None
if args.which == create_args.CMD_CREATE:
create.Run(args)
@@ -393,4 +395,19 @@
if __name__ == "__main__":
- main(sys.argv[1:])
+ EXIT_CODE = None
+ EXCEPTION_STACKTRACE = None
+ EXCEPTION_LOG = None
+ metrics.LogUsage(sys.argv[1:])
+ try:
+ EXIT_CODE = main(sys.argv[1:])
+ except Exception as e:
+ EXIT_CODE = constants.EXIT_BY_ERROR
+ EXCEPTION_STACKTRACE = traceback.format_exc()
+ EXCEPTION_LOG = str(e)
+ raise
+ finally:
+ # Log Exit event here to calculate the consuming time.
+ metrics.LogExitEvent(EXIT_CODE,
+ stacktrace=EXCEPTION_STACKTRACE,
+ logs=EXCEPTION_LOG)
diff --git a/setup/setup.py b/setup/setup.py
index 8b5eadb..ad498f4 100644
--- a/setup/setup.py
+++ b/setup/setup.py
@@ -95,7 +95,7 @@
if constants.ENV_ANDROID_BUILD_TOP not in os.environ:
print("Can't find $%s." % constants.ENV_ANDROID_BUILD_TOP)
print("Please run '#source build/envsetup.sh && lunch <target>' first.")
- sys.exit(1)
+ sys.exit(constants.EXIT_BY_USER)
pre_setup_sh = os.path.join(os.environ.get(constants.ENV_ANDROID_BUILD_TOP),
"tools",