Skip to content

Commit df31e7d

Browse files
sallyomclaude
andcommitted
Add OpenTelemetry manual instrumentation to KV Cache Manager
Implement custom tracing spans for observability into cache operations Changes: - Add OpenTelemetry SDK dependencies to go.mod - Create pkg/telemetry package with InitTracing() for setup - Add three custom spans to pkg/kvcache/indexer.go: * kvcache.manager.get_scores (SERVER): Main GetPodScores operation * kvcache.storage.lookup (INTERNAL): KV block index lookup * kvcache.scorer.compute (INTERNAL): Scoring algorithm execution - Instrument with attributes: * Model identifier, pod counts, block counts * Cache hit ratios and score distributions * Timing via automatic span duration tracking Key metrics captured: - kvcache.hit_ratio: Cache effectiveness (0.0-1.0) - kvcache.total_blocks_available: Available blocks across pods - kvcache.score.max/avg: Score distribution insights - kvcache.lookup.cache_hit: Whether blocks were found Security: Metadata-only tracing (no prompts, tokens, or sensitive data) Co-Authored-By: Claude <[email protected]> Signed-off-by: sallyom <[email protected]>
1 parent 268dcf1 commit df31e7d

File tree

4 files changed

+273
-5
lines changed

4 files changed

+273
-5
lines changed

go.mod

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,36 @@ require (
1717
github.com/redis/go-redis/v9 v9.7.3
1818
github.com/stretchr/testify v1.10.0
1919
github.com/vmihailenco/msgpack/v5 v5.4.1
20+
go.opentelemetry.io/otel v1.33.0
21+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0
22+
go.opentelemetry.io/otel/sdk v1.33.0
23+
go.opentelemetry.io/otel/trace v1.33.0
2024
go.uber.org/multierr v1.11.0
2125
golang.org/x/net v0.38.0
2226
golang.org/x/sync v0.12.0
2327
google.golang.org/grpc v1.68.1
2428
google.golang.org/protobuf v1.36.5
2529
k8s.io/apimachinery v0.33.0
2630
k8s.io/client-go v0.33.0
31+
k8s.io/klog/v2 v2.130.1
2732
sigs.k8s.io/controller-runtime v0.21.0
2833
)
2934

