99import time
1010import http .client
1111from collections import OrderedDict
12+ import random
1213from typing import Union , List , Optional , Dict , Any , Tuple , Pattern
1314from contextlib import contextmanager
1415from base64 import b64encode
1516import inspect
1617
18+ try :
19+ import boto3
20+ except Exception :
21+ boto3 = None
22+
1723EXECUTION_TAGS_KEY = "lumigo_execution_tags_no_scrub"
1824EDGE_HOST = "{region}.lumigo-tracer-edge.golumigo.com"
1925EDGE_PATH = "/api/spans"
5662LUMIGO_TOKEN_KEY = "LUMIGO_TRACER_TOKEN"
5763KILL_SWITCH = "LUMIGO_SWITCH_OFF"
5864ERROR_SIZE_LIMIT_MULTIPLIER = 2
65+ CHINA_REGION = "cn-northwest-1"
66+ EDGE_KINESIS_STREAM_NAME = "prod_trc-inges-edge_edge-kinesis-stream"
5967
6068_logger : Dict [str , logging .Logger ] = {}
6169
@@ -84,6 +92,9 @@ class Configuration:
8492 domains_scrubber : Optional [List ] = None
8593 max_entry_size : int = DEFAULT_MAX_ENTRY_SIZE
8694 get_key_depth : int = DEFAULT_KEY_DEPTH
95+ edge_kinesis_stream_name : str = EDGE_KINESIS_STREAM_NAME
96+ edge_kinesis_aws_access_key_id : Optional [str ] = None
97+ edge_kinesis_aws_secret_access_key : Optional [str ] = None
8798
8899 @staticmethod
89100 def get_max_entry_size (has_error : bool = False ) -> int :
@@ -104,6 +115,9 @@ def config(
104115 domains_scrubber : Optional [List [str ]] = None ,
105116 max_entry_size : int = DEFAULT_MAX_ENTRY_SIZE ,
106117 get_key_depth : int = None ,
118+ edge_kinesis_stream_name : Optional [str ] = None ,
119+ edge_kinesis_aws_access_key_id : Optional [str ] = None ,
120+ edge_kinesis_aws_secret_access_key : Optional [str ] = None ,
107121) -> None :
108122 """
109123 This function configure the lumigo wrapper.
@@ -120,6 +134,9 @@ def config(
120134 :param domains_scrubber: List of regexes. We will not collect data of requests with hosts that match it.
121135 :param max_entry_size: The maximum size of each entry when sending back the events.
122136 :param get_key_depth: Max depth to search the lumigo key in the event (relevant to step functions). default 4.
137+ :param edge_kinesis_stream_name: The name of the Kinesis to push the spans in China region
138+ :param edge_kinesis_aws_access_key_id: The credentials to push to the Kinesis in China region
139+ :param edge_kinesis_aws_secret_access_key: The credentials to push to the Kinesis in China region
123140 """
124141 if should_report is not None :
125142 Configuration .should_report = should_report
@@ -162,6 +179,18 @@ def config(
162179 domains_scrubber_regex = DOMAIN_SCRUBBER_REGEXES
163180 Configuration .domains_scrubber = [re .compile (r , re .IGNORECASE ) for r in domains_scrubber_regex ]
164181 Configuration .max_entry_size = int (os .environ .get ("LUMIGO_MAX_ENTRY_SIZE" , max_entry_size ))
182+ Configuration .edge_kinesis_stream_name = (
183+ edge_kinesis_stream_name
184+ or os .environ .get ("LUMIGO_EDGE_KINESIS_STREAM_NAME" ) # noqa`
185+ or EDGE_KINESIS_STREAM_NAME # noqa
186+ )
187+ Configuration .edge_kinesis_aws_access_key_id = edge_kinesis_aws_access_key_id or os .environ .get (
188+ "LUMIGO_EDGE_KINESIS_AWS_ACCESS_KEY_ID"
189+ )
190+ Configuration .edge_kinesis_aws_secret_access_key = (
191+ edge_kinesis_aws_secret_access_key
192+ or os .environ .get ("LUMIGO_EDGE_KINESIS_AWS_SECRET_ACCESS_KEY" ) # noqa
193+ )
165194
166195
167196def _is_span_has_error (span : dict ) -> bool :
@@ -235,9 +264,19 @@ def report_json(region: Union[None, str], msgs: List[dict], should_retry: bool =
235264 :return: The duration of reporting (in milliseconds),
236265 or 0 if we didn't send (due to configuration or fail).
237266 """
238- global edge_connection
267+ if not Configuration .should_report :
268+ return 0
239269 get_logger ().info (f"reporting the messages: { msgs [:10 ]} " )
270+ try :
271+ prune_trace : bool = not os .environ .get ("LUMIGO_PRUNE_TRACE_OFF" , "" ).lower () == "true"
272+ to_send = _create_request_body (msgs , prune_trace ).encode ()
273+ except Exception as e :
274+ get_logger ().exception ("Failed to create request: A span was lost." , exc_info = e )
275+ return 0
276+ if region == CHINA_REGION :
277+ return _publish_spans_to_kinesis (to_send , CHINA_REGION )
240278 host = None
279+ global edge_connection
241280 with lumigo_safe_execute ("report json: establish connection" ):
242281 host = prepare_host (Configuration .host or EDGE_HOST .format (region = region ))
243282 duration = 0
@@ -246,28 +285,67 @@ def report_json(region: Union[None, str], msgs: List[dict], should_retry: bool =
246285 if not edge_connection :
247286 get_logger ().warning ("Can not establish connection. Skip sending span." )
248287 return duration
249- if Configuration .should_report :
250- try :
251- prune_trace : bool = not os .environ .get ("LUMIGO_PRUNE_TRACE_OFF" , "" ).lower () == "true"
252- to_send = _create_request_body (msgs , prune_trace ).encode ()
253- start_time = time .time ()
254- edge_connection .request (
255- "POST" , EDGE_PATH , to_send , headers = {"Content-Type" : "application/json" }
256- )
257- response = edge_connection .getresponse ()
258- response .read () # We most read the response to keep the connection available
259- duration = int ((time .time () - start_time ) * 1000 )
260- get_logger ().info (f"successful reporting, code: { getattr (response , 'code' , 'unknown' )} " )
261- except Exception as e :
262- if should_retry :
263- get_logger ().exception (f"Could not report to { host } . Retrying." , exc_info = e )
264- edge_connection = establish_connection (host )
265- report_json (region , msgs , should_retry = False )
266- else :
267- get_logger ().exception ("Could not report: A span was lost." , exc_info = e )
288+ try :
289+ start_time = time .time ()
290+ edge_connection .request (
291+ "POST" , EDGE_PATH , to_send , headers = {"Content-Type" : "application/json" }
292+ )
293+ response = edge_connection .getresponse ()
294+ response .read () # We most read the response to keep the connection available
295+ duration = int ((time .time () - start_time ) * 1000 )
296+ get_logger ().info (f"successful reporting, code: { getattr (response , 'code' , 'unknown' )} " )
297+ except Exception as e :
298+ if should_retry :
299+ get_logger ().exception (f"Could not report to { host } . Retrying." , exc_info = e )
300+ edge_connection = establish_connection (host )
301+ report_json (region , msgs , should_retry = False )
302+ else :
303+ get_logger ().exception ("Could not report: A span was lost." , exc_info = e )
268304 return duration
269305
270306
307+ def _publish_spans_to_kinesis (to_send : bytes , region : str ) -> int :
308+ start_time = time .time ()
309+ with lumigo_safe_execute ("report json: publish to kinesis" ):
310+ get_logger ().info ("Sending spans to Kinesis" )
311+ if not Configuration .edge_kinesis_aws_access_key_id :
312+ get_logger ().error ("Missing edge_kinesis_aws_access_key_id, can't publish the spans" )
313+ return 0
314+ if not Configuration .edge_kinesis_aws_secret_access_key :
315+ get_logger ().error (
316+ "Missing edge_kinesis_aws_secret_access_key, can't publish the spans"
317+ )
318+ return 0
319+ _send_data_to_kinesis (
320+ stream_name = Configuration .edge_kinesis_stream_name ,
321+ to_send = to_send ,
322+ region = region ,
323+ aws_access_key_id = Configuration .edge_kinesis_aws_access_key_id ,
324+ aws_secret_access_key = Configuration .edge_kinesis_aws_secret_access_key ,
325+ )
326+ return int ((time .time () - start_time ) * 1000 )
327+
328+
329+ def _send_data_to_kinesis (
330+ stream_name : str ,
331+ to_send : bytes ,
332+ region : str ,
333+ aws_access_key_id : str ,
334+ aws_secret_access_key : str ,
335+ ):
336+ if not boto3 :
337+ get_logger ().error ("boto3 is missing. Unable to send to Kinesis." )
338+ return None
339+ client = boto3 .client (
340+ "kinesis" ,
341+ region_name = region ,
342+ aws_access_key_id = aws_access_key_id ,
343+ aws_secret_access_key = aws_secret_access_key ,
344+ )
345+ client .put_record (Data = to_send , StreamName = stream_name , PartitionKey = str (random .random ()))
346+ get_logger ().info ("Successful sending to Kinesis" )
347+
348+
271349def get_logger (logger_name = "lumigo" ):
272350 """
273351 This function returns lumigo's logger.
0 commit comments