OTEL Collector¶
otel
¶
OTLP HTTP/JSON receiver and token/cost summary.
Lightweight collector that accepts OTLP exports for metrics and logs, tracks token usage over a sliding window, and prints a summary.
UsageSummary
¶
Bases: NamedTuple
Usage totals and models with Codex completion events from one OTEL log.
start_collector(run_dir, bind_addr='127.0.0.1')
¶
Start the OTEL collector as a subprocess. Returns (proc, port).
Source code in src/agentic_ci/otel.py
stop_collector(proc)
¶
parse_metrics(records)
¶
Parse OTLP JSONL records into structured token/cost data.
read_usage_summary(log_file)
¶
Read curated usage totals without printing or modifying the log.
Raises OSError for unreadable logs and ValueError for a line that is not JSON. Valid JSON with an unexpected shape is skipped, not raised.
Source code in src/agentic_ci/otel.py
print_summary(log_file)
¶
Print a human-readable token/cost summary from an OTEL JSONL log.
Returns a :class:UsageSummary. Missing, unreadable, empty, or invalid
logs return empty model names, token totals, and cost totals.
Source code in src/agentic_ci/otel.py
append_codex_usage(log_file, summary, *, start_ns=None)
¶
Append agentic-ci-owned Codex usage totals to an OTEL JSONL log.
Only models with completion events in summary are written. Unknown
prices omit the cost point but retain tokens. Returns True when written.
start_ns is the run start time for the cumulative sums; when unknown,
the collection time is used as the start of the series.
Source code in src/agentic_ci/otel.py
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 | |
generate_trace_context()
¶
Generate W3C Trace Context components for orchestrator-owned root spans.
Returns (trace_id, span_id, traceparent) where traceparent is a valid W3C traceparent header value. If the agent's OTEL SDK picks up the TRACEPARENT env var, its spans become children of this root span.
Source code in src/agentic_ci/otel.py
root_span_attributes(backend, harness, model, effort=None, subagent_effort=None)
¶
Return the synthetic root span attributes for one agent run.
Always sets agent.backend, agent.harness and agent.model;
adds agent.reasoning_effort and agent.subagent_reasoning_effort
when those efforts are in effect, so MLflow and JSONL consumers can see
the effective effort next to the model.
Source code in src/agentic_ci/otel.py
inject_root_spans(log_file, start_ns, end_ns, exit_code, fallback_trace_id=None, fallback_span_id=None, attributes=None)
¶
Stitch the run's traces together and append a synthetic root.
All traces in the JSONL belong to one agent run, so they are first merged
into a single trace (see :func:_stitch_run_traces). Then, for each trace
that has child spans but no root span (agent ignored TRACEPARENT,
container crash, OOM, timeout), a synthetic root span is appended to the
JSONL file. If no spans exist at all and fallback_trace_id is provided, a
standalone root span is created so MLflow always has at least one
complete trace. When fallback_span_id is set, the fallback root reuses
that span ID so children that were parented via TRACEPARENT stay
connected.
Returns the number of synthetic root spans injected.
Source code in src/agentic_ci/otel.py
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 | |
main()
¶
Run the OTEL collector server.