2525 logger ,
2626 get_before_send_log ,
2727 has_logs_enabled ,
28+ has_trace_metrics_enabled ,
2829)
2930from sentry_sdk .serializer import serialize
3031from sentry_sdk .tracing import trace
@@ -184,6 +185,7 @@ def __init__(self, options=None):
184185 self .monitor = None # type: Optional[Monitor]
185186 self .metrics_aggregator = None # type: Optional[MetricsAggregator]
186187 self .log_batcher = None # type: Optional[LogBatcher]
188+ self .trace_metrics_batcher = None # type: Optional[TraceMetricsBatcher]
187189
188190 def __getstate__ (self , * args , ** kwargs ):
189191 # type: (*Any, **Any) -> Any
@@ -219,6 +221,10 @@ def _capture_experimental_log(self, log):
219221 # type: (Log) -> None
220222 pass
221223
224+ def _capture_trace_metric (self , metric ):
225+ # type: (TraceMetric) -> None
226+ pass
227+
222228 def capture_session (self , * args , ** kwargs ):
223229 # type: (*Any, **Any) -> None
224230 return None
@@ -388,6 +394,13 @@ def _capture_envelope(envelope):
388394
389395 self .log_batcher = LogBatcher (capture_func = _capture_envelope )
390396
397+ self .trace_metrics_batcher = None
398+
399+ if has_trace_metrics_enabled (self .options ):
400+ from sentry_sdk ._trace_metrics_batcher import TraceMetricsBatcher
401+
402+ self .trace_metrics_batcher = TraceMetricsBatcher (capture_func = _capture_envelope )
403+
391404 max_request_body_size = ("always" , "never" , "small" , "medium" )
392405 if self .options ["max_request_body_size" ] not in max_request_body_size :
393406 raise ValueError (
@@ -967,6 +980,56 @@ def _capture_experimental_log(self, log):
967980 if self .log_batcher :
968981 self .log_batcher .add (log )
969982
983+ def _capture_trace_metric (self , metric ):
984+ # type: (Optional[TraceMetric]) -> None
985+ if not has_trace_metrics_enabled (self .options ) or metric is None :
986+ return
987+
988+ current_scope = sentry_sdk .get_current_scope ()
989+ isolation_scope = sentry_sdk .get_isolation_scope ()
990+
991+ metric ["attributes" ]["sentry.sdk.name" ] = SDK_INFO ["name" ]
992+ metric ["attributes" ]["sentry.sdk.version" ] = SDK_INFO ["version" ]
993+
994+ environment = self .options .get ("environment" )
995+ if environment is not None and "sentry.environment" not in metric ["attributes" ]:
996+ metric ["attributes" ]["sentry.environment" ] = environment
997+
998+ release = self .options .get ("release" )
999+ if release is not None and "sentry.release" not in metric ["attributes" ]:
1000+ metric ["attributes" ]["sentry.release" ] = release
1001+
1002+ if isolation_scope ._user is not None :
1003+ for metric_attribute , user_attribute in (
1004+ ("user.id" , "id" ),
1005+ ("user.name" , "username" ),
1006+ ("user.email" , "email" ),
1007+ ):
1008+ if (
1009+ user_attribute in isolation_scope ._user
1010+ and metric_attribute not in metric ["attributes" ]
1011+ ):
1012+ metric ["attributes" ][metric_attribute ] = isolation_scope ._user [
1013+ user_attribute
1014+ ]
1015+
1016+ debug = self .options .get ("debug" , False )
1017+ if debug :
1018+ logger .debug (
1019+ f"[Sentry Trace Metrics] [{ metric .get ('type' )} ] { metric .get ('name' )} : { metric .get ('value' )} "
1020+ )
1021+
1022+ from sentry_sdk .utils import get_before_send_trace_metric
1023+ before_send_trace_metric = get_before_send_trace_metric (self .options )
1024+ if before_send_trace_metric is not None :
1025+ metric = before_send_trace_metric (metric , {})
1026+
1027+ if metric is None :
1028+ return
1029+
1030+ if self .trace_metrics_batcher :
1031+ self .trace_metrics_batcher .add (metric )
1032+
9701033 def capture_session (
9711034 self ,
9721035 session , # type: Session
@@ -1023,6 +1086,8 @@ def close(
10231086 self .metrics_aggregator .kill ()
10241087 if self .log_batcher is not None :
10251088 self .log_batcher .kill ()
1089+ if self .trace_metrics_batcher is not None :
1090+ self .trace_metrics_batcher .kill ()
10261091 if self .monitor :
10271092 self .monitor .kill ()
10281093 self .transport .kill ()
@@ -1049,6 +1114,8 @@ def flush(
10491114 self .metrics_aggregator .flush ()
10501115 if self .log_batcher is not None :
10511116 self .log_batcher .flush ()
1117+ if self .trace_metrics_batcher is not None :
1118+ self .trace_metrics_batcher .flush ()
10521119 self .transport .flush (timeout = timeout , callback = callback )
10531120
10541121 def __enter__ (self ):
0 commit comments