diff --git a/ddtrace/_trace/span.py b/ddtrace/_trace/span.py index 6180f70db7d..fb15ca2a4b6 100644 --- a/ddtrace/_trace/span.py +++ b/ddtrace/_trace/span.py @@ -240,13 +240,20 @@ def _set_sampling_decision_maker( self.context._meta[SAMPLING_DECISION_TRACE_TAG_KEY] = value return value - def set_tag(self, key: str, value: Optional[str] = None) -> None: - """Set a tag key/value pair on the span.""" + def set_tag(self, key: str, value: Any = None) -> None: + """Set a tag key/value pair on the span. + + Boolean and bytes values are stored as their string representation. Finite floats + and integers within the signed 64-bit range are stored as metrics (see + ``set_metric``); integers outside that range fall back to their string + representation, and NaN or infinite floats are discarded. ``http.status_code`` is + always stored as a string. + """ # Explicitly try to convert expected integers to `int` # DEV: Some integrations parse these values from strings, but don't call `int(value)` themselves if key == net.TARGET_PORT: try: - value = int(value) # type: ignore + value = int(value) except (ValueError, TypeError): pass @@ -261,14 +268,14 @@ def set_tag(self, key: str, value: Optional[str] = None) -> None: elif key == SERVICE_VERSION_KEY: # Also set the `version` tag to the same value # DEV: Note that we do no return, we want to set both - self._set_attribute(VERSION_KEY, value) # type: ignore[arg-type] + self._set_attribute(VERSION_KEY, value) elif key == _SPAN_MEASURED_KEY: # Set `_dd.measured` tag as a metric # DEV: `set_metric` will ensure it is an integer 0 or 1 if value is None: - value = 1 # type: ignore + value = 1 - self.set_metric(key, value) # type: ignore[arg-type] # ast-grep-ignore: span-set-metric + self.set_metric(key, value) # ast-grep-ignore: span-set-metric return if isinstance(key, bytes): @@ -278,7 +285,7 @@ def set_tag(self, key: str, value: Optional[str] = None) -> None: value = str(value) try: - self._set_attribute(key, value) # type: ignore[arg-type] + self._set_attribute(key, value) except Exception: log.warning("error setting tag %s, ignoring it", key, exc_info=True) diff --git a/releasenotes/notes/widen-set-tag-value-typing-40a41e0a8804ec18.yaml b/releasenotes/notes/widen-set-tag-value-typing-40a41e0a8804ec18.yaml new file mode 100644 index 00000000000..c64bd12b434 --- /dev/null +++ b/releasenotes/notes/widen-set-tag-value-typing-40a41e0a8804ec18.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + tracing: This fix resolves an issue where type checkers rejected valid application code passing + non-string values to ``Span.set_tag`` (for example ``span.set_tag("custom.tag", True)``). The + ``value`` parameter was annotated as ``Optional[str]``, but the implementation accepts the + historic domain: booleans and bytes are stringified into tags, and numeric values are stored + as metrics.