Skip to content

Commit 270be59

Browse files
committed
ref: Make logs, metrics go via scope
1 parent 2ce4379 commit 270be59

File tree

7 files changed

+163
-144
lines changed

7 files changed

+163
-144
lines changed

sentry_sdk/_types.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -222,28 +222,33 @@ class SDKInfo(TypedDict):
222222
# TODO: Make a proper type definition for this (PRs welcome!)
223223
Hint = Dict[str, Any]
224224

225+
AttributeValue = (
226+
str | bool | float | int | list[str] | list[bool] | list[float] | list[int]
227+
)
228+
Attributes = dict[str, AttributeValue]
229+
230+
SerializedAttributeValue = TypedDict(
231+
"SerializedAttributeValue",
232+
{
233+
"type": Literal["string", "boolean", "double", "integer"],
234+
"value": AttributeValue,
235+
},
236+
)
237+
225238
Log = TypedDict(
226239
"Log",
227240
{
228241
"severity_text": str,
229242
"severity_number": int,
230243
"body": str,
231-
"attributes": dict[str, str | bool | float | int],
244+
"attributes": Attributes,
232245
"time_unix_nano": int,
233246
"trace_id": Optional[str],
234247
},
235248
)
236249

237250
MetricType = Literal["counter", "gauge", "distribution"]
238251

239-
MetricAttributeValue = TypedDict(
240-
"MetricAttributeValue",
241-
{
242-
"value": Union[str, bool, float, int],
243-
"type": Literal["string", "boolean", "double", "integer"],
244-
},
245-
)
246-
247252
Metric = TypedDict(
248253
"Metric",
249254
{
@@ -254,7 +259,7 @@ class SDKInfo(TypedDict):
254259
"type": MetricType,
255260
"value": float,
256261
"unit": Optional[str],
257-
"attributes": dict[str, str | bool | float | int],
262+
"attributes": Attributes,
258263
},
259264
)
260265

sentry_sdk/client.py

