Per-request OpenTelemetry configuration. Attached to an invocation via ``RunConfig.telemetry``. Any field left as ``None`` falls back to its corresponding env var (an ``OTEL_*`` var, plus the default-on ``ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS`` for legacy spans). ``frozen=True`` lets the sam
| 79 | |
| 80 | |
| 81 | class TelemetryConfig(BaseModel): |
| 82 | """Per-request OpenTelemetry configuration. |
| 83 | |
| 84 | Attached to an invocation via ``RunConfig.telemetry``. Any field left as |
| 85 | ``None`` falls back to its corresponding env var (an ``OTEL_*`` var, plus the |
| 86 | default-on ``ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS`` for legacy spans). |
| 87 | ``frozen=True`` lets the same config be shared safely across concurrent |
| 88 | invocations; the resolution properties read env lazily, so later |
| 89 | ``os.environ`` changes are still picked up. |
| 90 | |
| 91 | Limitations: |
| 92 | * When ``opentelemetry-instrumentation-google-genai`` is installed and |
| 93 | wraps ``google.genai.Models.generate_content``, span creation is |
| 94 | delegated to that library, which reads its own OTel env vars; per-request |
| 95 | overrides are inoperative for the inference span (but still apply to |
| 96 | ADK-owned spans). |
| 97 | |
| 98 | Attributes: |
| 99 | genai_semconv_stability_opt_in: Override for |
| 100 | ``OTEL_SEMCONV_STABILITY_OPT_IN``. ``'experimental'`` opts in to the |
| 101 | experimental GenAI semconv attributes; ``'stable'`` keeps the legacy path. |
| 102 | ``'stable'`` has no env-var equivalent (the env path infers stable from |
| 103 | the absence of ``'gen_ai_latest_experimental'`` in the CSV). |
| 104 | capture_message_content: Override for |
| 105 | ``OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT``. Pass a |
| 106 | :class:`ContentCapturingMode` member; the env-var path accepts the |
| 107 | matching uppercase string. |
| 108 | """ |
| 109 | |
| 110 | model_config = ConfigDict(frozen=True, extra='forbid') |
| 111 | |
| 112 | genai_semconv_stability_opt_in: Optional[ |
| 113 | Literal['stable', 'experimental'] |
| 114 | ] = None |
| 115 | capture_message_content: Optional[ContentCapturingMode] = None |
| 116 | |
| 117 | @property |
| 118 | def _ignore_per_request(self) -> bool: |
| 119 | """Whether the admin lock (``ADK_TELEMETRY_IGNORE_RUN_CONFIG``) is set. |
| 120 | |
| 121 | When set, the per-request fields are ignored and resolution falls back to |
| 122 | the ``OTEL_*`` env vars. |
| 123 | """ |
| 124 | lock = os.getenv(ADK_TELEMETRY_IGNORE_RUN_CONFIG, '').strip().lower() |
| 125 | return lock in _TRUTHY_ENV_VALUES |
| 126 | |
| 127 | @property |
| 128 | def should_use_experimental_genai_semconv(self) -> bool: |
| 129 | """Whether to emit experimental GenAI semconv attributes. |
| 130 | |
| 131 | Precedence: admin lock > ``genai_semconv_stability_opt_in`` > |
| 132 | ``OTEL_SEMCONV_STABILITY_OPT_IN`` env var > ``False``. |
| 133 | """ |
| 134 | if ( |
| 135 | not self._ignore_per_request |
| 136 | and self.genai_semconv_stability_opt_in is not None |
| 137 | ): |
| 138 | return self.genai_semconv_stability_opt_in == 'experimental' |
no outgoing calls