Skip to content

Commit bc626f0

Browse files
committed
Telemetry api refactor and clenaup
1 parent e1f3657 commit bc626f0

File tree

16 files changed

+132
-85
lines changed

16 files changed

+132
-85
lines changed

splitio/api/auth.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@
22

33
import logging
44
import json
5+
import time
56

67
from splitio.api import APIException
7-
from splitio.api.commons import headers_from_metadata
8+
from splitio.api.commons import headers_from_metadata, record_telemetry
89
from splitio.api.client import HttpClientException
910
from splitio.models.token import from_raw
10-
11+
from splitio.models.telemetry import TOKEN
1112

1213
_LOGGER = logging.getLogger(__name__)
1314

1415

1516
class AuthAPI(object): # pylint: disable=too-few-public-methods
1617
"""Class that uses an httpClient to communicate with the SDK Auth Service API."""
1718

18-
def __init__(self, client, apikey, sdk_metadata):
19+
def __init__(self, client, apikey, sdk_metadata, telemetry_runtime_producer):
1920
"""
2021
Class constructor.
2122
@@ -29,6 +30,7 @@ def __init__(self, client, apikey, sdk_metadata):
2930
self._client = client
3031
self._apikey = apikey
3132
self._metadata = headers_from_metadata(sdk_metadata)
33+
self._telemetry_runtime_producer = telemetry_runtime_producer
3234

3335
def authenticate(self):
3436
"""
@@ -37,18 +39,21 @@ def authenticate(self):
3739
:return: Json representation of an authentication.
3840
:rtype: splitio.models.token.Token
3941
"""
42+
start = int(round(time.time() * 1000))
4043
try:
4144
response = self._client.get(
4245
'auth',
4346
'/v2/auth',
4447
self._apikey,
4548
extra_headers=self._metadata,
46-
metric_name='token'
4749
)
50+
record_telemetry(response.status_code, int(round(time.time() * 1000)) - start, TOKEN, self._telemetry_runtime_producer)
4851
if 200 <= response.status_code < 300:
4952
payload = json.loads(response.body)
5053
return from_raw(payload)
5154
else:
55+
if response.status_code == 401:
56+
self._telemetry_runtime_producer.record_auth_rejections()
5257
raise APIException(response.body, response.status_code)
5358
except HttpClientException as exc:
5459
_LOGGER.error('Exception raised while authenticating')

splitio/api/client.py

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class HttpClient(object):
2727
AUTH_URL = 'https://auth.split.io/api'
2828
TELEMETRY_URL = 'https://telemetry.split.io/api'
2929

30-
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None, telemetry_runtime_producer=None):
30+
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
3131
"""
3232
Class constructor.
3333
@@ -49,7 +49,6 @@ def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, t
4949
'auth': auth_url if auth_url is not None else self.AUTH_URL,
5050
'telemetry': telemetry_url if telemetry_url is not None else self.TELEMETRY_URL,
5151
}
52-
self._telemetry_runtime_producer = telemetry_runtime_producer
5352

5453
def _build_url(self, server, path):
5554
"""
@@ -78,7 +77,7 @@ def _build_basic_headers(apikey):
7877
'Authorization': "Bearer %s" % apikey
7978
}
8079

81-
def get(self, server, path, apikey, query=None, extra_headers=None, metric_name=None): # pylint: disable=too-many-arguments
80+
def get(self, server, path, apikey, query=None, extra_headers=None): # pylint: disable=too-many-arguments
8281
"""
8382
Issue a get request.
8483
@@ -107,22 +106,12 @@ def get(self, server, path, apikey, query=None, extra_headers=None, metric_name=
107106
headers=headers,
108107
timeout=self._timeout
109108
)
110-
elapsed = response.elapsed.total_seconds()
111109
response = HttpResponse(response.status_code, response.text)
112-
self._telemetry_runtime_producer.record_sync_latency(metric_name, elapsed)
113-
if not 200 <= response.status_code < 300:
114-
self._telemetry_runtime_producer.record_sync_error(metric_name, response.status_code)
115-
if metric_name == 'token':
116-
self._telemetry_runtime_producer.record_auth_rejections()
117-
else:
118-
self._telemetry_runtime_producer.record_suceessful_sync(metric_name, round(1000 * elapsed))
119-
if metric_name == 'token':
120-
self._telemetry_runtime_producer.record_token_refreshes()
121110
return response
122111
except Exception as exc: # pylint: disable=broad-except
123112
raise HttpClientException('requests library is throwing exceptions') from exc
124113

