11"""Redis client wrapper with prefix support."""
22from builtins import str
3+ import socket
4+ import logging
5+ from splitio .version import __version__
36
47try :
58 from redis import StrictRedis
@@ -14,6 +17,10 @@ def missing_redis_dependencies(*_, **__):
1417 )
1518 StrictRedis = Sentinel = missing_redis_dependencies
1619
20+ _LOGGER = logging .getLogger (__name__ )
21+ TELEMETRY_CONFIG_KEY = 'SPLITIO.telemetry.init'
22+ TELEMETRY_EXCEPTIONS_KEY = 'SPLITIO.telemetry.exceptions'
23+ TELEMETRY_LATENCIES_KEY = 'SPLITIO.telemetry.latencies'
1724
1825class RedisAdapterException (Exception ):
1926 """Exception to be thrown when a redis command fails with an exception."""
@@ -241,6 +248,13 @@ def hget(self, name, key):
241248 except RedisError as exc :
242249 raise RedisAdapterException ('Error executing hget operation' ) from exc
243250
251+ def hincrby (self , name , key , amount = 1 ):
252+ """Mimic original redis function but using user custom prefix."""
253+ try :
254+ return self ._decorated .hincrby (self ._prefix_helper .add_prefix (name ), key , amount )
255+ except RedisError as exc :
256+ raise RedisAdapterException ('Error executing hincrby operation' ) from exc
257+
244258 def incr (self , name , amount = 1 ):
245259 """Mimic original redis function but using user custom prefix."""
246260 try :
@@ -297,6 +311,54 @@ def pipeline(self):
297311 except RedisError as exc :
298312 raise RedisAdapterException ('Error executing ttl operation' ) from exc
299313
314+ def record_init (self , * values ):
315+ try :
316+ host_name , host_ip = self ._get_host_info ()
317+ return self .hset (TELEMETRY_CONFIG_KEY , 'python-' + __version__ + '/' + host_name + '/' + host_ip , str (* values ))
318+ except RedisError as exc :
319+ raise RedisAdapterException ('Error pushing telemetry config operation' ) from exc
320+
321+ def _get_host_info (self ):
322+ host_name = 'Unknown'
323+ host_ip = 'Unknown'
324+ try :
325+ host_name = socket .gethostname ()
326+ host_ip = socket .gethostbyname (socket .gethostname ())
327+ except :
328+ _LOGGER .debug ("Could not get hostname or ip" )
329+ pass
330+ return host_name , host_ip
331+
332+ def record_stats (self , values ):
333+ try :
334+ host_name , host_ip = self ._get_host_info ()
335+ for item in values ['mL' ]:
336+ bucket_number = 0
337+ for bucket in values ['mL' ][item ]:
338+ if bucket > 0 :
339+ self .hincrby (TELEMETRY_LATENCIES_KEY , 'python-' + __version__ + '/' + host_name + '/' + host_ip + '/' +
340+ self ._get_method_name (item ) + '/' + str (bucket_number ), bucket )
341+ bucket_number = bucket_number + 0
342+ for item in values ['mE' ]:
343+ if values ['mE' ][item ] > 0 :
344+ self .hincrby (TELEMETRY_EXCEPTIONS_KEY , 'python-' + __version__ + '/' + host_name + '/' + host_ip + '/' +
345+ self ._get_method_name (item ), values ['mE' ][item ])
346+ except RedisError as exc :
347+ raise RedisAdapterException ('Error pushing telemetry evaluation operation' ) from exc
348+
349+ def _get_method_name (self , item ):
350+ if item == 't' :
351+ return 'treatment'
352+ elif item == 'ts' :
353+ return 'treatments'
354+ elif item == 'tc' :
355+ return 'treatment_with_config'
356+ elif item == 'tcs' :
357+ return 'treatments_with_config'
358+ elif item == 'tr' :
359+ return 'track'
360+ else :
361+ return ''
300362
301363class RedisPipelineAdapter (object ):
302364 """
0 commit comments