feat(observability): add semantic pkgsite spans - #12
Conversation
|
| Filename | Overview |
|---|---|
| internal/observability/attrs.go | New file centralizing all span attribute helpers; contains a whitespace-handling inconsistency in ClassifyVersion's default branch. |
| internal/observability/attrs_test.go | New test file covering EndpointFromURL, ClassifyVersion, and RemainingBucket; missing vulns endpoint test cases. |
| internal/pkgsite/transport/cache.go | Cache transport migrated to typed CacheLookupAttrs; adds error recording for upstream client failures and write-outcome tracking. |
| internal/pkgsite/warmer.go | AsyncWarmer.run now returns a WarmOutcome alongside the error; adds per-job spans with outcome attributes and a validWarmKind guard. |
| internal/mcpserver/tools/register.go | Tool instrumentation migrated to typed ToolAttrs/EnvelopeAttrs; intArg may silently return 0 for JSON-decoded float64 limits. |
| internal/middleware/ratelimit.go | Rate-limit middleware now records outcome, remaining bucket, limit, and window on each span branch. |
| .github/workflows/fly-deploy.yml | Adds Sentry deployment notification step; fetch-depth changed to 0 to provide commit history. |
| internal/mcpserver/tools/tools_explain.go | Explain tool migrated from raw attribute.String calls to ToolAttrs struct; no logic changes. |
| internal/observability/cache.go | RecordCacheLookup and RecordCacheWrite updated to use centralized attribute constants and CacheWriteOutcomeFromOK helper. |
| internal/pkgsite/client_test.go | Test updated for the new (WarmOutcome, error) return signature of AsyncWarmer.run. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[HTTP Request] --> B{CachedDoer.Do}
B -->|non-GET or disabled| C[RecordCacheLookup: bypass/disabled]
B -->|GET + enabled| D[Start pkgsite.cache lookup span]
D --> E{kv.Store.Get}
E -->|hit| F[outcome=hit]
E -->|error| G[outcome=error, RecordError]
E -->|miss| H[outcome=miss]
G --> I[d.client.Do upstream]
H --> I
I -->|error| J[RecordError + return]
I -->|ok| K{cacheTTL > 0?}
K -->|yes| L[store.Set, writeOutcome=ok/error]
K -->|no| M[writeOutcome=skipped]
L --> N[SetAttributes: ttl, statusCode, writeOutcome]
M --> N
N --> O[Return response]
Comments Outside Diff (1)
-
internal/mcpserver/tools/register.go, line 135-141 (link)intArguses a directinttype assertion. Go'sencoding/jsonunmarshals all JSON numbers intofloat64when decoding intoany, so ifnextArgsoriginates from a JSON-decoded payload,args[key].(int)will always fail silently and return 0, meaningpkgsite.query.limitwould never be recorded in traces.
Reviews (1): Last reviewed commit: "feat(observability): add semantic pkgsit..." | Re-trigger Greptile
| func ClassifyVersion(version string) VersionClass { | ||
| switch strings.TrimSpace(version) { | ||
| case "": | ||
| return VersionClassEmpty | ||
| case "latest": | ||
| return VersionClassFloating | ||
| case "main", "master": | ||
| return VersionClassBranch | ||
| default: | ||
| if strings.HasPrefix(version, "v") && strings.Contains(version, ".") { | ||
| return VersionClassPinned | ||
| } | ||
| return VersionClassOther | ||
| } | ||
| } |
There was a problem hiding this comment.
ClassifyVersion trims whitespace before the switch but then uses the raw, untrimmed version inside the default case. A caller passing " v1.2.3" would fall through the switch correctly but then fail the HasPrefix("v") guard on the original string and be misclassified as VersionClassOther instead of VersionClassPinned.
| func ClassifyVersion(version string) VersionClass { | |
| switch strings.TrimSpace(version) { | |
| case "": | |
| return VersionClassEmpty | |
| case "latest": | |
| return VersionClassFloating | |
| case "main", "master": | |
| return VersionClassBranch | |
| default: | |
| if strings.HasPrefix(version, "v") && strings.Contains(version, ".") { | |
| return VersionClassPinned | |
| } | |
| return VersionClassOther | |
| } | |
| } | |
| func ClassifyVersion(version string) VersionClass { | |
| version = strings.TrimSpace(version) | |
| switch version { | |
| case "": | |
| return VersionClassEmpty | |
| case "latest": | |
| return VersionClassFloating | |
| case "main", "master": | |
| return VersionClassBranch | |
| default: | |
| if strings.HasPrefix(version, "v") && strings.Contains(version, ".") { | |
| return VersionClassPinned | |
| } | |
| return VersionClassOther | |
| } | |
| } |
| {raw: "https://pkg.go.dev/v1beta/imported-by/golang.org%2Fx%2Foauth2", want: PkgsiteEndpointImportedBy}, | ||
| } |
There was a problem hiding this comment.
TestEndpointFromURL covers every endpoint except PkgsiteEndpointVulns, which has a uniquely branched match — EndpointFromURL accepts both vuln/ and vulns/ prefixes. Without a test case here, neither path is exercised.
| {raw: "https://pkg.go.dev/v1beta/imported-by/golang.org%2Fx%2Foauth2", want: PkgsiteEndpointImportedBy}, | |
| } | |
| {raw: "https://pkg.go.dev/v1beta/imported-by/golang.org%2Fx%2Foauth2", want: PkgsiteEndpointImportedBy}, | |
| {raw: "https://pkg.go.dev/v1beta/vuln/GO-2021-0001", want: PkgsiteEndpointVulns}, | |
| {raw: "https://pkg.go.dev/v1beta/vulns/GO-2021-0001", want: PkgsiteEndpointVulns}, | |
| } |
pkgsitespan attributes behind typed helpers ininternal/observability.github/workflows/fly-deploy.ymlusing the stamped release value