Ensure functions have docstrings for documentation
def capture_envelope(self, envelope):
1"""Environment export remains active alongside independently configured SDKs."""23import pytest45from ._otlp import otlp_collector6from ._subprocess import run_in_subprocess789@pytest.mark.parametrize(10 "mode",11 [12 "global",13 "explicit",14 "sentry-first",15 "fastapi-first",16 "sentry-classic",17 "logfire",18 "logfire-opt-out",19 ],20)21@run_in_subprocess22def test_environment_export_with_existing_integrations(mode):23 import os2425 from fastapi import FastAPI26 from fastapi.telemetry import TelemetryConfig, _runtime27 from fastapi.testclient import TestClient28 from opentelemetry import _logs, metrics, trace29 from opentelemetry.proto.collector.logs.v1.logs_service_pb2 import (30 ExportLogsServiceRequest,31 )32 from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import (33 ExportMetricsServiceRequest,34 )35 from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import (36 ExportTraceServiceRequest,37 )38 from opentelemetry.proto.trace.v1.trace_pb2 import Span39 from opentelemetry.sdk._logs import LoggerProvider40 from opentelemetry.sdk._logs.export import (41 InMemoryLogRecordExporter,42 SimpleLogRecordProcessor,43 )44 from opentelemetry.sdk.metrics import MeterProvider45 from opentelemetry.sdk.metrics.export import InMemoryMetricReader46 from opentelemetry.sdk.trace import TracerProvider47 from opentelemetry.sdk.trace.export import SimpleSpanProcessor48 from opentelemetry.sdk.trace.export.in_memory_span_exporter import (49 InMemorySpanExporter,50 )5152 with otlp_collector() as (base, received):53 os.environ["FASTAPI_OTEL_AUTO_CONFIGURE"] = "true"54 os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = base + "/environment"55 os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = "x-cloud=preserved"56 os.environ["OTEL_BSP_SCHEDULE_DELAY"] = "60000"57 os.environ["OTEL_BLRP_SCHEDULE_DELAY"] = "60000"58 os.environ["OTEL_METRIC_EXPORT_INTERVAL"] = "60000"59 settings: TelemetryConfig = {}60 original_spans = InMemorySpanExporter()61 original_logs = InMemoryLogRecordExporter()62 original_metrics = InMemoryMetricReader()63 if mode in ("global", "explicit"):64 tp = TracerProvider(shutdown_on_exit=False)65 tp.add_span_processor(SimpleSpanProcessor(original_spans))66 mp = MeterProvider(67 metric_readers=[original_metrics], shutdown_on_exit=False68 )69 lp = LoggerProvider(shutdown_on_exit=False)70 lp.add_log_record_processor(SimpleLogRecordProcessor(original_logs))71 if mode == "global":72 trace.set_tracer_provider(tp)73 metrics.set_meter_provider(mp)74 _logs.set_logger_provider(lp)75 else:76 settings = {77 "tracer_provider": tp,78 "meter_provider": mp,79 "logger_provider": lp,80 }81 elif mode.startswith("logfire"):82 import logfire8384 logfire.configure(85 send_to_logfire=False,86 console=False,87 additional_span_processors=[SimpleSpanProcessor(original_spans)],88 metrics=logfire.MetricsOptions(additional_readers=[original_metrics]),89 advanced=logfire.AdvancedOptions(90 log_record_processors=[SimpleLogRecordProcessor(original_logs)]91 ),92 )93 settings["auto_configure"] = mode != "logfire-opt-out"94 else:95 import sentry_sdk96 from sentry_sdk.integrations.fastapi import FastApiIntegration97 from sentry_sdk.integrations.otlp import OTLPIntegration98 from sentry_sdk.integrations.starlette import StarletteIntegration99 from sentry_sdk.transport import Transport100101 items = []102103 class LocalTransport(Transport):104 def capture_envelope(self, envelope):105 items.extend(item.type for item in envelope.items)106107 if mode == "fastapi-first":108 with TestClient(FastAPI()):109 pass110 integrations = (111 [StarletteIntegration(), FastApiIntegration()]112 if mode == "sentry-classic"113 else [114 OTLPIntegration(115 collector_url=base + "/sentry/traces", setup_propagator=False116 )117 ]118 )119 sentry_sdk.init(120 dsn="https://public@example.invalid/1",121 transport=LocalTransport,122 default_integrations=False,123 auto_enabling_integrations=False,124 integrations=integrations,125 traces_sample_rate=1.0,126 send_client_reports=False,127 )128129 app = FastAPI(telemetry=settings)130131 @app.get("/items/{item_id}")132 def endpoint(item_id: int):133 raise ValueError("environment export")134135 try:136 for _ in range(2):137 with TestClient(app, raise_server_exceptions=False) as client:138 assert client.get("/items/1").status_code == 500139 if mode.startswith("logfire"):140 logfire.force_flush()141 elif mode.startswith("sentry") or mode == "fastapi-first":142 tracer_provider = trace.get_tracer_provider()143 assert isinstance(tracer_provider, TracerProvider)144 tracer_provider.force_flush()145 sentry_sdk.flush()146147 def spans_at(path):148 requests = [149 ExportTraceServiceRequest.FromString(body)150 for url, body, _ in received151 if url == path152 ]153 return [154 span155 for request in requests156 for resource in request.resource_spans157 for scope in resource.scope_spans158 for span in scope.spans159 ]160161 environment_spans = spans_at("/environment/v1/traces")162 multiplier = 2 if mode == "logfire" else 1163 servers = [164 span for span in environment_spans if span.kind == Span.SPAN_KIND_SERVER165 ]166 assert len(servers) == 2 * multiplier, (mode, len(servers))167 assert len({span.span_id for span in servers}) == 2168 assert all(span.name == "GET /items/{item_id}" for span in servers)169 if mode in ("global", "explicit"):170 assert sorted(171 (span.context.trace_id, span.context.span_id, span.name)172 for span in original_spans.get_finished_spans()173 ) == sorted(174 (175 int.from_bytes(span.trace_id, "big"),176 int.from_bytes(span.span_id, "big"),177 span.name,178 )179 for span in environment_spans180 )181 if mode in ("sentry-first", "fastapi-first"):182 sentry_spans = spans_at("/sentry/traces")183 assert {span.span_id for span in sentry_spans} == {184 span.span_id for span in environment_spans185 }186 if mode == "sentry-classic":187 assert items.count("event") == 2, items188 assert items.count("transaction") == 2, items189190 log_requests = [191 ExportLogsServiceRequest.FromString(body)192 for url, body, _ in received193 if url == "/environment/v1/logs"194 ]195 logs = [196 record197 for request in log_requests198 for resource in request.resource_logs199 for scope in resource.scope_logs200 for record in scope.log_records201 ]202 assert len(logs) == 2 * multiplier, (mode, len(logs))203 assert all(204 record.trace_id in {span.trace_id for span in servers}205 for record in logs206 )207 metric_requests = [208 ExportMetricsServiceRequest.FromString(body)209 for url, body, _ in received210 if url == "/environment/v1/metrics"211 ]212 counts = [213 point.count214 for request in metric_requests215 for resource in request.resource_metrics216 for scope in resource.scope_metrics217 for metric in scope.metrics218 if metric.name == "http.server.request.duration"219 for point in getattr(metric, metric.WhichOneof("data")).data_points220 ]221 assert counts and counts[-1] == 2, counts222 assert all(223 headers.get("x-cloud") == "preserved"224 for url, _, headers in received225 if url.startswith("/environment/")226 )227 assert len(_runtime._configured) == (0 if mode == "logfire-opt-out" else 3)228 _runtime._shutdown()229 if mode in ("global", "explicit"):230 # FastAPI's cleanup closes its own exporters, leaving the provider and231 # previously installed vendor components usable.232 count = len(original_spans.get_finished_spans())233 with tp.get_tracer("vendor").start_as_current_span("still-running"):234 pass235 assert len(original_spans.get_finished_spans()) == count + 1236 lp.get_logger("vendor").emit(body="still-running")237 assert len(original_logs.get_finished_logs()) == 3238 assert original_metrics.get_metrics_data() is not None239 tp.shutdown()240 mp.shutdown()241 lp.shutdown()242 finally:243 _runtime._shutdown()244 if mode.startswith("logfire"):245 logfire.shutdown()
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.
Generated by searchcode.com · powered by code_get_file + code_get_findings