Call method with OpenTelemetry tracing if enabled. Extracts traceparent from context (3rd arg) and creates a child span that links to the parent trace from Promptfoo.
(method_callable, args, function_name)
| 183 | |
| 184 | |
| 185 | def _traced_call(method_callable, args, function_name): |
| 186 | """ |
| 187 | Call method with OpenTelemetry tracing if enabled. |
| 188 | |
| 189 | Extracts traceparent from context (3rd arg) and creates a child span |
| 190 | that links to the parent trace from Promptfoo. |
| 191 | """ |
| 192 | global _tracer, _tracing_enabled |
| 193 | |
| 194 | # Fast path: if tracing not enabled, just call the method |
| 195 | if not _tracing_enabled or _tracer is None: |
| 196 | return call_method(method_callable, args) |
| 197 | |
| 198 | # Extract traceparent from context (3rd argument for call_api) |
| 199 | traceparent = None |
| 200 | context_arg = None |
| 201 | if len(args) >= 3: |
| 202 | context_arg = args[2] |
| 203 | if isinstance(context_arg, dict): |
| 204 | traceparent = context_arg.get("traceparent") |
| 205 | |
| 206 | # If no traceparent, fall back to untraced call |
| 207 | if not traceparent: |
| 208 | return call_method(method_callable, args) |
| 209 | |
| 210 | try: |
| 211 | from opentelemetry.propagate import extract |
| 212 | from opentelemetry.trace import SpanKind, Status, StatusCode |
| 213 | |
| 214 | # Extract parent context from W3C traceparent header |
| 215 | parent_ctx = extract({"traceparent": traceparent}) |
| 216 | |
| 217 | # Determine span name following GenAI conventions |
| 218 | span_name = f"python {function_name}" |
| 219 | |
| 220 | with _tracer.start_as_current_span( |
| 221 | span_name, context=parent_ctx, kind=SpanKind.CLIENT |
| 222 | ) as span: |
| 223 | # Set GenAI semantic convention attributes |
| 224 | span.set_attribute("gen_ai.system", "python") |
| 225 | span.set_attribute("gen_ai.operation.name", function_name) |
| 226 | |
| 227 | # Set request attributes from prompt (1st arg) |
| 228 | if len(args) >= 1: |
| 229 | prompt = args[0] |
| 230 | if isinstance(prompt, str): |
| 231 | span.set_attribute("promptfoo.request.body", _truncate_body(prompt)) |
| 232 | |
| 233 | # Set model from config if available (2nd arg) |
| 234 | if len(args) >= 2: |
| 235 | options = args[1] |
| 236 | if isinstance(options, dict): |
| 237 | config = options.get("config", {}) |
| 238 | if config.get("model"): |
| 239 | span.set_attribute("gen_ai.request.model", config["model"]) |
| 240 | # Also check for provider id |
| 241 | if options.get("id"): |
| 242 | span.set_attribute("promptfoo.provider.id", options["id"]) |
no test coverage detected
searching dependent graphs…