88from requests .adapters import HTTPAdapter
99from urllib3 import Retry
1010
11- from flagsmith .analytics import AnalyticsProcessor
11+ from flagsmith .analytics import (
12+ AnalyticsProcessor ,
13+ PipelineAnalyticsConfig ,
14+ PipelineAnalyticsProcessor ,
15+ )
1216from flagsmith .exceptions import FlagsmithAPIError , FlagsmithClientError
1317from flagsmith .mappers import (
1418 map_context_and_identity_data_to_context ,
1519 map_environment_document_to_context ,
1620 map_environment_document_to_environment_updated_at ,
1721 map_segment_results_to_identity_segments ,
22+ resolve_trait_values ,
1823)
1924from flagsmith .models import DefaultFlag , Flags , Segment
2025from flagsmith .offline_handlers import OfflineHandler
@@ -63,6 +68,7 @@ def __init__(
6368 environment_refresh_interval_seconds : typing .Union [int , float ] = 60 ,
6469 retries : typing .Optional [Retry ] = None ,
6570 enable_analytics : bool = False ,
71+ pipeline_analytics_config : typing .Optional [PipelineAnalyticsConfig ] = None ,
6672 default_flag_handler : typing .Optional [
6773 typing .Callable [[str ], DefaultFlag ]
6874 ] = None ,
@@ -108,6 +114,9 @@ def __init__(
108114 self .default_flag_handler = default_flag_handler
109115 self .enable_realtime_updates = enable_realtime_updates
110116 self ._analytics_processor : typing .Optional [AnalyticsProcessor ] = None
117+ self ._pipeline_analytics_processor : typing .Optional [
118+ PipelineAnalyticsProcessor
119+ ] = None
111120 self ._evaluation_context : typing .Optional [SDKEvaluationContext ] = None
112121 self ._environment_updated_at : typing .Optional [datetime ] = None
113122
@@ -170,10 +179,28 @@ def __init__(
170179
171180 self ._initialise_local_evaluation ()
172181
173- if enable_analytics :
174- self ._analytics_processor = AnalyticsProcessor (
175- environment_key , self .api_url , timeout = self .request_timeout_seconds
176- )
182+ self ._initialise_analytics (
183+ environment_key = environment_key ,
184+ enable_analytics = enable_analytics ,
185+ pipeline_analytics_config = pipeline_analytics_config ,
186+ )
187+
188+ def _initialise_analytics (
189+ self ,
190+ environment_key : str ,
191+ enable_analytics : bool ,
192+ pipeline_analytics_config : typing .Optional [PipelineAnalyticsConfig ],
193+ ) -> None :
194+ if enable_analytics :
195+ self ._analytics_processor = AnalyticsProcessor (
196+ environment_key , self .api_url , timeout = self .request_timeout_seconds
197+ )
198+ if pipeline_analytics_config :
199+ self ._pipeline_analytics_processor = PipelineAnalyticsProcessor (
200+ config = pipeline_analytics_config ,
201+ environment_key = environment_key ,
202+ )
203+ self ._pipeline_analytics_processor .start ()
177204
178205 def _initialise_local_evaluation (self ) -> None :
179206 # To ensure that the environment is set before allowing subsequent
@@ -290,6 +317,25 @@ def get_identity_segments(
290317
291318 return map_segment_results_to_identity_segments (evaluation_result ["segments" ])
292319
320+ def track_event (
321+ self ,
322+ event_name : str ,
323+ identity_identifier : typing .Optional [str ] = None ,
324+ traits : typing .Optional [TraitMapping ] = None ,
325+ metadata : typing .Optional [typing .Dict [str , typing .Any ]] = None ,
326+ ) -> None :
327+ if not self ._pipeline_analytics_processor :
328+ raise ValueError (
329+ "Pipeline analytics is not configured. "
330+ "Provide pipeline_analytics_config to use track_event."
331+ )
332+ self ._pipeline_analytics_processor .record_custom_event (
333+ event_name = event_name ,
334+ identity_identifier = identity_identifier ,
335+ traits = resolve_trait_values (traits ),
336+ metadata = metadata ,
337+ )
338+
293339 def update_environment (self ) -> None :
294340 try :
295341 environment_data = self ._get_json_response (
@@ -345,6 +391,7 @@ def _get_environment_flags_from_document(self) -> Flags:
345391 evaluation_result = evaluation_result ,
346392 analytics_processor = self ._analytics_processor ,
347393 default_flag_handler = self .default_flag_handler ,
394+ pipeline_analytics_processor = self ._pipeline_analytics_processor ,
348395 )
349396
350397 def _get_identity_flags_from_document (
@@ -368,6 +415,9 @@ def _get_identity_flags_from_document(
368415 evaluation_result = evaluation_result ,
369416 analytics_processor = self ._analytics_processor ,
370417 default_flag_handler = self .default_flag_handler ,
418+ pipeline_analytics_processor = self ._pipeline_analytics_processor ,
419+ identity_identifier = identifier ,
420+ traits = resolve_trait_values (traits ),
371421 )
372422
373423 def _get_environment_flags_from_api (self ) -> Flags :
@@ -379,6 +429,7 @@ def _get_environment_flags_from_api(self) -> Flags:
379429 api_flags = json_response ,
380430 analytics_processor = self ._analytics_processor ,
381431 default_flag_handler = self .default_flag_handler ,
432+ pipeline_analytics_processor = self ._pipeline_analytics_processor ,
382433 )
383434 except FlagsmithAPIError :
384435 if self .offline_handler :
@@ -411,6 +462,9 @@ def _get_identity_flags_from_api(
411462 api_flags = json_response ["flags" ],
412463 analytics_processor = self ._analytics_processor ,
413464 default_flag_handler = self .default_flag_handler ,
465+ pipeline_analytics_processor = self ._pipeline_analytics_processor ,
466+ identity_identifier = identifier ,
467+ traits = resolve_trait_values (traits ),
414468 )
415469 except FlagsmithAPIError :
416470 if self .offline_handler :
@@ -443,3 +497,6 @@ def __del__(self) -> None:
443497
444498 if hasattr (self , "event_stream_thread" ):
445499 self .event_stream_thread .stop ()
500+
501+ if self ._pipeline_analytics_processor :
502+ self ._pipeline_analytics_processor .stop ()
0 commit comments