- harness/es.py: append-only event store + проекции (образец — кооп-портал) - harness/levels.py: уровни 1с/1м/1ч/1д, контекст ∝ масштабу - harness/scheduler.py: уровневые потоки, идемпотентные тики, absorbed-стабы - harness/isolated_runner.py + _llm_worker.py: LLM-тик в сабпроцессе (глобальный asyncio-рантайм Strands не переживает 2+ create_harness) - cli.py: init/task/tasks/status/events + requeue (написан самим минутным агентом) - 9router: отдельный ключ sk-simbiot, модель auto (glm-5.3 первым)
725 lines
22 KiB
Python
725 lines
22 KiB
Python
# Copyright The OpenTelemetry Authors
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import threading
|
|
from collections.abc import Container, Mapping, MutableMapping
|
|
from enum import Enum
|
|
from urllib.parse import urlparse
|
|
|
|
from packaging import version as package_version
|
|
|
|
from opentelemetry.instrumentation.utils import http_status_to_status_code
|
|
from opentelemetry.semconv._incubating.attributes.db_attributes import (
|
|
DB_NAME,
|
|
DB_OPERATION,
|
|
DB_REDIS_DATABASE_INDEX,
|
|
DB_STATEMENT,
|
|
DB_SYSTEM,
|
|
DB_USER,
|
|
)
|
|
from opentelemetry.semconv._incubating.attributes.http_attributes import (
|
|
HTTP_FLAVOR,
|
|
HTTP_HOST,
|
|
HTTP_METHOD,
|
|
HTTP_SCHEME,
|
|
HTTP_SERVER_NAME,
|
|
HTTP_STATUS_CODE,
|
|
HTTP_TARGET,
|
|
HTTP_URL,
|
|
HTTP_USER_AGENT,
|
|
)
|
|
from opentelemetry.semconv._incubating.attributes.net_attributes import (
|
|
NET_HOST_NAME,
|
|
NET_HOST_PORT,
|
|
NET_PEER_IP,
|
|
NET_PEER_NAME,
|
|
NET_PEER_PORT,
|
|
NET_TRANSPORT,
|
|
)
|
|
from opentelemetry.semconv.attributes.client_attributes import (
|
|
CLIENT_ADDRESS,
|
|
CLIENT_PORT,
|
|
)
|
|
from opentelemetry.semconv.attributes.db_attributes import (
|
|
DB_NAMESPACE,
|
|
DB_OPERATION_NAME,
|
|
DB_QUERY_TEXT,
|
|
DB_SYSTEM_NAME,
|
|
)
|
|
from opentelemetry.semconv.attributes.error_attributes import ERROR_TYPE
|
|
from opentelemetry.semconv.attributes.http_attributes import (
|
|
HTTP_REQUEST_METHOD,
|
|
HTTP_REQUEST_METHOD_ORIGINAL,
|
|
HTTP_RESPONSE_STATUS_CODE,
|
|
HTTP_ROUTE,
|
|
)
|
|
from opentelemetry.semconv.attributes.network_attributes import (
|
|
NETWORK_PROTOCOL_VERSION,
|
|
NETWORK_TRANSPORT,
|
|
)
|
|
from opentelemetry.semconv.attributes.server_attributes import (
|
|
SERVER_ADDRESS,
|
|
SERVER_PORT,
|
|
)
|
|
from opentelemetry.semconv.attributes.url_attributes import (
|
|
URL_FULL,
|
|
URL_PATH,
|
|
URL_QUERY,
|
|
URL_SCHEME,
|
|
)
|
|
from opentelemetry.semconv.attributes.user_agent_attributes import (
|
|
USER_AGENT_ORIGINAL,
|
|
)
|
|
from opentelemetry.semconv.schemas import Schemas
|
|
from opentelemetry.trace import Span
|
|
from opentelemetry.trace.status import Status, StatusCode
|
|
from opentelemetry.util.types import AttributeValue
|
|
|
|
# Values defined in milliseconds
|
|
HTTP_DURATION_HISTOGRAM_BUCKETS_OLD = (
|
|
0.0,
|
|
5.0,
|
|
10.0,
|
|
25.0,
|
|
50.0,
|
|
75.0,
|
|
100.0,
|
|
250.0,
|
|
500.0,
|
|
750.0,
|
|
1000.0,
|
|
2500.0,
|
|
5000.0,
|
|
7500.0,
|
|
10000.0,
|
|
)
|
|
|
|
# Values defined in seconds
|
|
HTTP_DURATION_HISTOGRAM_BUCKETS_NEW = (
|
|
0.005,
|
|
0.01,
|
|
0.025,
|
|
0.05,
|
|
0.075,
|
|
0.1,
|
|
0.25,
|
|
0.5,
|
|
0.75,
|
|
1,
|
|
2.5,
|
|
5,
|
|
7.5,
|
|
10,
|
|
)
|
|
|
|
# These lists represent attributes for metrics that are currently supported
|
|
|
|
_client_duration_attrs_old = [
|
|
HTTP_STATUS_CODE,
|
|
HTTP_HOST,
|
|
HTTP_METHOD,
|
|
HTTP_FLAVOR,
|
|
HTTP_SCHEME,
|
|
NET_PEER_PORT,
|
|
NET_PEER_NAME,
|
|
]
|
|
|
|
_client_duration_attrs_new = [
|
|
ERROR_TYPE,
|
|
HTTP_REQUEST_METHOD,
|
|
HTTP_RESPONSE_STATUS_CODE,
|
|
NETWORK_PROTOCOL_VERSION,
|
|
SERVER_ADDRESS,
|
|
SERVER_PORT,
|
|
# TODO: Support opt-in for scheme in new semconv
|
|
# URL_SCHEME,
|
|
]
|
|
|
|
_server_duration_attrs_old = [
|
|
HTTP_METHOD,
|
|
HTTP_HOST,
|
|
HTTP_SCHEME,
|
|
HTTP_STATUS_CODE,
|
|
HTTP_FLAVOR,
|
|
HTTP_SERVER_NAME,
|
|
NET_HOST_NAME,
|
|
NET_HOST_PORT,
|
|
]
|
|
|
|
_server_duration_attrs_new = [
|
|
ERROR_TYPE,
|
|
HTTP_REQUEST_METHOD,
|
|
HTTP_RESPONSE_STATUS_CODE,
|
|
HTTP_ROUTE,
|
|
NETWORK_PROTOCOL_VERSION,
|
|
URL_SCHEME,
|
|
]
|
|
|
|
_server_active_requests_count_attrs_old = [
|
|
HTTP_METHOD,
|
|
HTTP_HOST,
|
|
HTTP_SCHEME,
|
|
HTTP_FLAVOR,
|
|
HTTP_SERVER_NAME,
|
|
]
|
|
|
|
_server_active_requests_count_attrs_new = [
|
|
HTTP_REQUEST_METHOD,
|
|
URL_SCHEME,
|
|
# TODO: Support SERVER_ADDRESS AND SERVER_PORT
|
|
]
|
|
|
|
OTEL_SEMCONV_STABILITY_OPT_IN = "OTEL_SEMCONV_STABILITY_OPT_IN"
|
|
|
|
# Legacy/default schema version when schema_url was first introduced
|
|
_LEGACY_SCHEMA_VERSION = "1.11.0"
|
|
|
|
|
|
class _OpenTelemetryStabilitySignalType(Enum):
|
|
HTTP = "http"
|
|
DATABASE = "database"
|
|
GEN_AI = "gen_ai"
|
|
|
|
|
|
class _StabilityMode(Enum):
|
|
DEFAULT = "default"
|
|
HTTP = "http"
|
|
HTTP_DUP = "http/dup"
|
|
DATABASE = "database"
|
|
DATABASE_DUP = "database/dup"
|
|
GEN_AI_LATEST_EXPERIMENTAL = "gen_ai_latest_experimental"
|
|
|
|
|
|
def _report_new(mode: _StabilityMode):
|
|
return mode != _StabilityMode.DEFAULT
|
|
|
|
|
|
def _report_old(mode: _StabilityMode):
|
|
return mode not in (_StabilityMode.HTTP, _StabilityMode.DATABASE)
|
|
|
|
|
|
class _OpenTelemetrySemanticConventionStability:
|
|
_initialized = False
|
|
_lock = threading.Lock()
|
|
_OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING = {}
|
|
|
|
@classmethod
|
|
def _initialize(cls):
|
|
with cls._lock:
|
|
if cls._initialized:
|
|
return
|
|
|
|
# Users can pass in comma delimited string for opt-in options
|
|
# Only values for http, gen ai, and database stability are supported for now
|
|
opt_in = os.environ.get(OTEL_SEMCONV_STABILITY_OPT_IN)
|
|
|
|
if not opt_in:
|
|
# early return in case of default
|
|
cls._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING = {
|
|
_OpenTelemetryStabilitySignalType.HTTP: _StabilityMode.DEFAULT,
|
|
_OpenTelemetryStabilitySignalType.DATABASE: _StabilityMode.DEFAULT,
|
|
_OpenTelemetryStabilitySignalType.GEN_AI: _StabilityMode.DEFAULT,
|
|
}
|
|
cls._initialized = True
|
|
return
|
|
|
|
opt_in_list = [s.strip() for s in opt_in.split(",")]
|
|
|
|
cls._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING[_OpenTelemetryStabilitySignalType.HTTP] = cls._filter_mode(
|
|
opt_in_list, _StabilityMode.HTTP, _StabilityMode.HTTP_DUP
|
|
)
|
|
|
|
cls._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING[_OpenTelemetryStabilitySignalType.GEN_AI] = cls._filter_mode(
|
|
opt_in_list,
|
|
_StabilityMode.DEFAULT,
|
|
_StabilityMode.GEN_AI_LATEST_EXPERIMENTAL,
|
|
)
|
|
|
|
cls._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING[_OpenTelemetryStabilitySignalType.DATABASE] = cls._filter_mode(
|
|
opt_in_list,
|
|
_StabilityMode.DATABASE,
|
|
_StabilityMode.DATABASE_DUP,
|
|
)
|
|
cls._initialized = True
|
|
|
|
@staticmethod
|
|
def _filter_mode(opt_in_list, stable_mode, dup_mode):
|
|
# Process semconv stability opt-in
|
|
# http/dup,database/dup has higher precedence over http,database
|
|
if dup_mode.value in opt_in_list:
|
|
return dup_mode
|
|
|
|
return stable_mode if stable_mode.value in opt_in_list else _StabilityMode.DEFAULT
|
|
|
|
@classmethod
|
|
def _get_opentelemetry_stability_opt_in_mode(cls, signal_type: _OpenTelemetryStabilitySignalType) -> _StabilityMode:
|
|
# Get OpenTelemetry opt-in mode based off of signal type (http, messaging, etc.)
|
|
return cls._OTEL_SEMCONV_STABILITY_SIGNAL_MAPPING.get(signal_type, _StabilityMode.DEFAULT)
|
|
|
|
|
|
def _get_semconv_opt_in_modes(
|
|
signal_types: tuple[_OpenTelemetryStabilitySignalType, ...],
|
|
) -> dict[_OpenTelemetryStabilitySignalType, _StabilityMode]:
|
|
"""Returns a mapping of signal type to mode for the provided
|
|
signal_types (one/more of DATABASE, HTTP, GEN_AI).
|
|
"""
|
|
_OpenTelemetrySemanticConventionStability._initialize()
|
|
return {
|
|
signal_type: _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(signal_type)
|
|
for signal_type in signal_types
|
|
}
|
|
|
|
|
|
def _filter_semconv_duration_attrs(
|
|
attrs: Mapping[str, AttributeValue],
|
|
old_attrs: Container[AttributeValue],
|
|
new_attrs: Container[AttributeValue],
|
|
sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
|
|
) -> dict[str, AttributeValue]:
|
|
filtered_attrs = {}
|
|
# duration is two different metrics depending on sem_conv_opt_in_mode, so no DUP attributes
|
|
allowed_attributes = new_attrs if sem_conv_opt_in_mode == _StabilityMode.HTTP else old_attrs
|
|
for key, val in attrs.items():
|
|
if key in allowed_attributes:
|
|
filtered_attrs[key] = val
|
|
return filtered_attrs
|
|
|
|
|
|
def _filter_semconv_active_request_count_attr(
|
|
attrs: Mapping[str, AttributeValue],
|
|
old_attrs: Container[AttributeValue],
|
|
new_attrs: Container[AttributeValue],
|
|
sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
|
|
) -> dict[str, AttributeValue]:
|
|
filtered_attrs = {}
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
for key, val in attrs.items():
|
|
if key in old_attrs:
|
|
filtered_attrs[key] = val
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
for key, val in attrs.items():
|
|
if key in new_attrs:
|
|
filtered_attrs[key] = val
|
|
return filtered_attrs
|
|
|
|
|
|
def set_string_attribute(
|
|
result: MutableMapping[str, AttributeValue],
|
|
key: str,
|
|
value: AttributeValue,
|
|
) -> None:
|
|
if value:
|
|
result[key] = value
|
|
|
|
|
|
def set_int_attribute(
|
|
result: MutableMapping[str, AttributeValue],
|
|
key: str,
|
|
value: AttributeValue,
|
|
) -> None:
|
|
if value:
|
|
try:
|
|
result[key] = int(value)
|
|
except (ValueError, TypeError):
|
|
pass
|
|
|
|
|
|
def _set_http_method(
|
|
result: MutableMapping[str, AttributeValue],
|
|
original: str,
|
|
normalized: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
original = original.strip()
|
|
normalized = normalized.strip()
|
|
# See https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/http-spans.md#common-attributes
|
|
# Method is case sensitive. "http.request.method_original" should not be sanitized or automatically capitalized.
|
|
if original != normalized and _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, HTTP_REQUEST_METHOD_ORIGINAL, original)
|
|
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, HTTP_METHOD, normalized)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, HTTP_REQUEST_METHOD, normalized)
|
|
|
|
|
|
def _set_http_status_code(
|
|
result: MutableMapping[str, AttributeValue],
|
|
code: str | int,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_int_attribute(result, HTTP_STATUS_CODE, code)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_int_attribute(result, HTTP_RESPONSE_STATUS_CODE, code)
|
|
|
|
|
|
def _set_http_url(
|
|
result: MutableMapping[str, AttributeValue],
|
|
url: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, HTTP_URL, url)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, URL_FULL, url)
|
|
|
|
|
|
def _set_http_scheme(
|
|
result: MutableMapping[str, AttributeValue],
|
|
scheme: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, HTTP_SCHEME, scheme)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, URL_SCHEME, scheme)
|
|
|
|
|
|
def _set_http_flavor_version(
|
|
result: MutableMapping[str, AttributeValue],
|
|
version: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, HTTP_FLAVOR, version)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, NETWORK_PROTOCOL_VERSION, version)
|
|
|
|
|
|
def _set_http_user_agent(
|
|
result: MutableMapping[str, AttributeValue],
|
|
user_agent: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, HTTP_USER_AGENT, user_agent)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, USER_AGENT_ORIGINAL, user_agent)
|
|
|
|
|
|
# Client
|
|
|
|
|
|
def _set_http_host_client(
|
|
result: MutableMapping[str, AttributeValue],
|
|
host: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, HTTP_HOST, host)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, SERVER_ADDRESS, host)
|
|
|
|
|
|
def _set_http_net_peer_name_client(
|
|
result: MutableMapping[str, AttributeValue],
|
|
peer_name: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, NET_PEER_NAME, peer_name)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, SERVER_ADDRESS, peer_name)
|
|
|
|
|
|
def _set_http_peer_port_client(
|
|
result: MutableMapping[str, AttributeValue],
|
|
port: str | int,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_int_attribute(result, NET_PEER_PORT, port)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_int_attribute(result, SERVER_PORT, port)
|
|
|
|
|
|
def _set_http_network_protocol_version(
|
|
result: MutableMapping[str, AttributeValue],
|
|
version: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, HTTP_FLAVOR, version)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, NETWORK_PROTOCOL_VERSION, version)
|
|
|
|
|
|
# Server
|
|
|
|
|
|
def _set_http_net_host(
|
|
result: MutableMapping[str, AttributeValue],
|
|
host: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, NET_HOST_NAME, host)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, SERVER_ADDRESS, host)
|
|
|
|
|
|
def _set_http_net_host_port(
|
|
result: MutableMapping[str, AttributeValue],
|
|
port: str | int,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_int_attribute(result, NET_HOST_PORT, port)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_int_attribute(result, SERVER_PORT, port)
|
|
|
|
|
|
def _set_http_target(
|
|
result: MutableMapping[str, AttributeValue],
|
|
target: str,
|
|
path: str | None,
|
|
query: str | None,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, HTTP_TARGET, target)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
if path:
|
|
set_string_attribute(result, URL_PATH, path)
|
|
if query:
|
|
set_string_attribute(result, URL_QUERY, query)
|
|
|
|
|
|
def _set_http_host_server(
|
|
result: MutableMapping[str, AttributeValue],
|
|
host: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, HTTP_HOST, host)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
if not result.get(SERVER_ADDRESS):
|
|
set_string_attribute(result, SERVER_ADDRESS, host)
|
|
|
|
|
|
# net.peer.ip -> net.sock.peer.addr
|
|
# https://github.com/open-telemetry/semantic-conventions/blob/40db676ca0e735aa84f242b5a0fb14e49438b69b/schemas/1.15.0#L18
|
|
# net.sock.peer.addr -> client.socket.address for server spans (TODO) AND client.address if missing
|
|
# https://github.com/open-telemetry/semantic-conventions/blob/v1.21.0/CHANGELOG.md#v1210-2023-07-13
|
|
# https://github.com/open-telemetry/semantic-conventions/blob/main/docs/non-normative/http-migration.md#common-attributes-across-http-client-and-server-spans
|
|
def _set_http_peer_ip_server(
|
|
result: MutableMapping[str, AttributeValue],
|
|
ip: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, NET_PEER_IP, ip)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
# Only populate if not already populated
|
|
if not result.get(CLIENT_ADDRESS):
|
|
set_string_attribute(result, CLIENT_ADDRESS, ip)
|
|
|
|
|
|
def _set_http_peer_port_server(
|
|
result: MutableMapping[str, AttributeValue],
|
|
port: str | int,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_int_attribute(result, NET_PEER_PORT, port)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_int_attribute(result, CLIENT_PORT, port)
|
|
|
|
|
|
def _set_http_net_peer_name_server(
|
|
result: MutableMapping[str, AttributeValue],
|
|
name: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, NET_PEER_NAME, name)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, CLIENT_ADDRESS, name)
|
|
|
|
|
|
# Database
|
|
|
|
|
|
def _set_db_system(
|
|
result: MutableMapping[str, AttributeValue],
|
|
system: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, DB_SYSTEM, system)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, DB_SYSTEM_NAME, system)
|
|
|
|
|
|
def _set_db_name(
|
|
result: MutableMapping[str, AttributeValue],
|
|
name: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, DB_NAME, name)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, DB_NAMESPACE, name)
|
|
|
|
|
|
def _set_db_statement(
|
|
result: MutableMapping[str, AttributeValue],
|
|
statement: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
# skip the statement if it's None but set it if it's an empty string
|
|
if statement is None:
|
|
return
|
|
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
result[DB_STATEMENT] = statement
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
result[DB_QUERY_TEXT] = statement
|
|
|
|
|
|
def _set_db_user(
|
|
result: MutableMapping[str, AttributeValue],
|
|
user: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, DB_USER, user)
|
|
# No new attribute - db.user was removed with no replacement
|
|
|
|
|
|
def _set_db_operation(
|
|
result: MutableMapping[str, AttributeValue],
|
|
operation: str,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, DB_OPERATION, operation)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, DB_OPERATION_NAME, operation)
|
|
|
|
|
|
def _set_db_redis_database_index(
|
|
result: MutableMapping[str, AttributeValue],
|
|
database_index: int,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
if database_index is not None:
|
|
result[DB_REDIS_DATABASE_INDEX] = int(database_index)
|
|
# No new attribute - db.redis.database_index was removed with no replacement in semconv 1.38.0
|
|
|
|
|
|
def _set_net_transport(
|
|
result: MutableMapping[str, AttributeValue],
|
|
old_transport: AttributeValue,
|
|
new_transport: AttributeValue,
|
|
sem_conv_opt_in_mode: _StabilityMode,
|
|
) -> None:
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, NET_TRANSPORT, old_transport)
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
set_string_attribute(result, NETWORK_TRANSPORT, new_transport)
|
|
|
|
|
|
# General
|
|
|
|
|
|
def _set_status(
|
|
span: Span,
|
|
metrics_attributes: MutableMapping[str, AttributeValue],
|
|
status_code: int,
|
|
status_code_str: str,
|
|
server_span: bool = True,
|
|
sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
|
|
) -> None:
|
|
if status_code < 0:
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
metrics_attributes[ERROR_TYPE] = status_code_str
|
|
if span.is_recording():
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
span.set_attribute(ERROR_TYPE, status_code_str)
|
|
span.set_status(
|
|
Status(
|
|
StatusCode.ERROR,
|
|
"Non-integer HTTP status: " + status_code_str,
|
|
)
|
|
)
|
|
else:
|
|
status = http_status_to_status_code(status_code, server_span=server_span)
|
|
|
|
if _report_old(sem_conv_opt_in_mode):
|
|
if span.is_recording():
|
|
span.set_attribute(HTTP_STATUS_CODE, status_code)
|
|
metrics_attributes[HTTP_STATUS_CODE] = status_code
|
|
if _report_new(sem_conv_opt_in_mode):
|
|
if span.is_recording():
|
|
span.set_attribute(HTTP_RESPONSE_STATUS_CODE, status_code)
|
|
metrics_attributes[HTTP_RESPONSE_STATUS_CODE] = status_code
|
|
if status == StatusCode.ERROR:
|
|
if span.is_recording():
|
|
span.set_attribute(ERROR_TYPE, status_code_str)
|
|
metrics_attributes[ERROR_TYPE] = status_code_str
|
|
if span.is_recording():
|
|
span.set_status(Status(status))
|
|
|
|
|
|
def _get_schema_url(mode: _StabilityMode) -> str:
|
|
"""Get schema version URL for a single signal type's opt-in mode (backwards compatible).
|
|
|
|
For new instrumentations using multiple signal types, use
|
|
_get_schema_url_for_signal_types()
|
|
"""
|
|
if mode is _StabilityMode.DEFAULT:
|
|
return f"https://opentelemetry.io/schemas/{_LEGACY_SCHEMA_VERSION}"
|
|
return Schemas.V1_21_0.value
|
|
|
|
|
|
def _get_schema_version_for_opt_in_mode(
|
|
signal_type: _OpenTelemetryStabilitySignalType,
|
|
mode: _StabilityMode,
|
|
) -> str:
|
|
"""Get the schema version for a specific signal type and opt-in mode."""
|
|
if mode == _StabilityMode.DEFAULT:
|
|
return _LEGACY_SCHEMA_VERSION
|
|
|
|
signal_versions = {
|
|
_OpenTelemetryStabilitySignalType.HTTP: Schemas.V1_21_0.value,
|
|
_OpenTelemetryStabilitySignalType.DATABASE: Schemas.V1_25_0.value,
|
|
_OpenTelemetryStabilitySignalType.GEN_AI: Schemas.V1_26_0.value,
|
|
}
|
|
schema_url = signal_versions.get(signal_type)
|
|
if not schema_url:
|
|
return _LEGACY_SCHEMA_VERSION
|
|
|
|
path = urlparse(schema_url).path
|
|
schema_version = path.rstrip("/").split("/")[-1]
|
|
return schema_version or _LEGACY_SCHEMA_VERSION
|
|
|
|
|
|
def _get_schema_url_for_signal_types(
|
|
signal_types: list[_OpenTelemetryStabilitySignalType],
|
|
) -> str:
|
|
"""Get the highest applicable schema URL for multiple signal types.
|
|
|
|
Note:
|
|
Instrumentors should call _OpenTelemetrySemanticConventionStability._initialize()
|
|
before using this function to ensure proper initialization of stability modes.
|
|
|
|
Args:
|
|
signal_types: List of signal types used by the instrumentation
|
|
|
|
Returns:
|
|
Schema URL string representing the highest applicable semconv version
|
|
"""
|
|
highest_schema_version = _LEGACY_SCHEMA_VERSION
|
|
for signal_type in signal_types:
|
|
mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(signal_type)
|
|
schema_version = _get_schema_version_for_opt_in_mode(signal_type, mode)
|
|
# Keep the highest for all signals
|
|
if package_version.Version(schema_version) > package_version.Version(highest_schema_version):
|
|
highest_schema_version = schema_version
|
|
return f"https://opentelemetry.io/schemas/{highest_schema_version}"
|