Skip to content

Commit 2fef9bc

Browse files
authored
chore: Make enable_logs, enable_metrics no-op (#7177)
We're making `enable_logs` and `enable_metrics` no-op with this change, and they'll be dropped in the next major. There's no need for an additional hurdle for using the logs and metrics APIs -- opting to use the API is opt-in enough. Previously, `enable_logs` also controlled automatic logs collection from the logging and Loguru integrations. These integrations now get an integration-level `capture_sentry_logs` boolean option to allow for more control over the auto-collection. These options are `False` by default, i.e., **nothing is auto-collected without your explicit opt-in**. If you want to enable auto-collection, do: ```python import sentry_sdk from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.loguru import LoguruIntegration sentry_sdk.init( integrations=[ LoggingIntegration(capture_sentry_logs=True), LoguruIntegration(capture_sentry_logs=True), ] ) ``` Closes #6195
1 parent 8177739 commit 2fef9bc

9 files changed

Lines changed: 173 additions & 125 deletions

File tree

sentry_sdk/client.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from typing import TYPE_CHECKING, Dict, List, cast, overload
1313

1414
from sentry_sdk._compat import check_uwsgi_thread_support
15+
from sentry_sdk._log_batcher import LogBatcher
1516
from sentry_sdk._metrics_batcher import MetricsBatcher
1617
from sentry_sdk._span_batcher import SpanBatcher
1718
from sentry_sdk.consts import (
@@ -64,8 +65,6 @@
6465
get_type_name,
6566
handle_in_app,
6667
has_data_collection_enabled,
67-
has_logs_enabled,
68-
has_metrics_enabled,
6968
logger,
7069
)
7170

@@ -649,22 +648,27 @@ def _record_lost_event(
649648

650649
self.session_flusher = SessionFlusher(capture_func=_capture_envelope)
651650

652-
self.log_batcher = None
651+
if self.options.get("enable_logs", False) or self.options[
652+
"_experiments"
653+
].get("enable_logs", False):
654+
logger.warning(
655+
"The enable_logs option has no effect and will be removed in the next major."
656+
)
653657

654-
if has_logs_enabled(self.options):
655-
from sentry_sdk._log_batcher import LogBatcher
658+
self.log_batcher = LogBatcher(
659+
capture_func=_capture_envelope,
660+
record_lost_func=_record_lost_event,
661+
)
656662

657-
self.log_batcher = LogBatcher(
658-
capture_func=_capture_envelope,
659-
record_lost_func=_record_lost_event,
663+
if self.options.get("enable_metrics", True) is False:
664+
logger.warning(
665+
"The enable_metrics option has no effect and will be removed in the next major."
660666
)
661667

662-
self.metrics_batcher = None
663-
if has_metrics_enabled(self.options):
664-
self.metrics_batcher = MetricsBatcher(
665-
capture_func=_capture_envelope,
666-
record_lost_func=_record_lost_event,
667-
)
668+
self.metrics_batcher = MetricsBatcher(
669+
capture_func=_capture_envelope,
670+
record_lost_func=_record_lost_event,
671+
)
668672

669673
self.span_batcher = None
670674
if has_span_streaming_enabled(self.options):

sentry_sdk/integrations/logging.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
capture_internal_exceptions,
1313
current_stacktrace,
1414
event_from_exception,
15-
has_logs_enabled,
1615
safe_repr,
1716
to_string,
1817
)
@@ -115,13 +114,17 @@ def unignore_logger_for_sentry_logs(
115114

116115
class LoggingIntegration(Integration):
117116
identifier = "logging"
117+
capture_sentry_logs: "Optional[bool]" = False
118118

119119
def __init__(
120120
self,
121121
level: "Optional[int]" = DEFAULT_LEVEL,
122122
event_level: "Optional[int]" = DEFAULT_EVENT_LEVEL,
123123
sentry_logs_level: "Optional[int]" = DEFAULT_LEVEL,
124+
capture_sentry_logs: "Optional[bool]" = False,
124125
) -> None:
126+
LoggingIntegration.capture_sentry_logs = capture_sentry_logs
127+
125128
self._handler = None
126129
self._breadcrumb_handler = None
127130
self._sentry_logs_handler = None
@@ -378,7 +381,7 @@ class SentryLogsHandler(_BaseHandler):
378381
"""
379382
A logging handler that records Sentry logs for each Python log record.
380383
381-
Note that you do not have to use this class if the logging integration is enabled, which it is by default.
384+
Note that you do not have to use this class if the LoggingIntegration's capture_sentry_logs option is enabled.
382385
"""
383386

384387
def _can_record(self, record: "LogRecord") -> bool:
@@ -398,7 +401,7 @@ def emit(self, record: "LogRecord") -> "Any":
398401
if not client.is_active():
399402
return
400403

401-
if not has_logs_enabled(client.options):
404+
if not LoggingIntegration.capture_sentry_logs:
402405
return
403406

404407
self._capture_log_from_record(client, record)
@@ -462,7 +465,6 @@ def _capture_log_from_record(
462465
if record.name:
463466
attrs["logger.name"] = record.name
464467

465-
# noinspection PyProtectedMember
466468
sentry_sdk.get_current_scope()._capture_log(
467469
{
468470
"severity_text": otel_severity_text,

sentry_sdk/integrations/loguru.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
_BaseHandler,
1010
)
1111
from sentry_sdk.logger import _log_level_to_otel
12-
from sentry_sdk.utils import has_logs_enabled, safe_repr
12+
from sentry_sdk.utils import safe_repr
1313

1414
if TYPE_CHECKING:
1515
from logging import LogRecord
@@ -70,6 +70,7 @@ class LoguruIntegration(Integration):
7070
breadcrumb_format = DEFAULT_FORMAT
7171
event_format = DEFAULT_FORMAT
7272
sentry_logs_level: "Optional[int]" = DEFAULT_LEVEL
73+
capture_sentry_logs: "Optional[bool]" = False
7374

7475
def __init__(
7576
self,
@@ -78,12 +79,14 @@ def __init__(
7879
breadcrumb_format: "str | loguru.FormatFunction" = DEFAULT_FORMAT,
7980
event_format: "str | loguru.FormatFunction" = DEFAULT_FORMAT,
8081
sentry_logs_level: "Optional[int]" = DEFAULT_LEVEL,
82+
capture_sentry_logs: "Optional[bool]" = False,
8183
) -> None:
8284
LoguruIntegration.level = level
8385
LoguruIntegration.event_level = event_level
8486
LoguruIntegration.breadcrumb_format = breadcrumb_format
8587
LoguruIntegration.event_format = event_format
8688
LoguruIntegration.sentry_logs_level = sentry_logs_level
89+
LoguruIntegration.capture_sentry_logs = capture_sentry_logs
8790

8891
@staticmethod
8992
def setup_once() -> None:
@@ -142,11 +145,10 @@ def loguru_sentry_logs_handler(message: "Message") -> None:
142145
# This is intentionally a callable sink instead of a standard logging handler
143146
# since otherwise we wouldn't get direct access to message.record
144147
client = sentry_sdk.get_client()
145-
146148
if not client.is_active():
147149
return
148150

149-
if not has_logs_enabled(client.options):
151+
if not LoguruIntegration.capture_sentry_logs:
150152
return
151153

152154
record = message.record

sentry_sdk/scope.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@
5858
exc_info_from_error,
5959
format_attribute,
6060
has_data_collection_enabled,
61-
has_logs_enabled,
62-
has_metrics_enabled,
6361
logger,
6462
)
6563

@@ -1487,8 +1485,6 @@ def _capture_log(self, log: "Optional[Log]") -> None:
14871485
return
14881486

14891487
client = self.get_client()
1490-
if not has_logs_enabled(client.options):
1491-
return
14921488

14931489
merged_scope = self._merge_scopes()
14941490

@@ -1505,8 +1501,6 @@ def _capture_metric(self, metric: "Optional[Metric]") -> None:
15051501
return
15061502

15071503
client = self.get_client()
1508-
if not has_metrics_enabled(client.options):
1509-
return
15101504

15111505
merged_scope = self._merge_scopes()
15121506

sentry_sdk/utils.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,16 +2070,6 @@ def serialize_item(
20702070
return str(data)
20712071

20722072

2073-
def has_logs_enabled(options: "Optional[dict[str, Any]]") -> bool:
2074-
if options is None:
2075-
return False
2076-
2077-
return bool(
2078-
options.get("enable_logs", False)
2079-
or options["_experiments"].get("enable_logs", False)
2080-
)
2081-
2082-
20832073
def has_data_collection_enabled(options: "Optional[dict[str, Any]]") -> bool:
20842074
if options is None:
20852075
return False
@@ -2098,13 +2088,6 @@ def get_before_send_log(
20982088
)
20992089

21002090

2101-
def has_metrics_enabled(options: "Optional[dict[str, Any]]") -> bool:
2102-
if options is None:
2103-
return False
2104-
2105-
return bool(options.get("enable_metrics", True))
2106-
2107-
21082091
def get_before_send_metric(
21092092
options: "Optional[dict[str, Any]]",
21102093
) -> "Optional[Callable[[Metric, Hint], Optional[Metric]]]":

tests/integrations/logging/test_logging.py

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,37 @@ def test_logging_captured_warnings(sentry_init, capture_events, recwarn):
231231
assert len(third_warnings) == 1
232232

233233

234+
def test_sentry_logs_collection_off_by_default(sentry_init, capture_items, request):
235+
"""Automatic logs capture by Sentry logs needs explicit opt-in via capture_sentry_logs."""
236+
sentry_init()
237+
items = capture_items("log")
238+
239+
python_logger = logging.Logger("test-logger")
240+
python_logger.warning("this is %s a template %s", "1", "2")
241+
242+
get_client().flush()
243+
244+
assert not items
245+
246+
247+
def test_sentry_logs_collection_opt_in(sentry_init, capture_items, request):
248+
"""Automatic logs capture by Sentry logs needs explicit opt-in via capture_sentry_logs."""
249+
sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)])
250+
items = capture_items("log")
251+
252+
python_logger = logging.Logger("test-logger")
253+
python_logger.warning("this is %s a template %s", "1", "2")
254+
255+
get_client().flush()
256+
257+
assert len(items) == 1
258+
259+
log = items[0].payload
260+
assert log["attributes"]["sentry.message.template"] == "this is %s a template %s"
261+
assert log["attributes"]["sentry.severity_number"] == 13
262+
assert log["attributes"]["sentry.severity_text"] == "warn"
263+
264+
234265
def test_ignore_logger(sentry_init, capture_events, request):
235266
sentry_init(integrations=[LoggingIntegration()], default_integrations=False)
236267
events = capture_events()
@@ -276,7 +307,7 @@ def test_ignore_logger_wildcard(sentry_init, capture_events, request):
276307

277308
def test_ignore_logger_does_not_affect_sentry_logs(sentry_init, capture_items, request):
278309
"""ignore_logger should suppress events/breadcrumbs but not Sentry Logs."""
279-
sentry_init(enable_logs=True)
310+
sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)])
280311
items = capture_items("log")
281312