125-
def post(self, server, path, apikey, body, query=None, extra_headers=None, metric_name=None): # pylint: disable=too-many-arguments
114+
def post(self, server, path, apikey, body, query=None, extra_headers=None): # pylint: disable=too-many-arguments
126115
"""
127116
Issue a POST request.
128117
@@ -155,13 +144,7 @@ def post(self, server, path, apikey, body, query=None, extra_headers=None, metri
155144
headers=headers,
156145
timeout=self._timeout
157146
)
158-
elapsed = response.elapsed.total_seconds()
159147
response = HttpResponse(response.status_code, response.text)
160-
self._telemetry_runtime_producer.record_sync_latency(metric_name, elapsed)
161-
if not 200 <= response.status_code < 300:
162-
self._telemetry_runtime_producer.record_sync_error(metric_name, response.status_code)
163-
else:
164-
self._telemetry_runtime_producer.record_suceessful_sync(metric_name, round(1000 * elapsed))
165148
return response
166149
except Exception as exc: # pylint: disable=broad-except
167150
raise HttpClientException('requests library is throwing exceptions') from exc

splitio/api/commons.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ def headers_from_metadata(sdk_metadata, client_key=None):
3232

3333
return metadata
3434

35+
def record_telemetry(status_code, elapsed, metric_name, telemetry_runtime_producer):
36+
"""
37+
Record Telemetry info
38+
39+
:param status_code: http request status code
40+
:type status_code: int
41+
42+
:param elapsed: response time elapsed.
43+
:type status_code: int
44+
45+
:param metric_name: metric name for telemetry
46+
:type metric_name: str
47+
48+
:param telemetry_runtime_producer: telemetry recording instance
49+
:type telemetry_runtime_producer: splitio.engine.telemetry.TelemetryRuntimeProducer
50+
"""
51+
telemetry_runtime_producer.record_sync_latency(metric_name, elapsed)
52+
if 200 <= status_code < 300:
53+
telemetry_runtime_producer.record_suceessful_sync(metric_name, elapsed)
54+
else:
55+
telemetry_runtime_producer.record_sync_error(metric_name, status_code)
3556

3657
class FetchOptions(object):
3758
"""Fetch Options object."""

splitio/api/events.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
"""Events API module."""
22
import logging
3+
import time
34

45
from splitio.api import APIException
56
from splitio.api.client import HttpClientException
6-
from splitio.api.commons import headers_from_metadata
7+
from splitio.api.commons import headers_from_metadata, record_telemetry
8+
from splitio.models.telemetry import EVENT
79

810

911
_LOGGER = logging.getLogger(__name__)
@@ -12,7 +14,7 @@
1214
class EventsAPI(object): # pylint: disable=too-few-public-methods
1315
"""Class that uses an httpClient to communicate with the events API."""
1416

15-
def __init__(self, http_client, apikey, sdk_metadata):
17+
def __init__(self, http_client, apikey, sdk_metadata, telemetry_runtime_producer):
1618
"""
1719
Class constructor.
1820
@@ -26,6 +28,7 @@ def __init__(self, http_client, apikey, sdk_metadata):
2628
self._client = http_client
2729
self._apikey = apikey
2830
self._metadata = headers_from_metadata(sdk_metadata)
31+
self._telemetry_runtime_producer = telemetry_runtime_producer
2932

