1# Copyright 2018, The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Asuite simple Metrics Functions"""
16
17import json
18import logging
19import os
20import uuid
21
22try:
23    # PYTHON2
24    from urllib2 import Request
25    from urllib2 import urlopen
26except ImportError:
27    # PYTHON3
28    from urllib.request import Request
29    from urllib.request import urlopen
30
31
32_JSON_HEADERS = {'Content-Type': 'application/json'}
33_METRICS_RESPONSE = 'done'
34_METRICS_TIMEOUT = 2 #seconds
35_META_FILE = os.path.join(os.path.expanduser('~'),
36                          '.config', 'asuite', '.metadata')
37_ANDROID_BUILD_TOP = 'ANDROID_BUILD_TOP'
38
39DUMMY_UUID = '00000000-0000-4000-8000-000000000000'
40
41
42#pylint: disable=broad-except
43def log_event(metrics_url, dummy_key_fallback=True, **kwargs):
44    """Base log event function for asuite backend.
45
46    Args:
47        metrics_url: String, URL to report metrics to.
48        dummy_key_fallback: Boolean, If True and unable to get grouping key,
49                            use a dummy key otherwise return out. Sometimes we
50                            don't want to return metrics for users we are
51                            unable to identify. Default True.
52        kwargs: Dict, additional fields we want to return metrics for.
53    """
54    try:
55        try:
56            key = str(_get_grouping_key())
57        except Exception:
58            if not dummy_key_fallback:
59                return
60            key = DUMMY_UUID
61        data = {'grouping_key': key,
62                'run_id': str(uuid.uuid4())}
63        if kwargs:
64            data.update(kwargs)
65        data = json.dumps(data)
66        request = Request(metrics_url, data=data,
67                          headers=_JSON_HEADERS)
68        response = urlopen(request, timeout=_METRICS_TIMEOUT)
69        content = response.read()
70        if content != _METRICS_RESPONSE:
71            raise Exception('Unexpected metrics response: %s' % content)
72    except Exception as e:
73        logging.debug('Exception sending metrics: %s', e)
74
75
76def _get_grouping_key():
77    """Get grouping key. Returns UUID.uuid4."""
78    if os.path.isfile(_META_FILE):
79        with open(_META_FILE) as f:
80            try:
81                return uuid.UUID(f.read(), version=4)
82            except ValueError:
83                logging.debug('malformed group_key in file, rewriting')
84    # TODO: Delete get_old_key() on 11/17/2018
85    key = _get_old_key() or uuid.uuid4()
86    dir_path = os.path.dirname(_META_FILE)
87    if os.path.isfile(dir_path):
88        os.remove(dir_path)
89    try:
90        os.makedirs(dir_path)
91    except OSError as e:
92        if not os.path.isdir(dir_path):
93            raise e
94    with open(_META_FILE, 'w+') as f:
95        f.write(str(key))
96    return key
97
98
99def _get_old_key():
100    """Get key from old meta data file if exists, else return None."""
101    old_file = os.path.join(os.environ[_ANDROID_BUILD_TOP],
102                            'tools/tradefederation/core/atest', '.metadata')
103    key = None
104    if os.path.isfile(old_file):
105        with open(old_file) as f:
106            try:
107                key = uuid.UUID(f.read(), version=4)
108            except ValueError:
109                logging.debug('error reading old key')
110        os.remove(old_file)
111    return key
112