282313
ignore_logger("testfoo")
@@ -294,7 +325,7 @@ def test_ignore_logger_for_sentry_logs(
294325
sentry_init, capture_envelopes, capture_items, request
295326
):
296327
"""ignore_logger_for_sentry_logs should suppress Sentry Logs but not events."""
297-
sentry_init(enable_logs=True)
328+
sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)])
298329
envelopes = capture_envelopes()
299330
items = capture_items("log")
300331

@@ -355,7 +386,7 @@ def test_sentry_logs_warning(sentry_init, capture_items):
355386
"""
356387
The python logger module should create 'warn' sentry logs if the flag is on.
357388
"""
358-
sentry_init(enable_logs=True)
389+
sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)])
359390
items = capture_items("log")
360391

361392
python_logger = logging.Logger("test-logger")
@@ -380,7 +411,7 @@ def test_sentry_logs_debug(sentry_init, capture_envelopes):
380411
"""
381412
The python logger module should not create 'debug' sentry logs if the flag is on by default
382413
"""
383-
sentry_init(enable_logs=True)
414+
sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)])
384415
envelopes = capture_envelopes()
385416

386417
python_logger = logging.Logger("test-logger")
@@ -395,8 +426,11 @@ def test_no_log_infinite_loop(sentry_init, capture_envelopes):
395426
If 'debug' mode is true, and you set a low log level in the logging integration, there should be no infinite loops.
396427
"""
397428
sentry_init(
398-
enable_logs=True,
399-
integrations=[LoggingIntegration(sentry_logs_level=logging.DEBUG)],
429+
integrations=[
430+
LoggingIntegration(
431+
capture_sentry_logs=True, sentry_logs_level=logging.DEBUG
432+
)
433+
],
400434
debug=True,
401435
)
402436
envelopes = capture_envelopes()
@@ -412,7 +446,7 @@ def test_logging_errors(sentry_init, capture_envelopes, capture_items):
412446
"""
413447
The python logger module should be able to log errors without erroring
414448
"""
415-
sentry_init(enable_logs=True)
449+
sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)])
416450
envelopes = capture_envelopes()
417451
items = capture_items("log")
418452

@@ -448,8 +482,8 @@ def test_log_strips_project_root(sentry_init, capture_items):
448482
The python logger should strip project roots from the log record path
449483
"""
450484
sentry_init(
451-
enable_logs=True,
452485
project_root="/custom/test",
486+
integrations=[LoggingIntegration(capture_sentry_logs=True)],
453487
)
454488
items = capture_items("log")
455489

