diff --git a/python/instrumentation/openinference-instrumentation-langchain/src/openinference/instrumentation/langchain/_tracer.py b/python/instrumentation/openinference-instrumentation-langchain/src/openinference/instrumentation/langchain/_tracer.py index 4a8cfe104..8ba9a167a 100644 --- a/python/instrumentation/openinference-instrumentation-langchain/src/openinference/instrumentation/langchain/_tracer.py +++ b/python/instrumentation/openinference-instrumentation-langchain/src/openinference/instrumentation/langchain/_tracer.py @@ -4,7 +4,7 @@ import time import traceback from copy import deepcopy -from datetime import datetime +from datetime import datetime, timezone from enum import Enum from itertools import chain from threading import RLock @@ -86,7 +86,14 @@ def _start_trace(self, run: Run) -> None: and (parent := self._runs.get(parent_run_id)) else None ) - span = self._tracer.start_span(name=run.name, context=parent_context) + # We can't use real time because the handler may be + # called in a background thread. + start_time_utc_nano = _as_utc_nano(run.start_time) + span = self._tracer.start_span( + name=run.name, + context=parent_context, + start_time=start_time_utc_nano, + ) context = trace_api.set_span_in_context(span) # The following line of code is commented out to serve as a reminder that in a system # of callbacks, attaching the context can be hazardous because there is no guarantee @@ -111,7 +118,10 @@ def _end_trace(self, run: Run) -> None: _update_span(span, run) except Exception: logger.exception("Failed to update span with run data.") - span.end() + # We can't use real time because the handler may be + # called in a background thread. + end_time_utc_nano = _as_utc_nano(run.end_time) if run.end_time else None + span.end(end_time=end_time_utc_nano) def _persist_run(self, run: Run) -> None: pass @@ -583,6 +593,10 @@ def default(self, obj: Any) -> Any: return str(obj) +def _as_utc_nano(dt: datetime) -> int: + return int(dt.astimezone(timezone.utc).timestamp() * 1_000_000_000) + + DOCUMENT_CONTENT = DocumentAttributes.DOCUMENT_CONTENT DOCUMENT_ID = DocumentAttributes.DOCUMENT_ID DOCUMENT_METADATA = DocumentAttributes.DOCUMENT_METADATA