Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions docs/introduction/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Additional parameters can also be supplied through the settings object:
- `sentry_traces_sample_rate` - in the range of 0.0 to 1.0, the percentage chance a given transaction will be sent
- `sentry_sample_rate` - in the range of 0.0 to 1.0, the sample rate for error events
- `sentry_max_breadcrumbs` - the total amount of breadcrumbs
- `sentry_max_value_length` - the max event payload length
- `sentry_max_value_length` - the maximum length of each string value before sentry-sdk truncates it
- `sentry_attach_stacktrace` - if True, stack traces are automatically attached to all messages logged
- `sentry_auto_session_tracking` - whether every request opens and closes a Sentry release-health `Session` (default: `False`), measured at ~7.7 µs per request. Set it to `True` if you use Sentry release health: crash-free session and user rates need it.
- `sentry_integrations` - list of integrations to enable
Expand Down Expand Up @@ -346,7 +346,7 @@ See [Performance](performance.md).
Additional parameters:

- `logging_enabled` - whether to configure structlog (default: `True`).
- `logging_log_level`
- `logging_log_level` - the root logger level set at bootstrap (default: `logging.INFO`).
- `logging_extra_processors`
- `logging_unset_handlers` - logger names whose handlers are cleared at bootstrap. These removals are permanent.
- `logging_record_filters` - standard-library `logging.Filter` instances to attach to named loggers (see below).
Expand Down Expand Up @@ -538,8 +538,6 @@ from lite_bootstrap import InstrumentDependencyMissingWarning
warnings.filterwarnings("ignore", category=InstrumentDependencyMissingWarning)
```

`InstrumentSkippedWarning` is kept as the base class for forward-compatibility (additional skip categories may emerge); today, `InstrumentDependencyMissingWarning` is its only concrete subclass.

To inspect skipped instruments programmatically:

```python
Expand Down
17 changes: 17 additions & 0 deletions docs/migration/to-2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,20 @@ traffic mix.
JSON log lines include `tracing` only when emitted inside a recording
OpenTelemetry span. The object contains `span_id` and `trace_id`.
Update log parsers to treat `tracing` as optional.

## Missing-dependency warning category

`InstrumentSkippedWarning` has been removed. Importing it from `lite_bootstrap`
now raises `ImportError`. Replace imports and warning filters with
`InstrumentDependencyMissingWarning`, which now derives directly from `UserWarning`:

```python
import warnings

from lite_bootstrap import InstrumentDependencyMissingWarning

warnings.filterwarnings("error", category=InstrumentDependencyMissingWarning)
```

Unconfigured instruments continue to be skipped silently. A configured instrument
with a missing optional dependency emits `InstrumentDependencyMissingWarning`.
2 changes: 0 additions & 2 deletions lite_bootstrap/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
BootstrapperNotReadyError,
ConfigurationError,
InstrumentDependencyMissingWarning,
InstrumentSkippedWarning,
LiteBootstrapError,
TeardownError,
)
Expand All @@ -26,7 +25,6 @@
"FreeBootstrapper",
"FreeConfig",
"InstrumentDependencyMissingWarning",
"InstrumentSkippedWarning",
"LiteBootstrapError",
"LitestarBootstrapper",
"LitestarConfig",
Expand Down
2 changes: 0 additions & 2 deletions lite_bootstrap/bootstrappers/fastapi_bootstrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,6 @@ def bootstrap(self) -> None:


class FastAPIBootstrapper(BaseBootstrapper["fastapi.FastAPI", FastAPIConfig]):
__slots__ = "bootstrap_config", "instruments"