@@ -477,7 +511,7 @@ def test_logger_with_all_attributes(sentry_init, capture_items):
477511
"""
478512
The python logger should be able to log all attributes, including extra data.
479513
"""
480-
sentry_init(enable_logs=True)
514+
sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)])
481515
items = capture_items("log")
482516

483517
python_logger = logging.Logger("test-logger")
@@ -554,7 +588,7 @@ def test_sentry_logs_named_parameters(sentry_init, capture_items):
554588
"""
555589
The python logger module should capture named parameters from dictionary arguments in Sentry logs.
556590
"""
557-
sentry_init(enable_logs=True)
591+
sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)])
558592
items = capture_items("log")
559593

560594
python_logger = logging.Logger("test-logger")
@@ -599,7 +633,7 @@ def test_sentry_logs_named_parameters_complex_values(sentry_init, capture_items)
599633
"""
600634
The python logger module should handle complex values in named parameters using safe_repr.
601635
"""
602-
sentry_init(enable_logs=True)
636+
sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)])
603637
items = capture_items("log")
604638

605639
python_logger = logging.Logger("test-logger")
@@ -633,7 +667,7 @@ def test_sentry_logs_no_parameters_no_template(sentry_init, capture_items):
633667
"""
634668
There shouldn't be a template if there are no parameters.
635669
"""
636-
sentry_init(enable_logs=True)
670+
sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)])
637671
items = capture_items("log")
638672

639673
python_logger = logging.Logger("test-logger")

0 commit comments

Comments
 (0)