3033
@staticmethod
3134
def _build_bulk(events):
@@ -61,15 +64,16 @@ def flush_events(self, events):
6164
:rtype: bool
6265
"""
6366
bulk = self._build_bulk(events)
67+
start = int(round(time.time() * 1000))
6468
try:
6569
response = self._client.post(
6670
'events',
6771
'/events/bulk',
6872
self._apikey,
6973
body=bulk,
7074
extra_headers=self._metadata,
71-
metric_name='event'
7275
)
76+
record_telemetry(response.status_code, int(round(time.time() * 1000)) - start, EVENT, self._telemetry_runtime_producer)
7377
if not 200 <= response.status_code < 300:
7478
raise APIException(response.body, response.status_code)
7579
except HttpClientException as exc:

splitio/api/impressions.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
import logging
44
from itertools import groupby
5+
import time
56

67
from splitio.api import APIException
78
from splitio.api.client import HttpClientException
8-
from splitio.api.commons import headers_from_metadata
9-
from splitio.engine.impressions.impressions import ImpressionsMode
9+
from splitio.api.commons import headers_from_metadata, record_telemetry
10+
from splitio.engine.impressions import ImpressionsMode
11+
from splitio.models.telemetry import IMPRESSION, IMPRESSION_COUNT
1012

1113

1214
_LOGGER = logging.getLogger(__name__)
@@ -15,7 +17,7 @@
1517
class ImpressionsAPI(object): # pylint: disable=too-few-public-methods
1618
"""Class that uses an httpClient to communicate with the impressions API."""
1719

18-
def __init__(self, client, apikey, sdk_metadata, mode=ImpressionsMode.OPTIMIZED):
20+
def __init__(self, client, apikey, sdk_metadata, telemetry_runtime_producer, mode=ImpressionsMode.OPTIMIZED):
1921
"""
2022
Class constructor.
2123
@@ -28,6 +30,7 @@ def __init__(self, client, apikey, sdk_metadata, mode=ImpressionsMode.OPTIMIZED)
2830
self._apikey = apikey
2931
self._metadata = headers_from_metadata(sdk_metadata)
3032
self._metadata['SplitSDKImpressionsMode'] = mode.name
33+
self._telemetry_runtime_producer = telemetry_runtime_producer
3134

3235
@staticmethod
3336
def _build_bulk(impressions):
@@ -91,15 +94,16 @@ def flush_impressions(self, impressions):
9194
:type impressions: list
9295
"""
9396
bulk = self._build_bulk(impressions)
97+
start = int(round(time.time() * 1000))
9498
try:
9599
response = self._client.post(
96100
'events',
97101
'/testImpressions/bulk',
98102
self._apikey,
99103
body=bulk,
100104
extra_headers=self._metadata,
101-
metric_name='impression'
102105
)
106+
record_telemetry(response.status_code, int(round(time.time() * 1000)) - start, IMPRESSION, self._telemetry_runtime_producer)
103107
if not 200 <= response.status_code < 300:
104108
raise APIException(response.body, response.status_code)
105109
except HttpClientException as exc:
@@ -117,15 +121,16 @@ def flush_counters(self, counters):
117121
:type impressions: list
118122
"""
119123
bulk = self._build_counters(counters)
124+
start = int(round(time.time() * 1000))
120125
try:
121126
response = self._client.post(
122127
'events',
123128
'/testImpressions/count',
124129
self._apikey,
125130
body=bulk,
126131
extra_headers=self._metadata,
127-
metric_name='im'
128132
)
133+
record_telemetry(response.status_code, int(round(time.time() * 1000)) - start, IMPRESSION_COUNT, self._telemetry_runtime_producer)
129134
if not 200 <= response.status_code < 300:
130135
raise APIException(response.body, response.status_code)
131136
except HttpClientException as exc:

splitio/api/segments.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import json
44
import logging
5+
import time
56

