Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OTel-Go Consistent Probability Sampler and conformance tests #1379

Merged
merged 47 commits into from Apr 26, 2022
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
bf06b79
Second prototype (based on OTel-Go draft PR #2177 from main repo)
jmacd Oct 27, 2021
b17b13c
comments
jmacd Oct 27, 2021
852c242
add a test for sampled vs r/p-value consistency
jmacd Oct 27, 2021
7fc989b
adding tests
jmacd Oct 28, 2021
d6295d5
test various D values
jmacd Oct 29, 2021
63f36fb
test spec
jmacd Nov 2, 2021
f6e50b5
have the test print the specification table
jmacd Nov 2, 2021
6bf816f
output the table used in the spec
jmacd Nov 2, 2021
418aac5
remove a package
jmacd Nov 2, 2021
48a7daf
Merge branch 'main' of github.com:open-telemetry/opentelemetry-go-con…
jmacd Nov 2, 2021
8ac4b54
comment
jmacd Nov 2, 2021
b3a2e9d
add tracestate handling tests
jmacd Nov 3, 2021
6e56ff4
remove a file
jmacd Nov 3, 2021
c5c42fa
add parent test
jmacd Nov 3, 2021
9b6a591
100% coverage
jmacd Nov 3, 2021
1c3145f
lint
jmacd Nov 3, 2021
4a74478
Merge branch 'main' into jmacd/probsample
jmacd Nov 16, 2021
72c418e
propose short tests
jmacd Nov 17, 2021
4715db2
clarify test settings
jmacd Nov 17, 2021
090c7f2
raise test timeout
jmacd Nov 17, 2021
fb0fe84
raise more
jmacd Nov 17, 2021
d951723
disable statistical test w/ race detector
jmacd Nov 17, 2021
6dbfe35
missing file
jmacd Nov 17, 2021
04dae4b
test fix
jmacd Nov 19, 2021
89ea220
Merge branch 'main' of github.com:open-telemetry/opentelemetry-go-con…
jmacd Dec 10, 2021
fb378f8
Merge branch 'main' of github.com:open-telemetry/opentelemetry-go-con…
jmacd Jan 7, 2022
23489ae
mod tidy
jmacd Jan 7, 2022
23dd9f6
Merge branch 'main' of github.com:open-telemetry/opentelemetry-go-con…
jmacd Jan 26, 2022
4e1171d
Merge branch 'main' of github.com:open-telemetry/opentelemetry-go-con…
jmacd Feb 4, 2022
7cfe766
shorten the test runtime
jmacd Feb 4, 2022
e339747
even shorter
jmacd Feb 4, 2022
a3e74a1
shorten the test; lint
jmacd Feb 4, 2022
fcaea33
Merge branch 'main' of github.com:open-telemetry/opentelemetry-go-con…
jmacd Feb 14, 2022
e8257a1
run 3 / 15 non-deterministically
jmacd Feb 14, 2022
7fa6a76
Merge branch 'main' into jmacd/probsample
jmacd Feb 16, 2022
554e3e4
Update samplers/probability/consistent/sampler.go
jmacd Feb 22, 2022
d536b64
Merge branch 'main' into jmacd/probsample
jmacd Feb 28, 2022
7e7ec20
Merge branch 'main' of github.com:open-telemetry/opentelemetry-go-con…
jmacd Apr 1, 2022
23cc752
Merge branch 'jmacd/probsample' of github.com:jmacd/opentelemetry-go-…
jmacd Apr 1, 2022
58d6ddc
Apply suggestions from code review
jmacd Apr 1, 2022
77e3fbe
test one more thing
jmacd Apr 1, 2022
19b8de4
Merge branch 'jmacd/probsample' of github.com:jmacd/opentelemetry-go-…
jmacd Apr 1, 2022
50516b0
lint
jmacd Apr 1, 2022
d3bc61f
changelog & readme
jmacd Apr 1, 2022
36f3e67
revert accidental golint fix
jmacd Apr 1, 2022
d2baa56
godoc
jmacd Apr 1, 2022
95cd108
Merge branch 'main' into jmacd/probsample
Aneurysm9 Apr 25, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Expand Up @@ -723,3 +723,13 @@ updates:
schedule:
interval: "weekly"
day: "sunday"
-
package-ecosystem: "gomod"
directory: "/samplers/probability/consistent"
labels:
- dependencies
- go
- "Skip Changelog"
schedule:
interval: "weekly"
day: "sunday"
Expand Up @@ -24,7 +24,7 @@ type ExampleController struct {

func (c *ExampleController) Get() {
// name of the template in the views directory
c.TplName = "index.tpl"
c.Controller.TplName = "index.tpl"
jmacd marked this conversation as resolved.
Show resolved Hide resolved

// explicit call to Render
if err := Render(&c.Controller); err != nil {
Expand Down
69 changes: 69 additions & 0 deletions samplers/probability/consistent/base2.go
@@ -0,0 +1,69 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package consistent // import "go.opentelemetry.io/contrib/samplers/probability/consistent"

import "math"

// These are IEEE 754 double-width floating point constants used with
// math.Float64bits.
const (
offsetExponentMask = 0x7ff0000000000000
offsetExponentBias = 1023
significandBits = 52
)

// expFromFloat64 returns floor(log2(x)).
func expFromFloat64(x float64) int {
return int((math.Float64bits(x)&offsetExponentMask)>>significandBits) - offsetExponentBias
}

// expToFloat64 returns 2^x.
func expToFloat64(x int) float64 {
return math.Float64frombits(uint64(offsetExponentBias+x) << significandBits)
}

// splitProb returns the two values of log-adjusted-count nearest to p
// Example:
//
// splitProb(0.375) => (2, 1, 0.5)
//
// indicates to sample with probability (2^-2) 50% of the time
// and (2^-1) 50% of the time.
func splitProb(p float64) (uint8, uint8, float64) {
if p < 2e-62 {
// Note: spec.
return pZeroValue, pZeroValue, 1
}
// Take the exponent and drop the significand to locate the
// smaller of two powers of two.
exp := expFromFloat64(p)

// Low is the smaller of two log-adjusted counts, the negative
// of the exponent computed above.
low := -exp
// High is the greater of two log-adjusted counts (i.e., one
// less than low, a smaller adjusted count means a larger
// probability).
high := low - 1

// Return these to probability values and use linear
// interpolation to compute the required probability of
// choosing the low-probability Sampler.
lowP := expToFloat64(-low)
highP := expToFloat64(-high)
lowProb := (highP - p) / (highP - lowP)

return uint8(low), uint8(high), lowProb
}
61 changes: 61 additions & 0 deletions samplers/probability/consistent/base2_test.go
@@ -0,0 +1,61 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package consistent

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestSplitProb(t *testing.T) {
require.Equal(t, -1, expFromFloat64(0.6))
require.Equal(t, -2, expFromFloat64(0.4))
require.Equal(t, 0.5, expToFloat64(-1))
require.Equal(t, 0.25, expToFloat64(-2))

for _, tc := range []struct {
in float64
low uint8
lowProb float64
}{
// Probability 0.75 corresponds with choosing S=1 (the
// "low" probability) 50% of the time and S=0 (the
// "high" probability) 50% of the time.
{0.75, 1, 0.5},
{0.6, 1, 0.8},
{0.9, 1, 0.2},

// Powers of 2 exactly
{1, 0, 1},
{0.5, 1, 1},
{0.25, 2, 1},

// Smaller numbers
{0.05, 5, 0.4},
{0.1, 4, 0.4}, // 0.1 == 0.4 * 1/16 + 0.6 * 1/8
{0.003, 9, 0.464},

// Special cases:
{0, 63, 1},
} {
low, high, lowProb := splitProb(tc.in)
require.Equal(t, tc.low, low, "got %v want %v", low, tc.low)
if lowProb != 1 {
require.Equal(t, tc.low-1, high, "got %v want %v", high, tc.low-1)
}
require.InEpsilon(t, tc.lowProb, lowProb, 1e-6, "got %v want %v", lowProb, tc.lowProb)
}
}
10 changes: 10 additions & 0 deletions samplers/probability/consistent/go.mod
@@ -0,0 +1,10 @@
module go.opentelemetry.io/contrib/samplers/probability/consistent

go 1.15
jmacd marked this conversation as resolved.
Show resolved Hide resolved

require (
github.com/stretchr/testify v1.7.0
go.opentelemetry.io/otel v1.2.0
go.opentelemetry.io/otel/sdk v1.1.0
go.opentelemetry.io/otel/trace v1.2.0
jmacd marked this conversation as resolved.
Show resolved Hide resolved
)
25 changes: 25 additions & 0 deletions samplers/probability/consistent/go.sum
@@ -0,0 +1,25 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.opentelemetry.io/otel v1.1.0/go.mod h1:7cww0OW51jQ8IaZChIEdqLwgh+44+7uiTdWsAL0wQpA=
go.opentelemetry.io/otel v1.2.0 h1:YOQDvxO1FayUcT9MIhJhgMyNO1WqoduiyvQHzGN0kUQ=
go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I=
go.opentelemetry.io/otel/sdk v1.1.0 h1:j/1PngUJIDOddkCILQYTevrTIbWd494djgGkSsMit+U=
go.opentelemetry.io/otel/sdk v1.1.0/go.mod h1:3aQvM6uLm6C4wJpHtT8Od3vNzeZ34Pqc6bps8MywWzo=
go.opentelemetry.io/otel/trace v1.1.0/go.mod h1:i47XtdcBQiktu5IsrPqOHe8w+sBmnLwwHt8wiUsWGTI=
go.opentelemetry.io/otel/trace v1.2.0 h1:Ys3iqbqZhcf28hHzrm5WAquMkDHNZTUkw7KHbuNjej0=
go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
68 changes: 68 additions & 0 deletions samplers/probability/consistent/parent.go
@@ -0,0 +1,68 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package consistent // import "go.opentelemetry.io/contrib/samplers/probability/consistent"

import (
"strings"

"go.opentelemetry.io/otel"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
)

type (
parentProbabilitySampler struct {
delegate sdktrace.Sampler
}
)

func ParentProbabilityBased(root sdktrace.Sampler, samplers ...sdktrace.ParentBasedSamplerOption) sdktrace.Sampler {
jmacd marked this conversation as resolved.
Show resolved Hide resolved
return &parentProbabilitySampler{
delegate: sdktrace.ParentBased(root, samplers...),
}
}

func (p *parentProbabilitySampler) ShouldSample(params sdktrace.SamplingParameters) sdktrace.SamplingResult {
psc := trace.SpanContextFromContext(params.ParentContext)

// Note: We do not check psc.IsValid(), i.e., we repair the tracestate
// with or without a parent TraceId and SpanId.
state := psc.TraceState()

otts, err := parseOTelTraceState(state.Get(traceStateKey), psc.IsSampled())

if err != nil {
otel.Handle(err)
value := otts.serialize()
if len(value) > 0 {
// Note: see the note in
// "go.opentelemetry.io/otel/trace".TraceState.Insert(). The
// error below is not a condition we're supposed to handle.
state, _ = state.Insert(traceStateKey, value)
} else {
state = state.Delete(traceStateKey)
}

// Fix the broken tracestate before calling the delegate.
params.ParentContext =
trace.ContextWithSpanContext(params.ParentContext, psc.WithTraceState(state))
jmacd marked this conversation as resolved.
Show resolved Hide resolved
}

return p.delegate.ShouldSample(params)
}

func (p *parentProbabilitySampler) Description() string {
return "ParentProbabilityBased" + strings.TrimPrefix(p.delegate.Description(), "ParentBased")
}