Skip to content

Commit 9fe731e

Browse files
authored
Merge pull request #301 from splitio/release-9_3_0-pr
Release 9.3.0 pr
2 parents f0480fb + cc7d021 commit 9fe731e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+4608
-594
lines changed

CHANGES.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
9.3.0 (Jan 30, 2023)
2+
- Updated SDK telemetry storage, metrics and updater to be more effective and send less often.
3+
- Removed deprecated threading.Thread.setDaemon() method.
4+
15
9.2.2 (Dec 13, 2022)
26
- Fixed RedisSenderAdapter instantiation to store mtk keys.
37

LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright © 2022 Split Software, Inc.
1+
Copyright © 2023 Split Software, Inc.
22

33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
'pytest-cov',
1313
'importlib-metadata==4.2',
1414
'tomli==1.2.3',
15+
'iniconfig==1.1.1'
1516
]
1617

1718
INSTALL_REQUIRES = [

splitio/api/auth.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,19 @@
44
import json
55

66
from splitio.api import APIException
7-
from splitio.api.commons import headers_from_metadata
7+
from splitio.api.commons import headers_from_metadata, record_telemetry
8+
from splitio.util.time import get_current_epoch_time_ms
89
from splitio.api.client import HttpClientException
910
from splitio.models.token import from_raw
10-
11+
from splitio.models.telemetry import HTTPExceptionsAndLatencies
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,17 +39,21 @@ def authenticate(self):
3739
:return: Json representation of an authentication.
3840
:rtype: splitio.models.token.Token
3941
"""
42+
start = get_current_epoch_time_ms()
4043
try:
4144
response = self._client.get(
4245
'auth',
4346
'/v2/auth',
4447
self._apikey,
45-
extra_headers=self._metadata
48+
extra_headers=self._metadata,
4649
)
50+
record_telemetry(response.status_code, get_current_epoch_time_ms() - start, HTTPExceptionsAndLatencies.TOKEN, self._telemetry_runtime_producer)
4751
if 200 <= response.status_code < 300:
4852
payload = json.loads(response.body)
4953
return from_raw(payload)
5054
else:
55+
if (response.status_code >= 400 and response.status_code < 500):
56+
self._telemetry_runtime_producer.record_auth_rejections()
5157
raise APIException(response.body, response.status_code)
5258
except HttpClientException as exc:
5359
_LOGGER.error('Exception raised while authenticating')

splitio/api/client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
from collections import namedtuple
33

44
import requests
5+
import logging
6+
_LOGGER = logging.getLogger(__name__)
57

68
HttpResponse = namedtuple('HttpResponse', ['status_code', 'body'])
79

8-
910
class HttpClientException(Exception):
1011
"""HTTP Client exception."""
1112

@@ -42,7 +43,7 @@ def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, t
4243
:param telemetry_url: Optional alternative telemetry URL.
4344
:type telemetry_url: str
4445
"""
45-
self._timeout = timeout/1000 if timeout else None # Convert ms to seconds.
46+
self._timeout = timeout/1000 if timeout else None # Convert ms to seconds.
4647
self._urls = {
4748
'sdk': sdk_url if sdk_url is not None else self.SDK_URL,
4849
'events': events_url if events_url is not None else self.EVENTS_URL,

splitio/api/commons.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""Commons module."""
2-
2+
from splitio.util.time import get_current_epoch_time_ms
33

44
_CACHE_CONTROL = 'Cache-Control'
55
_CACHE_CONTROL_NO_CACHE = 'no-cache'
@@ -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_successful_sync(metric_name, get_current_epoch_time_ms())
54+
return
55+
telemetry_runtime_producer.record_sync_error(metric_name, status_code)
3556

3657
class FetchOptions(object):
3758
"""Fetch Options object."""
@@ -92,4 +113,4 @@ def build_fetch(change_number, fetch_options, metadata):
92113
extra_headers[_CACHE_CONTROL] = _CACHE_CONTROL_NO_CACHE
93114
if fetch_options.change_number is not None:
94115
query['till'] = fetch_options.change_number
95-
return query, extra_headers
116+
return query, extra_headers

splitio/api/events.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
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.util.time import get_current_epoch_time_ms
9+
from splitio.models.telemetry import HTTPExceptionsAndLatencies
710

811

912
_LOGGER = logging.getLogger(__name__)
@@ -12,7 +15,7 @@
1215
class EventsAPI(object): # pylint: disable=too-few-public-methods
1316
"""Class that uses an httpClient to communicate with the events API."""
1417

15-
def __init__(self, http_client, apikey, sdk_metadata):
18+
def __init__(self, http_client, apikey, sdk_metadata, telemetry_runtime_producer):
1619
"""
1720
Class constructor.
1821
@@ -26,6 +29,7 @@ def __init__(self, http_client, apikey, sdk_metadata):
2629
self._client = http_client
2730
self._apikey = apikey
2831
self._metadata = headers_from_metadata(sdk_metadata)
32+
self._telemetry_runtime_producer = telemetry_runtime_producer
2933

3034
@staticmethod
3135
def _build_bulk(events):
@@ -61,14 +65,16 @@ def flush_events(self, events):
6165
:rtype: bool
6266
"""
6367
bulk = self._build_bulk(events)
68+
start = get_current_epoch_time_ms()
6469
try:
6570
response = self._client.post(
6671
'events',
6772
'/events/bulk',
6873
self._apikey,
6974
body=bulk,
70-
extra_headers=self._metadata
75+
extra_headers=self._metadata,
7176
)
77+
record_telemetry(response.status_code, get_current_epoch_time_ms() - start, HTTPExceptionsAndLatencies.EVENT, self._telemetry_runtime_producer)
7278
if not 200 <= response.status_code < 300:
7379
raise APIException(response.body, response.status_code)
7480
except HttpClientException as exc:

splitio/api/impressions.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55

66
from splitio.api import APIException
77
from splitio.api.client import HttpClientException
8-
from splitio.api.commons import headers_from_metadata
9-
from splitio.engine.impressions.impressions import ImpressionsMode
8+
from splitio.api.commons import headers_from_metadata, record_telemetry
9+
from splitio.util.time import get_current_epoch_time_ms
10+
from splitio.engine.impressions import ImpressionsMode
11+
from splitio.models.telemetry import HTTPExceptionsAndLatencies
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,14 +94,16 @@ def flush_impressions(self, impressions):
9194
:type impressions: list
9295
"""
9396
bulk = self._build_bulk(impressions)
97+
start = get_current_epoch_time_ms()
9498
try:
9599
response = self._client.post(
96100
'events',
97101
'/testImpressions/bulk',
98102
self._apikey,
99103
body=bulk,
100-
extra_headers=self._metadata
104+
extra_headers=self._metadata,
101105
)
106+
record_telemetry(response.status_code, get_current_epoch_time_ms() - start, HTTPExceptionsAndLatencies.IMPRESSION, self._telemetry_runtime_producer)
102107
if not 200 <= response.status_code < 300:
103108
raise APIException(response.body, response.status_code)
104109
except HttpClientException as exc:
@@ -116,14 +121,16 @@ def flush_counters(self, counters):
116121
:type impressions: list
117122
"""
118123
bulk = self._build_counters(counters)
124+
start = get_current_epoch_time_ms()
119125
try:
120126
response = self._client.post(
121127
'events',
122128
'/testImpressions/count',
123129
self._apikey,
124130
body=bulk,
125-
extra_headers=self._metadata
131+
extra_headers=self._metadata,
126132
)
133+
record_telemetry(response.status_code, get_current_epoch_time_ms() - start, HTTPExceptionsAndLatencies.IMPRESSION_COUNT, self._telemetry_runtime_producer)
127134
if not 200 <= response.status_code < 300:
128135
raise APIException(response.body, response.status_code)
129136
except HttpClientException as exc:

splitio/api/segments.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
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
9+
from splitio.util.time import get_current_epoch_time_ms
810
from splitio.api.client import HttpClientException
11+
from splitio.models.telemetry import HTTPExceptionsAndLatencies
912

1013

1114
_LOGGER = logging.getLogger(__name__)
@@ -14,7 +17,7 @@
1417
class SegmentsAPI(object): # pylint: disable=too-few-public-methods
1518
"""Class that uses an httpClient to communicate with the segments API."""
1619

17-
def __init__(self, http_client, apikey, sdk_metadata):
20+
def __init__(self, http_client, apikey, sdk_metadata, telemetry_runtime_producer):
1821
"""
1922
Class constructor.
2023
@@ -29,6 +32,7 @@ def __init__(self, http_client, apikey, sdk_metadata):
2932
self._client = http_client
3033
self._apikey = apikey
3134
self._metadata = headers_from_metadata(sdk_metadata)
35+
self._telemetry_runtime_producer = telemetry_runtime_producer
3236

3337
def fetch_segment(self, segment_name, change_number, fetch_options):
3438
"""
@@ -46,6 +50,7 @@ def fetch_segment(self, segment_name, change_number, fetch_options):
4650
:return: Json representation of a segmentChange response.
4751
:rtype: dict
4852
"""
53+
start = get_current_epoch_time_ms()
4954
try:
5055
query, extra_headers = build_fetch(change_number, fetch_options, self._metadata)
5156
response = self._client.get(
@@ -55,7 +60,7 @@ def fetch_segment(self, segment_name, change_number, fetch_options):
5560
extra_headers=extra_headers,
5661
query=query,
5762
)
58-
63+
record_telemetry(response.status_code, get_current_epoch_time_ms() - start, HTTPExceptionsAndLatencies.SEGMENT, self._telemetry_runtime_producer)
5964
if 200 <= response.status_code < 300:
6065
return json.loads(response.body)
6166
else:

splitio/api/splits.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +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, build_fetch
8+
from splitio.api.commons import headers_from_metadata, build_fetch, record_telemetry
9+
from splitio.util.time import get_current_epoch_time_ms
810
from splitio.api.client import HttpClientException
9-
11+
from splitio.models.telemetry import HTTPExceptionsAndLatencies
1012

1113
_LOGGER = logging.getLogger(__name__)
1214

1315

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

17-
def __init__(self, client, apikey, sdk_metadata):
19+
def __init__(self, client, apikey, sdk_metadata, telemetry_runtime_producer):
1820
"""
1921
Class constructor.
2022
@@ -28,6 +30,7 @@ def __init__(self, client, apikey, sdk_metadata):
2830
self._client = client
2931
self._apikey = apikey
3032
self._metadata = headers_from_metadata(sdk_metadata)
33+
self._telemetry_runtime_producer = telemetry_runtime_producer
3134

3235
def fetch_splits(self, change_number, fetch_options):
3336
"""
@@ -42,6 +45,7 @@ def fetch_splits(self, change_number, fetch_options):
4245
:return: Json representation of a splitChanges response.
4346
:rtype: dict
4447
"""
48+
start = get_current_epoch_time_ms()
4549
try:
4650
query, extra_headers = build_fetch(change_number, fetch_options, self._metadata)
4751
response = self._client.get(
@@ -51,6 +55,7 @@ def fetch_splits(self, change_number, fetch_options):
5155
extra_headers=extra_headers,
5256
query=query,
5357
)
58+
record_telemetry(response.status_code, get_current_epoch_time_ms() - start, HTTPExceptionsAndLatencies.SPLIT, self._telemetry_runtime_producer)
5459
if 200 <= response.status_code < 300:
5560
return json.loads(response.body)
5661
else:

0 commit comments

Comments
 (0)