Documentation
¶
Overview ¶
Package overhead splits per-request overhead latency into per-phase buckets from a completed trace's spans. Shared by logging (stores the full breakdown per log row) and the metrics plugins (export a folded per-component histogram) so all three agree.
Index ¶
- Constants
- func Compute(trace *schemas.Trace, overheadMs float64, overheadOK bool, upstreamMs float64, ...) ([]logstore.OverheadBucket, float64, bool)
- func ComputeForMetrics(trace *schemas.Trace) map[string]float64
- func MetricComponent(b logstore.OverheadBucket) string
- func TraceAttrFloatMs(attrs map[string]any, key string) (float64, bool)
Constants ¶
const ( CategorySerialization = "serialization" CategoryConversion = "conversion" CategoryPlugins = "plugins" CategoryMiddleware = "middleware" CategoryRouting = "routing" CategoryProcessing = "processing" CategoryNetworking = "networking" CategoryStreaming = "streaming" // CategoryProtocolSDK: time spent inside the third-party A2A protocol library // (request decode, method routing, response marshal), kept separate from // "processing" so library cost is not read as Bifrost pipeline cost. CategoryProtocolSDK = "protocol_sdk" // CategoryMiscellaneous: overhead not worth its own span. Folds the core "miscellaneous" // glue span and the "scheduling" residual (overhead minus the measured phases). CategoryMiscellaneous = "miscellaneous" CategoryOther = "other" )
overhead_component values emitted by ComputeForMetrics: the UI's top-level overhead categories, so the metric and the log-detail view share one vocabulary. Keep in sync with overheadCategoryKey / OVERHEAD_BUCKET_CATEGORY in ui/app/workspace/logs/sheets/logDetailView.tsx (paired Go/TS definitions).
Variables ¶
This section is empty.
Functions ¶
func Compute ¶
func Compute(trace *schemas.Trace, overheadMs float64, overheadOK bool, upstreamMs float64, upstreamOK bool) ([]logstore.OverheadBucket, float64, bool)
Compute decomposes Bifrost overhead across spans by self-time: each span's own wall duration minus the wall duration of its direct children. Self-times across the tree are non-overlapping and sum to the root duration, so summing the overhead-side buckets is an independent measure of overhead that does not depend on the upstream socket accumulator. Only overhead-side spans produce a bucket; provider/upstream spans still subtract from their parent's self-time.
The remaining overhead (the stamped total, minus the measured plugin/internal self-time) is attributed to a residual "scheduling" bucket: the goroutine-scheduling latency between phases plus any glue no phase span has captured yet. Now that request/response conversion, marshal, and parse each have their own phase span, this residual is small. It is derived from overheadMs (which already excludes upstream), not from the root span's self-time, so it never picks up streaming socket reads. Buckets are returned with microsecond values, measured spans first (chronological) then the scheduling residual.
Compute returns the per-phase buckets, the measured Bifrost-CPU total in ms (the sum of those buckets), and whether this was a streaming request. For streams the caller uses measuredMs as the overhead (see the logging plugin's Inject): total-upstream over-counts stream overhead because it includes off-CPU relay/scheduler wait between chunks, which is not Bifrost work.
func ComputeForMetrics ¶
ComputeForMetrics rolls the breakdown up for metric export: overhead_component -> microseconds. Reads overhead/upstream durations off the root span, so callers pass only the trace. Returns nil when there's nothing to record, so callers can skip observation.
func MetricComponent ¶
func MetricComponent(b logstore.OverheadBucket) string
MetricComponent maps one bucket to its category, mirroring the UI's overheadCategoryKey: serialization phases, middleware.*, convertor(.*) and plugin.* by rule, else bucketCategory, else "other". overheadBucketName guarantees the plugin.* prefix, so Kind needs no fallback here.
Types ¶
This section is empty.