Skip to content
This repository was archived by the owner on Jun 14, 2023. It is now read-only.

Commit

Permalink
Add tracer sampler (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
xbkaishui authored Sep 13, 2020
1 parent fdae247 commit 5ff73ea
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 5 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ if err != nil {
}
defer r.Close()
tracer, err := go2sky.NewTracer("example", go2sky.WithReporter(r))
// create with sampler
// tracer, err := go2sky.NewTracer("example", go2sky.WithReporter(r), go2sky.WithSampler(0.5))
```

You can also create tracer with sampling rate.
```go
....
tracer, err := go2sky.NewTracer("example", go2sky.WithReporter(r), go2sky.WithSampler(0.5))
```

## Create span
Expand Down
68 changes: 68 additions & 0 deletions sampler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Licensed to SkyAPM org under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. SkyAPM org licenses this file to you 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 go2sky

import (
"math/rand"
"time"
)

type Sampler interface {
IsSampled(operation string) (sampled bool)
}

type ConstSampler struct {
decision bool
}

// NewConstSampler creates a ConstSampler.
func NewConstSampler(sample bool) *ConstSampler {
s := &ConstSampler{
decision: sample,
}
return s
}

// IsSampled implements IsSampled() of Sampler.
func (s *ConstSampler) IsSampled(operation string) bool {
return s.decision
}

type RandomSampler struct {
samplingRate float64
rand *rand.Rand
threshold int
}

// IsSampled implements IsSampled() of Sampler.
func (s *RandomSampler) IsSampled(operation string) bool {
return s.threshold >= s.rand.Intn(100)
}

func (s *RandomSampler) init() {
s.rand = rand.New(rand.NewSource(time.Now().Unix()))
s.threshold = int(s.samplingRate * 100)
}

func NewRandomSampler(samplingRate float64) *RandomSampler {
s := &RandomSampler{
samplingRate: samplingRate,
}
s.init()
return s
}
47 changes: 47 additions & 0 deletions sampler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Licensed to SkyAPM org under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. SkyAPM org licenses this file to you 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 go2sky

import (
"testing"
)

func TestConstSampler_IsSampled(t *testing.T) {
sampler := NewConstSampler(true)
operationName := "op"
sampled := sampler.IsSampled(operationName)
if sampled != true {
t.Errorf("const sampler should be sampled")
}
samplerNegative := NewConstSampler(false)
sampledNegative := samplerNegative.IsSampled(operationName)
if sampledNegative != false {
t.Errorf("const sampler should not be sampled")
}
}

func TestRandomSampler_IsSampled(t *testing.T) {
randomSampler := NewRandomSampler(0.5)
//just for test case
randomSampler.threshold = 100
operationName := "op"
sampled := randomSampler.IsSampled(operationName)
if sampled != true {
t.Errorf("const sampler should be sampled")
}
}
7 changes: 7 additions & 0 deletions span_opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,10 @@ func WithSpanType(spanType SpanType) SpanOption {
s.SpanType = spanType
}
}

// WithOperationName setup span OperationName of a span
func WithOperationName(operationName string) SpanOption {
return func(s *defaultSpan) {
s.OperationName = operationName
}
}
27 changes: 23 additions & 4 deletions trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type Tracer struct {
reporter Reporter
// 0 not init 1 init
initFlag int32
sampler Sampler
}

// TracerOption allows for functional options to adjust behaviour
Expand Down Expand Up @@ -70,6 +71,10 @@ func NewTracer(service string, opts ...TracerOption) (tracer *Tracer, err error)
t.reporter.Boot(t.service, t.instance)
t.initFlag = 1
}

if t.sampler == nil {
t.sampler = NewConstSampler(true)
}
return t, nil
}

Expand All @@ -93,11 +98,10 @@ func (t *Tracer) CreateEntrySpan(ctx context.Context, operationName string, extr
return
}
}
s, nCtx, err = t.CreateLocalSpan(ctx, WithContext(refSc), WithSpanType(SpanTypeEntry))
s, nCtx, err = t.CreateLocalSpan(ctx, WithContext(refSc), WithSpanType(SpanTypeEntry), WithOperationName(operationName))
if err != nil {
return
}
s.SetOperationName(operationName)
return
}

Expand All @@ -117,6 +121,17 @@ func (t *Tracer) CreateLocalSpan(ctx context.Context, opts ...SpanOption) (s Spa
if !ok {
parentSpan = nil
}
isForceSample := len(ds.Refs) > 0
// Try to sample when it is not force sample
if parentSpan == nil && !isForceSample {
// Force sample
sampled := t.sampler.IsSampled(ds.OperationName)
if !sampled {
// Filter by sample just return noop span
s = &NoopSpan{}
return s, context.WithValue(ctx, ctxKeyInstance, s), nil
}
}
s, err = newSegmentSpan(ds, parentSpan)
if err != nil {
return nil, nil, err
Expand All @@ -132,11 +147,15 @@ func (t *Tracer) CreateExitSpan(ctx context.Context, operationName string, peer
if s, _ := t.createNoop(ctx); s != nil {
return s, nil
}
s, _, err := t.CreateLocalSpan(ctx, WithSpanType(SpanTypeExit))
s, _, err := t.CreateLocalSpan(ctx, WithSpanType(SpanTypeExit), WithOperationName(operationName))
if err != nil {
return nil, err
}
s.SetOperationName(operationName)
noopSpan, ok := interface{}(s).(NoopSpan)
if ok {
// Ignored, there is no need to inject SW8 in the request header
return &noopSpan, nil
}
s.SetPeer(peer)
spanContext := &propagation.SpanContext{}
span, ok := s.(ReportedSpan)
Expand Down
16 changes: 16 additions & 0 deletions trace_opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,19 @@ func WithInstance(instance string) TracerOption {
t.instance = instance
}
}

// WithSampler setup sampler
func WithSampler(samplingRate float64) TracerOption {
return func(t *Tracer) {
var sampler Sampler
//check const sampler
if samplingRate <= 0 {
sampler = NewConstSampler(false)
} else if samplingRate >= 1.0 {
sampler = NewConstSampler(true)
} else {
sampler = NewRandomSampler(samplingRate)
}
t.sampler = sampler
}
}
2 changes: 1 addition & 1 deletion trace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func TestNewTracer(t *testing.T) {
service string
opts []TracerOption
}{service: "test", opts: nil},
&Tracer{service: "test"},
&Tracer{service: "test", sampler: NewConstSampler(true)},
false,
},
}
Expand Down

3 comments on commit 5ff73ea

@eyjian
Copy link

@eyjian eyjian commented on 5ff73ea Nov 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.5版本不支持采样,量大时报“reach max send buffer”,超过了maxSendQueueSize值,不知道啥时发布支持采样的版本。最好智能采样,小压力时全量上报,大压力时自动调整采样率。业务的一次交易可能产生几100万的上报,这个时候只能采样压缩数据。

@rainbend
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.5版本不支持采样,量大时报“reach max send buffer”,超过了maxSendQueueSize值,不知道啥时发布支持采样的版本。最好智能采样,小压力时全量上报,大压力时自动调整采样率。业务的一次交易可能产生几100万的上报,这个时候只能采样压缩数据。

@eyjian Hi 我可以现在近期发布个 0.6.0的版本

@eyjian
Copy link

@eyjian eyjian commented on 5ff73ea Nov 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

及用采样特性,这个月能发布0.6.0吗?

Please sign in to comment.