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
1 change: 0 additions & 1 deletion src/splunk_ao/converter/attribute_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

SPLUNK_AO_SYSTEM = "splunk_ao.system"
SPLUNK_AO_SYSTEM_VALUE = "splunk_ao_python"
SPLUNK_AO_SIMULATION_RUN_ID = "splunk_ao.simulation.run_id"

CONTENT_ALIAS_BY_GEN_AI: Mapping[str, str] = {
"gen_ai.input.messages": "splunk_ao.input.messages",
Expand Down
4 changes: 2 additions & 2 deletions src/splunk_ao/converter/span_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
from opentelemetry.trace import SpanContext, SpanKind, Status, StatusCode

from galileo_core.schemas.logging.step import BaseStep, StepType
from splunk_ao.converter.attribute_mapping import SPLUNK_AO_SIMULATION_RUN_ID, build_span_attributes
from splunk_ao.simulation_run_context import validate_simulation_run_id
from splunk_ao.converter.attribute_mapping import build_span_attributes
from splunk_ao.simulation_run_context import SPLUNK_AO_SIMULATION_RUN_ID, validate_simulation_run_id
from splunk_ao.utils.headers_data import get_package_version

_EPOCH = datetime(1970, 1, 1, tzinfo=UTC)
Expand Down
3 changes: 1 addition & 2 deletions src/splunk_ao/otel.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from galileo_core.schemas.logging.span import Span as SplunkAOSpan
from splunk_ao.config import SplunkAOConfig
from splunk_ao.converter import build_span_attributes
from splunk_ao.converter.attribute_mapping import SPLUNK_AO_SIMULATION_RUN_ID
from splunk_ao.decorator import (
_agent_stream_context,
_dataset_input_context,
Expand All @@ -36,7 +35,7 @@
)
from splunk_ao.exporter.diagnostics import get_export_health
from splunk_ao.session_context import get_effective_session_id
from splunk_ao.simulation_run_context import get_simulation_run_id
from splunk_ao.simulation_run_context import SPLUNK_AO_SIMULATION_RUN_ID, get_simulation_run_id

logger = logging.getLogger(__name__)

Expand Down
7 changes: 5 additions & 2 deletions src/splunk_ao/session_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
from opentelemetry.context import Context
from opentelemetry.propagators import textmap

from splunk_ao.converter.attribute_mapping import SPLUNK_AO_SIMULATION_RUN_ID
from splunk_ao.simulation_run_context import get_baggage_simulation_run_id, get_simulation_run_id
from splunk_ao.simulation_run_context import (
SPLUNK_AO_SIMULATION_RUN_ID,
get_baggage_simulation_run_id,
get_simulation_run_id,
)

GEN_AI_CONVERSATION_ID = "gen_ai.conversation.id"

Expand Down
6 changes: 3 additions & 3 deletions src/splunk_ao/simulation_run_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
from opentelemetry import baggage
from opentelemetry.context import Context

from splunk_ao.converter.attribute_mapping import SPLUNK_AO_SIMULATION_RUN_ID
SPLUNK_AO_SIMULATION_RUN_ID = "splunk_ao.simulation.run_id"

_simulation_run_id_context: ContextVar[str | None] = ContextVar("simulation_run_id_context", default=None)


def validate_simulation_run_id(simulation_run_id: object) -> str:
"""Validate a public simulation run ID and return it unchanged."""
"""Validate a public simulation run ID and return its normalized value."""
if not isinstance(simulation_run_id, str) or not simulation_run_id.strip():
raise ValueError("simulation_run_id must be a non-empty string")
return simulation_run_id
return simulation_run_id.strip()


def get_baggage_simulation_run_id(context: Context | None = None) -> str | None:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_http_instrumentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
from yarl import URL

from splunk_ao import configure_distributed_tracing, instrument_distributed_tracing, splunk_ao_context
from splunk_ao.converter.attribute_mapping import SPLUNK_AO_SIMULATION_RUN_ID
from splunk_ao.http_instrumentation import (
_client_providers,
_configured_providers,
Expand All @@ -41,6 +40,7 @@
)
from splunk_ao.logger.logger import SplunkAOLogger
from splunk_ao.session_context import GEN_AI_CONVERSATION_ID, SplunkAOSessionPropagator, _session_id_context
from splunk_ao.simulation_run_context import SPLUNK_AO_SIMULATION_RUN_ID


class FakeTracerProvider:
Expand Down
3 changes: 1 addition & 2 deletions tests/test_logger_otel_egress.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
from opentelemetry import context, propagate, trace
from opentelemetry.sdk.trace import ReadableSpan

from splunk_ao.converter.attribute_mapping import SPLUNK_AO_SIMULATION_RUN_ID
from splunk_ao.deployment import DeploymentMode
from splunk_ao.exceptions import SplunkAOLoggerException
from splunk_ao.exporter.span_transform import copy_span_for_export
from splunk_ao.logger import SplunkAOLogger
from splunk_ao.shared.exceptions import MissingConfigurationError
from splunk_ao.simulation_run_context import _simulation_run_id_context
from splunk_ao.simulation_run_context import SPLUNK_AO_SIMULATION_RUN_ID, _simulation_run_id_context
from splunk_ao.utils.singleton import SplunkAOLoggerSingleton


Expand Down
2 changes: 1 addition & 1 deletion tests/test_otel_native_paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

from galileo_core.schemas.logging.span import WorkflowSpan
from splunk_ao import get_tracing_headers
from splunk_ao.converter.attribute_mapping import SPLUNK_AO_SIMULATION_RUN_ID
from splunk_ao.decorator import (
_agent_stream_context,
_dataset_input_context,
Expand All @@ -35,6 +34,7 @@
start_splunk_ao_span,
)
from splunk_ao.shared.exceptions import MissingConfigurationError
from splunk_ao.simulation_run_context import SPLUNK_AO_SIMULATION_RUN_ID

ROUTING_KEYS = {
"splunk_ao.project.name",
Expand Down
12 changes: 11 additions & 1 deletion tests/test_span_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
from galileo_core.schemas.logging.trace import Trace
from galileo_core.schemas.shared.document import Document
from splunk_ao.converter import SpanConverter, span_converter
from splunk_ao.converter.attribute_mapping import SPLUNK_AO_SIMULATION_RUN_ID, build_span_attributes
from splunk_ao.converter.attribute_mapping import build_span_attributes
from splunk_ao.logger.control import ControlAppliesTo, ControlCheckStage, ControlResult, ControlSpan
from splunk_ao.schema.logged import LoggedControlSpan
from splunk_ao.simulation_run_context import SPLUNK_AO_SIMULATION_RUN_ID
from splunk_ao.utils.headers_data import get_package_version

TRACE_ID = 0x1234567890ABCDEF1234567890ABCDEF
Expand Down Expand Up @@ -192,6 +193,15 @@ def test_simulation_run_id_is_a_direct_attribute_for_every_span_type(
assert "splunk_ao.experiment.id" not in (result.attributes or {})


def test_converter_normalizes_simulation_run_id_before_export() -> None:
result = convert(
WorkflowSpan(input="work", output="done", name="workflow", created_at=CREATED_AT),
simulation_run_id=" run-1 ",
)

assert (result.attributes or {})[SPLUNK_AO_SIMULATION_RUN_ID] == "run-1"


def test_fully_populated_logged_control_span_preserves_otlp_envelope_and_attributes() -> None:
parent_context = make_context(span_id=PARENT_SPAN_ID)
span = LoggedControlSpan(
Expand Down
10 changes: 10 additions & 0 deletions tests/test_splunk_ao_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ def test_simulation_run_scope_restores_the_previous_value() -> None:
_simulation_run_id_context.reset(outer_token)


def test_simulation_run_id_is_normalized_at_public_context_boundaries(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(splunk_ao_context, "get_logger_instance", Mock())

with splunk_ao_context.simulation_run(" run-1\n"):
assert _simulation_run_id_context.get() == "run-1"

with splunk_ao_context(simulation_run_id="\trun-2 "):
assert _simulation_run_id_context.get() == "run-2"
Comment thread
adityamehra marked this conversation as resolved.


def test_init_clears_active_simulation_run(monkeypatch: pytest.MonkeyPatch) -> None:
logger = Mock()
singleton = Mock()
Expand Down
3 changes: 1 addition & 2 deletions tests/test_tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@
from opentelemetry.trace import NonRecordingSpan, SpanContext, TraceFlags, TraceState

from splunk_ao import extract_tracing_context, get_tracing_headers, splunk_ao_context
from splunk_ao.converter.attribute_mapping import SPLUNK_AO_SIMULATION_RUN_ID
from splunk_ao.exceptions import SplunkAOLoggerException
from splunk_ao.logger import SplunkAOLogger
from splunk_ao.logger.logger import _otel_context_state
from splunk_ao.session_context import GEN_AI_CONVERSATION_ID, _session_id_context
from splunk_ao.simulation_run_context import _simulation_run_id_context
from splunk_ao.simulation_run_context import SPLUNK_AO_SIMULATION_RUN_ID, _simulation_run_id_context


class RecordingSink:
Expand Down
Loading