Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions http_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ func (p *Proxy) ListenAndServe(ctx context.Context) error {
p.CountryLookup,
p.ISPLookup,
p.ProxyName,
p.Track,
)
if err != nil {
return errors.New("Unable to configure instrumentation: %v", err)
Expand Down
6 changes: 5 additions & 1 deletion instrument/goodput_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func newGoodputInstrument(t *testing.T) (*defaultInstrument, *sdkmetric.ManualRe
provider := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader))
sdkotel.SetMeterProvider(provider)

ins, err := NewDefault(geo.NoLookup{}, &mockISPLookup{}, "test-proxy")
ins, err := NewDefault(geo.NoLookup{}, &mockISPLookup{}, "test-proxy", "test-track")
require.NoError(t, err)
return ins, reader
}
Expand All @@ -53,6 +53,10 @@ func TestSessionGoodput(t *testing.T) {

attrs := extractHistogramAttrs(rm, "proxy.session.goodput")
assert.Equal(t, "receive", attrs["network.io.direction"])
// track must be a point attribute keyed "track" so the bandit evaluator can
// slice goodput per (track, country); it queries this label, not the
// "proxy.track" resource attribute.
assert.Equal(t, "test-track", attrs["track"], "goodput sample should carry the track point attribute")
// The country point attribute must always be present (empty here, since the
// test uses geo.NoLookup) so the metric stays sliceable by country.
_, hasCountry := attrs["geo.country.iso_code"]
Expand Down
15 changes: 12 additions & 3 deletions instrument/instrument.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,10 @@ type defaultInstrument struct {
originStats map[originDetails]*usage
statsMx sync.Mutex
proxyName string
track string
}

func NewDefault(countryLookup geo.CountryLookup, ispLookup geo.ISPLookup, proxyName string) (*defaultInstrument, error) {
func NewDefault(countryLookup geo.CountryLookup, ispLookup geo.ISPLookup, proxyName, track string) (*defaultInstrument, error) {
if err := otelinstrument.Initialize(); err != nil {
return nil, err
}
Expand All @@ -127,6 +128,7 @@ func NewDefault(countryLookup geo.CountryLookup, ispLookup geo.ISPLookup, proxyN
clientStats: make(map[clientDetails]*usage),
originStats: make(map[originDetails]*usage),
proxyName: proxyName,
track: track,
}

return p, nil
Expand Down Expand Up @@ -320,8 +322,14 @@ func (ins *defaultInstrument) ProxiedBytes(ctx context.Context, sent, recv int,
// periods, so this is a floor on true transfer speed — but both arms of a
// bandit experiment are measured identically, so it's a fair relative signal,
// and the byte floor filters the worst idle-dominated noise. No device_id tag
// (cardinality); track and cloud.region come from resource attributes, leaving
// geo.country.iso_code as the only point attribute the evaluator strata need.
// (cardinality). track is emitted as a point attribute keyed "track": the bandit
// evaluator slices goodput per (track, country) and queries that low-cardinality
// point attribute (matching lantern-box). The resource also carries the track as
// semconv.ProxyTrackKey ("proxy.track"), but the metrics pipeline doesn't expose
// resource attributes as queryable labels, so the evaluator's "track" filter
// can't see it — hence the explicit point attribute. cloud.region is left to the
// resource: the strata are (track, country) only and a challenger is pinned to
// one DC, so region would add cardinality without decision value.
func (ins *defaultInstrument) SessionGoodput(ctx context.Context, recvBytes int, duration time.Duration, clientIP net.IP) {
if recvBytes < goodputMinBytes || duration <= 0 {
return
Expand All @@ -330,6 +338,7 @@ func (ins *defaultInstrument) SessionGoodput(ctx context.Context, recvBytes int,
country := ins.countryLookup.CountryCode(clientIP)
otelinstrument.SessionGoodput.Record(ctx, goodput,
metric.WithAttributes(
attribute.String("track", ins.track),
semconv.GeoCountryISOCodeKey.String(country),
semconv.NetworkIODirectionKey.String("receive"),
))
Expand Down
8 changes: 4 additions & 4 deletions instrument/otelinstrument/otelinstrument.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ func initialize() error {
}
// Per-session download goodput (received bytes per second of connection
// lifetime), recorded once at connection close for sessions that moved at
// least goodputMinBytes. Sliceable by track (resource attr) × cloud.region
// (resource attr) × geo.country.iso_code (point attr) so the bandit
// experiment evaluator can compare a challenger track's median goodput
// against the incumbent's. Unit "bytes/s" follows proxy.io's "bytes"
// least goodputMinBytes. Sliceable by track × geo.country.iso_code (both
// point attrs) so the bandit experiment evaluator can compare a challenger
// track's median goodput against the incumbent's per market; cloud.region
// stays a resource attr. Unit "bytes/s" follows proxy.io's "bytes"
// spelling for consistency within this package's metrics.
if SessionGoodput, err = meter.Float64Histogram("proxy.session.goodput",
metric.WithUnit("bytes/s"),
Expand Down
Loading