3035
require (
3136
github.com/beorn7/perks v1.0.1 // indirect
37+
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
3238
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
3339
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
3440
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
41+
github.com/go-logr/stdr v1.2.2 // indirect
3542
github.com/go-openapi/jsonpointer v0.21.0 // indirect
3643
github.com/go-openapi/jsonreference v0.20.2 // indirect
3744
github.com/go-openapi/swag v0.23.0 // indirect
3845
github.com/gogo/protobuf v1.3.2 // indirect
3946
github.com/google/gnostic-models v0.6.9 // indirect
4047
github.com/google/go-cmp v0.7.0 // indirect
4148
github.com/google/uuid v1.6.0 // indirect
49+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
4250
github.com/josharian/intern v1.0.0 // indirect
4351
github.com/json-iterator/go v1.1.12 // indirect
4452
github.com/mailru/easyjson v0.7.7 // indirect
@@ -53,17 +61,21 @@ require (
5361
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
5462
github.com/x448/float16 v0.8.4 // indirect
5563
github.com/yuin/gopher-lua v1.1.1 // indirect
64+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
65+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 // indirect
66+
go.opentelemetry.io/otel/metric v1.33.0 // indirect
67+
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
5668
golang.org/x/oauth2 v0.27.0 // indirect
5769
golang.org/x/sys v0.35.0 // indirect
5870
golang.org/x/term v0.30.0 // indirect
5971
golang.org/x/text v0.23.0 // indirect
6072
golang.org/x/time v0.9.0 // indirect
73+
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
6174
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
6275
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
6376
gopkg.in/inf.v0 v0.9.1 // indirect
6477
gopkg.in/yaml.v3 v3.0.1 // indirect
6578
k8s.io/api v0.33.0 // indirect
66-
k8s.io/klog/v2 v2.130.1 // indirect
6779
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
6880
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
6981
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect

go.sum

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
66
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
77
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
88
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
9+
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
10+
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
911
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
1012
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
1113
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -27,8 +29,11 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER
2729
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
2830
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
2931
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
32+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
3033
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
3134
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
35+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
36+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
3237
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
3338
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
3439
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
@@ -53,6 +58,8 @@ github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgY
5358
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
5459
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
5560
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
61+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
62+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
5663
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
5764
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
5865
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -61,13 +68,17 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
6168
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
6269
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
6370
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
71+
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
72+
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
6473
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
6574
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
6675
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
6776
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
6877
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
6978
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
7079
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
80+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
81+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
7182
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
7283
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
7384
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -123,6 +134,22 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
123134
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
124135
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
125136
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
137+
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
138+
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
139+
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
140+
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
141+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA=
142+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI=
143+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM=
144+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA=
145+
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
146+
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
147+
go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM=
148+
go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM=
149+
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
150+
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
151+
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
152+
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
126153
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
127154
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
128155
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -168,6 +195,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
168195
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
169196
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
170197
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
198+
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
199+
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
171200
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
172201
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
173202
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=

pkg/kvcache/indexer.go

Lines changed: 133 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ import (
2020
"context"
2121
"fmt"
2222

23+
"go.opentelemetry.io/otel/attribute"
24+
"go.opentelemetry.io/otel/codes"
25+
"go.opentelemetry.io/otel/trace"
2326
"k8s.io/apimachinery/pkg/util/sets"
2427
"sigs.k8s.io/controller-runtime/pkg/log"
2528

2629
"github.com/llm-d/llm-d-kv-cache-manager/pkg/kvcache/kvblock"
2730
preprocessing "github.com/llm-d/llm-d-kv-cache-manager/pkg/preprocessing/chat_completions"
31+
"github.com/llm-d/llm-d-kv-cache-manager/pkg/telemetry"
2832
"github.com/llm-d/llm-d-kv-cache-manager/pkg/tokenization"
2933
"github.com/llm-d/llm-d-kv-cache-manager/pkg/tokenization/prefixstore"
3034
"github.com/llm-d/llm-d-kv-cache-manager/pkg/utils/logging"
@@ -132,6 +136,19 @@ func (k *Indexer) KVBlockIndex() kvblock.Index {
132136
func (k *Indexer) GetPodScores(ctx context.Context, renderReq *preprocessing.RenderJinjaTemplateRequest, prompt, modelName string,
133137
podIdentifiers []string,
134138
) (map[string]float64, error) {
139+
// Start tracing span for main operation
140+
tracer := telemetry.Tracer()
141+
ctx, span := tracer.Start(ctx, "kvcache.manager.get_scores",
142+
trace.WithSpanKind(trace.SpanKindServer),
143+
)
144+
defer span.End()
145+
146+
// Set initial attributes
147+
span.SetAttributes(
148+
attribute.String("gen_ai.request.model", modelName),
149+
attribute.Int("kvcache.pod_count", len(podIdentifiers)),
150+
)
151+
135152
traceLogger := log.FromContext(ctx).V(logging.TRACE).WithName("kvcache.GetPodScores")
136153

137154
// 1. tokenize prompt
@@ -141,30 +158,142 @@ func (k *Indexer) GetPodScores(ctx context.Context, renderReq *preprocessing.Ren
141158
blockKeys := k.tokensProcessor.TokensToKVBlockKeys(tokens, modelName)
142159
if len(blockKeys) == 0 {
143160
traceLogger.Info("no block keys found, returning empty scores")
161+
span.SetAttributes(attribute.Int("kvcache.block_keys.count", 0))
162+
span.SetStatus(codes.Ok, "")
144163
//nolint:nilnil // no need to return an error
145164
return nil, nil
146165
}
147166

167+
span.SetAttributes(attribute.Int("kvcache.block_keys.count", len(blockKeys)))
148168
traceLogger.Info("found tokens", "tokens", tokens, "block-keys", blockKeys)
149169

150-
// 3. query kvblock indexer for pods
151-
keyToPods, err := k.kvBlockIndex.Lookup(ctx, blockKeys, sets.New(podIdentifiers...))
170+
// 3. query kvblock indexer for pods (with child span)
171+
keyToPods, err := k.lookupWithSpan(ctx, blockKeys, sets.New(podIdentifiers...))
152172
if err != nil {
173+
span.RecordError(err)
174+
span.SetStatus(codes.Error, err.Error())
153175
return nil, fmt.Errorf("failed to query kvblock indexer: %w", err)
154176
}
155177
traceLogger.Info("found block keys", "block-keys", blockKeys,
156178
"pods", podsPerKeyPrintHelper(keyToPods))
157179

158-
// 4. score pods
159-
podScores, err := k.kvBlockScorer.Score(blockKeys, keyToPods)
180+
// Calculate total blocks available
181+
totalBlocksAvailable := 0
182+
for _, pods := range keyToPods {
183+
totalBlocksAvailable += len(pods)
184+
}
185+
span.SetAttributes(attribute.Int("kvcache.total_blocks_available", totalBlocksAvailable))
186+
187+
// 4. score pods (with child span)
188+
podScores, err := k.scoreWithSpan(ctx, blockKeys, keyToPods)
160189
if err != nil {
190+
span.RecordError(err)
191+
span.SetStatus(codes.Error, err.Error())
161192
return nil, fmt.Errorf("failed to query kvblock scorer: %w", err)
162193
}
163194
traceLogger.Info("found pod scores", "pod-scores", podScores)
164195

196+
// Calculate hit ratio (pods with non-zero scores / total pods)
197+
podsWithHits := 0
198+
for _, score := range podScores {
199+
if score > 0 {
200+
podsWithHits++
201+
}
202+
}
203+
hitRatio := 0.0
204+
if len(podIdentifiers) > 0 {
205+
hitRatio = float64(podsWithHits) / float64(len(podIdentifiers))
206+
}
207+
span.SetAttributes(
208+
attribute.Float64("kvcache.hit_ratio", hitRatio),
209+
attribute.Int("kvcache.pods_with_hits", podsWithHits),
210+
)
211+
212+
span.SetStatus(codes.Ok, "")
165213
return podScores, nil
166214
}
167215

216+
// lookupWithSpan wraps kvBlockIndex.Lookup with a tracing span
217+
func (k *Indexer) lookupWithSpan(ctx context.Context, blockKeys []kvblock.Key, podSet sets.Set[string]) (map[kvblock.Key][]kvblock.PodEntry, error) {
218+
tracer := telemetry.Tracer()
219+
ctx, span := tracer.Start(ctx, "kvcache.storage.lookup",
220+
trace.WithSpanKind(trace.SpanKindInternal),
221+
)
222+
defer span.End()
223+
224+
span.SetAttributes(
225+
attribute.Int("kvcache.lookup.block_count", len(blockKeys)),
226+
attribute.Int("kvcache.lookup.pod_filter_count", podSet.Len()),
227+
)
228+
229+
result, err := k.kvBlockIndex.Lookup(ctx, blockKeys, podSet)
230+
if err != nil {
231+
span.RecordError(err)
232+
span.SetStatus(codes.Error, err.Error())
233+
return nil, err
234+
}
235+
236+
// Calculate cache hit metrics
237+
blocksFound := 0
238+
for _, pods := range result {
239+
if len(pods) > 0 {
240+
blocksFound++
241+
}
242+
}
243+
cacheHit := blocksFound > 0
244+
245+
span.SetAttributes(
246+
attribute.Bool("kvcache.lookup.cache_hit", cacheHit),
247+
attribute.Int("kvcache.lookup.blocks_found", blocksFound),
248+
)
249+
250+
span.SetStatus(codes.Ok, "")
251+
return result, nil
252+
}
253+
254+
// scoreWithSpan wraps kvBlockScorer.Score with a tracing span
255+
func (k *Indexer) scoreWithSpan(ctx context.Context, keys []kvblock.Key, keyToPods map[kvblock.Key][]kvblock.PodEntry) (map[string]float64, error) {
256+
tracer := telemetry.Tracer()
257+
ctx, span := tracer.Start(ctx, "kvcache.scorer.compute",
258+
trace.WithSpanKind(trace.SpanKindInternal),
259+
)
260+
defer span.End()
261+
262+
span.SetAttributes(
263+
attribute.String("kvcache.scorer.algorithm", string(k.kvBlockScorer.Strategy())),
264+
attribute.Int("kvcache.scorer.key_count", len(keys)),
265+
)
266+
267+
scores, err := k.kvBlockScorer.Score(keys, keyToPods)
268+
if err != nil {
269+
span.RecordError(err)
270+
span.SetStatus(codes.Error, err.Error())
271+
return nil, err
272+
}
273+
274+
// Calculate score distribution
275+
if len(scores) > 0 {
276+
maxScore := 0.0
277+
totalScore := 0.0
278+
for _, score := range scores {
279+
if score > maxScore {
280+
maxScore = score
281+
}
282+
totalScore += score
283+
}
284+
avgScore := totalScore / float64(len(scores))
285+
286+
span.SetAttributes(
287+
attribute.Float64("kvcache.score.max", maxScore),
288+
attribute.Float64("kvcache.score.avg", avgScore),
289+
attribute.Int("kvcache.scorer.pods_scored", len(scores)),
290+
)
291+
}
292+
293+
span.SetStatus(codes.Ok, "")
294+
return scores, nil
295+
}
296+
168297
// podsPerKeyPrintHelper formats a map of keys to pod entries for printing.
169298
func podsPerKeyPrintHelper(ks map[kvblock.Key][]kvblock.PodEntry) string {
170299
flattened := ""

0 commit comments

Comments
 (0)