Lines changed: 26 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -932,137 +932,39 @@ def capture_event(
932932

933933
return return_value
934934

935-
def _capture_log(self, log):
936-
# type: (Optional[Log]) -> None
937-
if not has_logs_enabled(self.options) or log is None:
935+
def _capture_telemetry(self, telemetry, type_, scope):
936+
# type: (Telemetry, str, Scope) -> None
937+
# Capture attributes-based telemetry (logs, metrics, spansV2)
938+
before_send_getter = {
939+
"log": lambda: get_before_send_log(self.options),
940+
"metric": lambda: get_before_send_metric(self.options),
941+
}.get(type_)
942+
943+
if before_send_getter is not None:
944+
before_send = before_send_getter()
945+
if before_send is not None:
946+
telemetry = before_send(telemetry, {})
947+
948+
if telemetry is None:
938949
return
939950

940-
current_scope = sentry_sdk.get_current_scope()
941-
isolation_scope = sentry_sdk.get_isolation_scope()
942-
943-
log["attributes"]["sentry.sdk.name"] = SDK_INFO["name"]
944-
log["attributes"]["sentry.sdk.version"] = SDK_INFO["version"]
945-
946-
server_name = self.options.get("server_name")
947-
if server_name is not None and SPANDATA.SERVER_ADDRESS not in log["attributes"]:
948-
log["attributes"][SPANDATA.SERVER_ADDRESS] = server_name
949-
950-
environment = self.options.get("environment")
951-
if environment is not None and "sentry.environment" not in log["attributes"]:
952-
log["attributes"]["sentry.environment"] = environment
953-
954-
release = self.options.get("release")
955-
if release is not None and "sentry.release" not in log["attributes"]:
956-
log["attributes"]["sentry.release"] = release
957-
958-
trace_context = current_scope.get_trace_context()
959-
trace_id = trace_context.get("trace_id")
960-
span_id = trace_context.get("span_id")
961-
962-
if trace_id is not None and log.get("trace_id") is None:
963-
log["trace_id"] = trace_id
964-
965-
if (
966-
span_id is not None
967-
and "sentry.trace.parent_span_id" not in log["attributes"]
968-
):
969-
log["attributes"]["sentry.trace.parent_span_id"] = span_id
970-
971-
# The user, if present, is always set on the isolation scope.
972-
if isolation_scope._user is not None:
973-
for log_attribute, user_attribute in (
974-
("user.id", "id"),
975-
("user.name", "username"),
976-
("user.email", "email"),
977-
):
978-
if (
979-
user_attribute in isolation_scope._user
980-
and log_attribute not in log["attributes"]
981-
):
982-
log["attributes"][log_attribute] = isolation_scope._user[
983-
user_attribute
984-
]
985-
986-
# If debug is enabled, log the log to the console
987-
debug = self.options.get("debug", False)
988-
if debug:
989-
logger.debug(
990-
f"[Sentry Logs] [{log.get('severity_text')}] {log.get('body')}"
991-
)
951+
scope.apply_to_telemetry(telemetry)
992952

993-
before_send_log = get_before_send_log(self.options)
994-
if before_send_log is not None:
995-
log = before_send_log(log, {})
953+
batcher = {
954+
"log": self.log_batcher,
955+
"metric": self.metrics_batcher,
956+
}.get(type_) # type: Optional[LogBatcher, MetricsBatcher]
996957

997-
if log is None:
998-
return
958+
if batcher:
959+
batcher.add(telemetry)
999960

1000-
if self.log_batcher:
1001-
self.log_batcher.add(log)
961+
def _capture_log(self, log, scope):
962+
# type: (Optional[Log], Scope) -> None
963+
self._capture_telemetry(log, "log", scope)
1002964

1003-
def _capture_metric(self, metric):
965+
def _capture_metric(self, metric, scope):
1004966
# type: (Optional[Metric]) -> None
1005-
if not has_metrics_enabled(self.options) or metric is None:
1006-
return
1007-
1008-
current_scope = sentry_sdk.get_current_scope()
1009-
isolation_scope = sentry_sdk.get_isolation_scope()
1010-
1011-
metric["attributes"]["sentry.sdk.name"] = SDK_INFO["name"]
1012-
metric["attributes"]["sentry.sdk.version"] = SDK_INFO["version"]
1013-
1014-
server_name = self.options.get("server_name")
1015-
if (
1016-
server_name is not None
1017-
and SPANDATA.SERVER_ADDRESS not in metric["attributes"]
1018-
):
1019-
metric["attributes"][SPANDATA.SERVER_ADDRESS] = server_name
1020-
1021-
environment = self.options.get("environment")
1022-
if environment is not None and "sentry.environment" not in metric["attributes"]:
1023-
metric["attributes"]["sentry.environment"] = environment
1024-
1025-
release = self.options.get("release")
1026-
if release is not None and "sentry.release" not in metric["attributes"]:
1027-
metric["attributes"]["sentry.release"] = release
1028-
1029-
trace_context = current_scope.get_trace_context()
1030-
trace_id = trace_context.get("trace_id")
1031-
span_id = trace_context.get("span_id")
1032-
1033-
metric["trace_id"] = trace_id or "00000000-0000-0000-0000-000000000000"
1034-
if span_id is not None:
1035-
metric["span_id"] = span_id
1036-
1037-
if isolation_scope._user is not None:
1038-
for metric_attribute, user_attribute in (
1039-
("user.id", "id"),
1040-
("user.name", "username"),
1041-
("user.email", "email"),
1042-
):
1043-
if (
1044-
user_attribute in isolation_scope._user
1045-
and metric_attribute not in metric["attributes"]
1046-
):
1047-
metric["attributes"][metric_attribute] = isolation_scope._user[
1048-
user_attribute
1049-
]
1050-
1051-
debug = self.options.get("debug", False)
1052-
if debug:
1053-
logger.debug(
1054-
f"[Sentry Metrics] [{metric.get('type')}] {metric.get('name')}: {metric.get('value')}"
1055-
)
1056-
1057-
before_send_metric = get_before_send_metric(self.options)
1058-
if before_send_metric is not None:
1059-
metric = before_send_metric(metric, {})
1060-
1061-
if metric is None:
1062-
return
1063-
1064-
if self.metrics_batcher:
1065-
self.metrics_batcher.add(metric)
967+
self._capture_telemetry(metric, "metric", scope)
1066968

1067969
def capture_session(
1068970
self,

sentry_sdk/integrations/logging.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ def _capture_log_from_record(self, client, record):
409409
attrs["logger.name"] = record.name
410410

411411
# noinspection PyProtectedMember
412-
client._capture_log(
412+
sentry_sdk.get_current_scope()._capture_log(
413413
{
414414
"severity_text": otel_severity_text,
415415
"severity_number": otel_severity_number,

sentry_sdk/integrations/loguru.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def loguru_sentry_logs_handler(message):
201201
else:
202202
attrs[f"sentry.message.parameter.{key}"] = safe_repr(value)
203203

204-
client._capture_log(
204+
sentry_sdk.get_current_scope()._capture_log(
205205
{
206206
"severity_text": otel_severity_text,
207207
"severity_number": otel_severity_number,

sentry_sdk/logger.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import time
44
from typing import Any
55

6-
from sentry_sdk import get_client
6+
import sentry_sdk
77
from sentry_sdk.utils import safe_repr, capture_internal_exceptions
88

99
OTEL_RANGES = [
@@ -28,8 +28,6 @@ def __missing__(self, key):
2828

2929
def _capture_log(severity_text, severity_number, template, **kwargs):
3030
# type: (str, int, str, **Any) -> None
31-
client = get_client()
32-
3331
body = template
3432
attrs = {} # type: dict[str, str | bool | float | int]
3533
if "attributes" in kwargs:
@@ -58,7 +56,7 @@ def _capture_log(severity_text, severity_number, template, **kwargs):
5856
}
5957

6058
# noinspection PyProtectedMember
61-
client._capture_log(
59+
sentry_sdk.get_current_scope()._capture_log(
6260
{
6361
"severity_text": severity_text,
6462
"severity_number": severity_number,

sentry_sdk/metrics.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ def _capture_metric(
2121
attributes=None, # type: Optional[dict[str, Any]]
2222
):
2323
# type: (...) -> None
24-
client = sentry_sdk.get_client()
25-
2624
attrs = {} # type: dict[str, Union[str, bool, float, int]]
2725
if attributes:
2826
for k, v in attributes.items():
@@ -48,7 +46,7 @@ def _capture_metric(
4846
"attributes": attrs,
4947
} # type: Metric
5048

51-
client._capture_metric(metric)
49+
sentry_sdk.get_current_scope()._capture_metric(metric)
5250

5351

5452
def count(

0 commit comments

Comments
 (0)