Skip to content

Commit

Permalink
Prevent OTEL from logging noisy traceback for handled requests except…
Browse files Browse the repository at this point in the history
…ions (#796)
  • Loading branch information
alexmojaki authored Jan 14, 2025
1 parent 9dad1d8 commit ec34449
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 6 deletions.
11 changes: 5 additions & 6 deletions logfire/_internal/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
ShowParentsConsoleSpanExporter,
SimpleConsoleSpanExporter,
)
from .exporters.otlp import OTLPExporterHttpSession, RetryFewerSpansSpanExporter
from .exporters.otlp import OTLPExporterHttpSession, QuietSpanExporter, RetryFewerSpansSpanExporter
from .exporters.processor_wrapper import CheckSuppressInstrumentationProcessorWrapper, MainSpanProcessorWrapper
from .exporters.quiet_metrics import QuietMetricExporter
from .exporters.remove_pending import RemovePendingSpansExporter
Expand Down Expand Up @@ -318,14 +318,12 @@ def configure( # noqa: D417
collect_system_metrics = deprecated_kwargs.pop('collect_system_metrics', None) # type: ignore
if collect_system_metrics is False:
raise ValueError(
'The `collect_system_metrics` argument has been removed. '
'System metrics are no longer collected by default.'
'The `collect_system_metrics` argument has been removed. System metrics are no longer collected by default.'
)

if collect_system_metrics is not None:
raise ValueError(
'The `collect_system_metrics` argument has been removed. '
'Use `logfire.instrument_system_metrics()` instead.'
'The `collect_system_metrics` argument has been removed. Use `logfire.instrument_system_metrics()` instead.'
)

scrubbing_callback = deprecated_kwargs.pop('scrubbing_callback', None) # type: ignore
Expand Down Expand Up @@ -858,6 +856,7 @@ def check_token():
session=session,
compression=Compression.Gzip,
)
span_exporter = QuietSpanExporter(span_exporter)
span_exporter = RetryFewerSpansSpanExporter(span_exporter)
span_exporter = RemovePendingSpansExporter(span_exporter)
schedule_delay_millis = _get_int_from_env(OTEL_BSP_SCHEDULE_DELAY) or 500
Expand Down Expand Up @@ -1332,7 +1331,7 @@ def use_existing_project(
[f'{index}. {item[0]}/{item[1]}' for index, item in project_choices.items()]
)
selected_project_key = Prompt.ask(
f'Please select one of the following projects by number:\n' f'{project_choices_str}\n',
f'Please select one of the following projects by number:\n{project_choices_str}\n',
choices=list(project_choices.keys()),
default='1',
)
Expand Down
11 changes: 11 additions & 0 deletions logfire/_internal/exporters/otlp.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,14 @@ def __init__(self, size: int, max_size: int) -> None:
super().__init__(f'Request body is too large ({size} bytes), must be less than {max_size} bytes.')
self.size = size
self.max_size = max_size


class QuietSpanExporter(WrapperSpanExporter):
"""A SpanExporter that catches request exceptions to prevent OTEL from logging a huge traceback."""

def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
try:
return super().export(spans)
except requests.exceptions.RequestException:
# Rely on OTLPExporterHttpSession/DiskRetryer to log this kind of error periodically.
return SpanExportResult.FAILURE
13 changes: 13 additions & 0 deletions tests/test_configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import inline_snapshot.extra
import pytest
import requests.exceptions
import requests_mock
from inline_snapshot import snapshot
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
Expand Down Expand Up @@ -46,6 +47,7 @@
sanitize_project_name,
)
from logfire._internal.exporters.console import ShowParentsConsoleSpanExporter
from logfire._internal.exporters.otlp import QuietSpanExporter
from logfire._internal.exporters.processor_wrapper import (
CheckSuppressInstrumentationProcessorWrapper,
MainSpanProcessorWrapper,
Expand Down Expand Up @@ -2065,3 +2067,14 @@ def test_distributed_tracing_disabled(exporter: TestExporter, config_kwargs: dic
},
]
)


def test_quiet_span_exporter(caplog: LogCaptureFixture):
class ConnectionErrorExporter(SpanExporter):
def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
raise requests.exceptions.ConnectionError()

exporter = QuietSpanExporter(ConnectionErrorExporter())

assert exporter.export([]) == SpanExportResult.FAILURE
assert not caplog.messages

0 comments on commit ec34449

Please sign in to comment.