instruments_types: typing.ClassVar = [
FastAPICorsInstrument,
FastAPIOpenTelemetryInstrument,
Expand Down
2 changes: 0 additions & 2 deletions lite_bootstrap/bootstrappers/fastmcp_bootstrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,6 @@ def bootstrap(self) -> None:


class FastMcpBootstrapper(BaseBootstrapper["FastMCP[typing.Any]", FastMcpConfig]):
__slots__ = "bootstrap_config", "instruments"

instruments_types: typing.ClassVar = [
FastMcpOpenTelemetryInstrument,
PyroscopeInstrument,
Expand Down
4 changes: 0 additions & 4 deletions lite_bootstrap/bootstrappers/faststream_bootstrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ async def after_processed(
tracer: typing.Final = trace.get_tracer(__name__)


@typing.runtime_checkable
class FastStreamTelemetryMiddlewareProtocol(typing.Protocol):
def __init__(
self,
Expand All @@ -71,7 +70,6 @@ def __init__(
def __call__(self, msg: typing.Any, /, *, context: typing.Any) -> typing.Any: ... # noqa: ANN401


@typing.runtime_checkable
class FastStreamPrometheusMiddlewareProtocol(typing.Protocol):
def __init__(
self,
Expand Down Expand Up @@ -266,8 +264,6 @@ def bootstrap(self) -> None:


class FastStreamBootstrapper(BaseBootstrapper["AsgiFastStream", FastStreamConfig]):
__slots__ = "bootstrap_config", "instruments"

instruments_types: typing.ClassVar = [
FastStreamOpenTelemetryInstrument,
PyroscopeInstrument,
Expand Down
2 changes: 0 additions & 2 deletions lite_bootstrap/bootstrappers/free_bootstrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ class FreeConfig(LoggingConfig, OpenTelemetryConfig, PyroscopeConfig, SentryConf


class FreeBootstrapper(BaseBootstrapper[None, FreeConfig]):
__slots__ = "bootstrap_config", "instruments"

instruments_types: typing.ClassVar = [
LoggingInstrument,
SentryInstrument,
Expand Down
2 changes: 0 additions & 2 deletions lite_bootstrap/bootstrappers/litestar_bootstrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,8 +485,6 @@ def bootstrap(self) -> None:


class LitestarBootstrapper(BaseBootstrapper["litestar.Litestar", LitestarConfig]):
__slots__ = "bootstrap_config", "instruments"

instruments_types: typing.ClassVar = [
LitestarCorsInstrument,
LitestarOpenTelemetryInstrument,
Expand Down
13 changes: 5 additions & 8 deletions lite_bootstrap/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ class BootstrapperNotReadyError(LiteBootstrapError):


class ConfigurationError(LiteBootstrapError):
"""Raised when a config is invalid or a required optional dependency is missing.
"""Raised for invalid configuration or when bootstrap() cannot use the application.

Also raised when a bootstrapper is constructed on an application another bootstrapper
already owns.
bootstrap() rejects an application owned by another bootstrapper and refuses to reuse
a bootstrapper after teardown or a failed bootstrap. Missing optional dependencies warn
instead, as does construction on an application another bootstrapper already owns.
"""


Expand All @@ -28,11 +29,7 @@ def __init__(self, errors: list[tuple[str, BaseException]]) -> None:
super().__init__(f"{len(errors)} instrument(s) failed during teardown: {details}")


class InstrumentSkippedWarning(UserWarning):
"""Base class for warnings emitted when an instrument is skipped during bootstrap."""


class InstrumentDependencyMissingWarning(InstrumentSkippedWarning):
class InstrumentDependencyMissingWarning(UserWarning):
"""Emitted when an instrument is skipped because its optional dependency is not installed."""


Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ faststream-metrics = [
]
faststream-all = [
"lite-bootstrap[faststream-sentry,faststream-otl,faststream-logging,faststream-metrics,pyroscope]",
"lite-bootstrap[sentry,otl,logging,faststream,faststream-metrics,pyroscope]"
]
fastmcp = [
# >=4.0 so one middleware dispatch model is supported: from 4.0 the access log's on_message sees
Expand Down
6 changes: 3 additions & 3 deletions scripts/floor_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
config with every instrument its extras can supply, bootstraps, exercises the calls
that set a floor, and tears down.

`InstrumentSkippedWarning` is escalated to an error, because an instrument that
`InstrumentDependencyMissingWarning` is escalated to an error, because an instrument that
degrades to a silent skip would let a too-low floor pass as success.

Not a pytest test: conftest.py hard-imports opentelemetry, sentry_sdk and structlog,
Expand All @@ -31,7 +31,7 @@
FastStreamConfig,
FreeBootstrapper,
FreeConfig,
InstrumentSkippedWarning,
InstrumentDependencyMissingWarning,
LitestarBootstrapper,
LitestarConfig,
import_checker,
Expand Down Expand Up @@ -338,7 +338,7 @@ def main() -> None:
expected_argv_len = 2
if len(sys.argv) != expected_argv_len or sys.argv[1] not in TARGETS:
sys.exit(f"usage: floor_smoke.py {{{'|'.join(TARGETS)}}}")
warnings.filterwarnings("error", category=InstrumentSkippedWarning)
warnings.filterwarnings("error", category=InstrumentDependencyMissingWarning)
target = sys.argv[1]
TARGETS[target]()
print(f"floor smoke OK: {target} on {sys.version}") # noqa: T201
Expand Down
6 changes: 3 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@
from structlog.typing import EventDict, WrappedLogger

from lite_bootstrap import import_checker
from lite_bootstrap.exceptions import InstrumentSkippedWarning
from lite_bootstrap.exceptions import InstrumentDependencyMissingWarning
from lite_bootstrap.instruments import healthchecks_instrument, opentelemetry_instrument


def pytest_configure() -> None:
"""Escalate InstrumentSkippedWarning (and subclasses) to errors.
"""Escalate InstrumentDependencyMissingWarning (and subclasses) to errors.

Done here rather than via filterwarnings in pyproject.toml to avoid pytest
resolving the warning class before pytest-cov starts coverage, which would
cause coverage to miss the lite_bootstrap module-level statements.
"""
warnings.filterwarnings("error", category=InstrumentSkippedWarning)
warnings.filterwarnings("error", category=InstrumentDependencyMissingWarning)


class CustomInstrumentor(BaseInstrumentor):
Expand Down
Loading