67
from splitio.api import APIException
7-
from splitio.api.commons import headers_from_metadata, build_fetch
8+
from splitio.api.commons import headers_from_metadata, build_fetch, record_telemetry
89
from splitio.api.client import HttpClientException
10+
from splitio.models.telemetry import SEGMENT
911

1012

1113
_LOGGER = logging.getLogger(__name__)
@@ -14,7 +16,7 @@
1416
class SegmentsAPI(object): # pylint: disable=too-few-public-methods
1517
"""Class that uses an httpClient to communicate with the segments API."""
1618

17-
def __init__(self, http_client, apikey, sdk_metadata):
19+
def __init__(self, http_client, apikey, sdk_metadata, telemetry_runtime_producer):
1820
"""
1921
Class constructor.
2022
@@ -29,6 +31,7 @@ def __init__(self, http_client, apikey, sdk_metadata):
2931
self._client = http_client
3032
self._apikey = apikey
3133
self._metadata = headers_from_metadata(sdk_metadata)
34+
self._telemetry_runtime_producer = telemetry_runtime_producer
3235

3336
def fetch_segment(self, segment_name, change_number, fetch_options):
3437
"""
@@ -46,6 +49,7 @@ def fetch_segment(self, segment_name, change_number, fetch_options):
4649
:return: Json representation of a segmentChange response.
4750
:rtype: dict
4851
"""
52+
start = int(round(time.time() * 1000))
4953
try:
5054
query, extra_headers = build_fetch(change_number, fetch_options, self._metadata)
5155
response = self._client.get(
@@ -54,8 +58,8 @@ def fetch_segment(self, segment_name, change_number, fetch_options):
5458
self._apikey,
5559
extra_headers=extra_headers,
5660
query=query,
57-
metric_name='segment'
5861
)
62+
record_telemetry(response.status_code, int(round(time.time() * 1000)) - start, SEGMENT, self._telemetry_runtime_producer)
5963
if 200 <= response.status_code < 300:
6064
return json.loads(response.body)
6165
else:

splitio/api/splits.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22

33
import logging
44
import json
5+
import time
56

67
from splitio.api import APIException
7-
from splitio.api.commons import headers_from_metadata, build_fetch
8+
from splitio.api.commons import headers_from_metadata, build_fetch, record_telemetry
89
from splitio.api.client import HttpClientException
9-
10+
from splitio.models.telemetry import SPLIT
1011

1112
_LOGGER = logging.getLogger(__name__)
1213

1314

1415
class SplitsAPI(object): # pylint: disable=too-few-public-methods
1516
"""Class that uses an httpClient to communicate with the splits API."""
1617

17-
def __init__(self, client, apikey, sdk_metadata):
18+
def __init__(self, client, apikey, sdk_metadata, telemetry_runtime_producer):
1819
"""
1920
Class constructor.
2021
@@ -28,6 +29,7 @@ def __init__(self, client, apikey, sdk_metadata):
2829
self._client = client
2930
self._apikey = apikey
3031
self._metadata = headers_from_metadata(sdk_metadata)
32+
self._telemetry_runtime_producer = telemetry_runtime_producer
3133

3234
def fetch_splits(self, change_number, fetch_options):
3335
"""
@@ -42,6 +44,7 @@ def fetch_splits(self, change_number, fetch_options):
4244
:return: Json representation of a splitChanges response.
4345
:rtype: dict
4446
"""
47+
start = int(round(time.time() * 1000))
4548
try:
4649
query, extra_headers = build_fetch(change_number, fetch_options, self._metadata)
4750
response = self._client.get(
@@ -50,8 +53,8 @@ def fetch_splits(self, change_number, fetch_options):
5053
self._apikey,
5154
extra_headers=extra_headers,
5255
query=query,
53-
metric_name='split'
5456
)
57+
record_telemetry(response.status_code, int(round(time.time() * 1000)) - start, SPLIT, self._telemetry_runtime_producer)
5558
if 200 <= response.status_code < 300:
5659
return json.loads(response.body)
5760
else:

0 commit comments

Comments
 (0)