Skip to content

Commit

Permalink
Configure sampling strategies (#139)
Browse files Browse the repository at this point in the history
* Configure sampling strategies

Signed-off-by: Gary Brown <[email protected]>

* Add example sampling config

Signed-off-by: Gary Brown <[email protected]>

* Move sampling example to separate file, and add text to README.adoc

Signed-off-by: Gary Brown <[email protected]>

* Fix production test

Signed-off-by: Gary Brown <[email protected]>

* Update following review comments

Signed-off-by: Gary Brown <[email protected]>

* Further test fix

Signed-off-by: Gary Brown <[email protected]>
  • Loading branch information
objectiser authored and jpkrohling committed Dec 3, 2018
1 parent c82a7c8 commit 9c9f809
Show file tree
Hide file tree
Showing 15 changed files with 298 additions and 18 deletions.
25 changes: 25 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,31 @@ The secrets are available as environment variables in the (Collector/Query/All-I

The secret itself would be managed outside of the `jaeger-operator` CR.

== Define sampling strategies

The operator can be used to define sampling strategies that will be supplied to tracers that have been configured
to use a remote sampler:

[source,yaml]
----
apiVersion: io.jaegertracing/v1alpha1
kind: Jaeger
metadata:
name: with-sampling
spec:
strategy: allInOne
sampling:
options:
default_strategy:
type: probabilistic
param: 50
----

This example defines a default sampling strategy that is probabilistic, with a 50% chance of the trace instances being
sampled.

Refer to the Jaeger documentation on link:https://www.jaegertracing.io/docs/1.8/sampling/#collector-sampling-configuration[Collector Sampling Configuration] to see how service and endpoint sampling can be configured. The JSON representation described in that documentation can be used in the operator by converting to YAML.

== Schema migration

=== Cassandra
Expand Down
11 changes: 11 additions & 0 deletions deploy/examples/with-sampling.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: io.jaegertracing/v1alpha1
kind: Jaeger
metadata:
name: with-sampling
spec:
strategy: allInOne
sampling:
options:
default_strategy:
type: probabilistic
param: 50
6 changes: 6 additions & 0 deletions pkg/apis/io/v1alpha1/jaeger_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type JaegerSpec struct {
Collector JaegerCollectorSpec `json:"collector"`
Agent JaegerAgentSpec `json:"agent"`
UI JaegerUISpec `json:"ui"`
Sampling JaegerSamplingSpec `json:"sampling"`
Storage JaegerStorageSpec `json:"storage"`
Ingress JaegerIngressSpec `json:"ingress"`
JaegerCommonSpec
Expand Down Expand Up @@ -83,6 +84,11 @@ type JaegerUISpec struct {
Options FreeForm `json:"options"`
}

// JaegerSamplingSpec defines the options to be used to configure the UI
type JaegerSamplingSpec struct {
Options FreeForm `json:"options"`
}

// JaegerIngressSpec defines the options to be used when deploying the query ingress
type JaegerIngressSpec struct {
Enabled *bool `json:"enabled"`
Expand Down
18 changes: 18 additions & 0 deletions pkg/apis/io/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

100 changes: 100 additions & 0 deletions pkg/config/sampling/sampling.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package sampling

import (
"fmt"

"github.com/sirupsen/logrus"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1"
)

const (
defaultSamplingStrategy = "{\"default_strategy\":{\"param\":1,\"type\":\"probabilistic\"}}"
)

// Config represents a sampling configmap
type Config struct {
jaeger *v1alpha1.Jaeger
}

// NewConfig builds a new Config struct based on the given spec
func NewConfig(jaeger *v1alpha1.Jaeger) *Config {
return &Config{jaeger: jaeger}
}

// Get returns a configmap specification for the current instance
func (u *Config) Get() *v1.ConfigMap {
var jsonObject []byte
var err error

// Check for empty map
if u.jaeger.Spec.Sampling.Options.IsEmpty() {
jsonObject = []byte(defaultSamplingStrategy)
} else {
jsonObject, err = u.jaeger.Spec.Sampling.Options.MarshalJSON()
}

if err != nil {
return nil
}

logrus.WithField("instance", u.jaeger.Name).Debug("Assembling the Sampling configmap")
trueVar := true

data := map[string]string{
"sampling": string(jsonObject),
}

return &v1.ConfigMap{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ConfigMap",
},
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-sampling-configuration", u.jaeger.Name),
Namespace: u.jaeger.Namespace,
OwnerReferences: []metav1.OwnerReference{
metav1.OwnerReference{
APIVersion: u.jaeger.APIVersion,
Kind: u.jaeger.Kind,
Name: u.jaeger.Name,
UID: u.jaeger.UID,
Controller: &trueVar,
},
},
},
Data: data,
}
}

// Update will modify the supplied common spec and options to include
// support for the Sampling configmap.
func Update(jaeger *v1alpha1.Jaeger, commonSpec *v1alpha1.JaegerCommonSpec, options *[]string) {

volume := v1.Volume{
Name: fmt.Sprintf("%s-sampling-configuration-volume", jaeger.Name),
VolumeSource: v1.VolumeSource{
ConfigMap: &v1.ConfigMapVolumeSource{
LocalObjectReference: v1.LocalObjectReference{
Name: fmt.Sprintf("%s-sampling-configuration", jaeger.Name),
},
Items: []v1.KeyToPath{
v1.KeyToPath{
Key: "sampling",
Path: "sampling.json",
},
},
},
},
}
volumeMount := v1.VolumeMount{
Name: fmt.Sprintf("%s-sampling-configuration-volume", jaeger.Name),
MountPath: "/etc/jaeger/sampling",
ReadOnly: true,
}
commonSpec.Volumes = append(commonSpec.Volumes, volume)
commonSpec.VolumeMounts = append(commonSpec.VolumeMounts, volumeMount)
*options = append(*options, "--sampling.strategies-file=/etc/jaeger/sampling/sampling.json")
}
81 changes: 81 additions & 0 deletions pkg/config/sampling/sampling_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package sampling

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1"
)

func TestNoSamplingConfig(t *testing.T) {
jaeger := v1alpha1.NewJaeger("TestNoSamplingConfig")

config := NewConfig(jaeger)
cm := config.Get()
assert.NotNil(t, cm)
assert.Equal(t, defaultSamplingStrategy, cm.Data["sampling"])
}

func TestWithEmptySamplingConfig(t *testing.T) {
uiconfig := v1alpha1.NewFreeForm(map[string]interface{}{})
jaeger := v1alpha1.NewJaeger("TestWithEmptySamplingConfig")
jaeger.Spec.UI.Options = uiconfig

config := NewConfig(jaeger)
cm := config.Get()
assert.NotNil(t, cm)
assert.Equal(t, defaultSamplingStrategy, cm.Data["sampling"])
}

func TestWithSamplingConfig(t *testing.T) {
samplingconfig := v1alpha1.NewFreeForm(map[string]interface{}{
"default_strategy": map[string]interface{}{
"type": "probabilistic",
"param": "20",
},
})
json := `{"default_strategy":{"param":"20","type":"probabilistic"}}`
jaeger := v1alpha1.NewJaeger("TestWithSamplingConfig")
jaeger.Spec.Sampling.Options = samplingconfig

config := NewConfig(jaeger)
cm := config.Get()
assert.Equal(t, json, cm.Data["sampling"])
}

func TestUpdateNoSamplingConfig(t *testing.T) {
jaeger := v1alpha1.NewJaeger("TestUpdateNoSamplingConfig")

commonSpec := v1alpha1.JaegerCommonSpec{}
options := []string{}

Update(jaeger, &commonSpec, &options)
assert.Len(t, commonSpec.Volumes, 1)
assert.Equal(t, "TestUpdateNoSamplingConfig-sampling-configuration-volume", commonSpec.Volumes[0].Name)
assert.Len(t, commonSpec.VolumeMounts, 1)
assert.Equal(t, "TestUpdateNoSamplingConfig-sampling-configuration-volume", commonSpec.VolumeMounts[0].Name)
assert.Len(t, options, 1)
assert.Equal(t, "--sampling.strategies-file=/etc/jaeger/sampling/sampling.json", options[0])
}

func TestUpdateWithSamplingConfig(t *testing.T) {
uiconfig := v1alpha1.NewFreeForm(map[string]interface{}{
"tracking": map[string]interface{}{
"gaID": "UA-000000-2",
},
})
jaeger := v1alpha1.NewJaeger("TestUpdateWithSamplingConfig")
jaeger.Spec.UI.Options = uiconfig

commonSpec := v1alpha1.JaegerCommonSpec{}
options := []string{}

Update(jaeger, &commonSpec, &options)
assert.Len(t, commonSpec.Volumes, 1)
assert.Equal(t, "TestUpdateWithSamplingConfig-sampling-configuration-volume", commonSpec.Volumes[0].Name)
assert.Len(t, commonSpec.VolumeMounts, 1)
assert.Equal(t, "TestUpdateWithSamplingConfig-sampling-configuration-volume", commonSpec.VolumeMounts[0].Name)
assert.Len(t, options, 1)
assert.Equal(t, "--sampling.strategies-file=/etc/jaeger/sampling/sampling.json", options[0])
}
2 changes: 2 additions & 0 deletions pkg/deployment/all-in-one.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"

"github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1"
"github.com/jaegertracing/jaeger-operator/pkg/config/sampling"
"github.com/jaegertracing/jaeger-operator/pkg/configmap"
"github.com/jaegertracing/jaeger-operator/pkg/service"
"github.com/jaegertracing/jaeger-operator/pkg/storage"
Expand Down Expand Up @@ -51,6 +52,7 @@ func (a *AllInOne) Get() *appsv1.Deployment {
a.jaeger.Spec.Storage.Options.Filter(storage.OptionsPrefix(a.jaeger.Spec.Storage.Type)))

configmap.Update(a.jaeger, commonSpec, &options)
sampling.Update(a.jaeger, commonSpec, &options)

var envFromSource []v1.EnvFromSource
if len(a.jaeger.Spec.Storage.SecretName) > 0 {
Expand Down
14 changes: 9 additions & 5 deletions pkg/deployment/all-in-one_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,9 @@ func TestAllInOneVolumeMountsWithVolumes(t *testing.T) {
jaeger.Spec.AllInOne.VolumeMounts = allInOneVolumeMounts
podSpec := NewAllInOne(jaeger).Get().Spec.Template.Spec

assert.Len(t, podSpec.Volumes, len(append(allInOneVolumes, globalVolumes...)))
assert.Len(t, podSpec.Containers[0].VolumeMounts, len(append(allInOneVolumeMounts, globalVolumeMounts...)))
// Additional 1 is sampling configmap
assert.Len(t, podSpec.Volumes, len(append(allInOneVolumes, globalVolumes...))+1)
assert.Len(t, podSpec.Containers[0].VolumeMounts, len(append(allInOneVolumeMounts, globalVolumeMounts...))+1)

// AllInOne is first while global is second
assert.Equal(t, "allInOneVolume", podSpec.Volumes[0].Name)
Expand Down Expand Up @@ -155,7 +156,8 @@ func TestAllInOneMountGlobalVolumes(t *testing.T) {
jaeger.Spec.AllInOne.VolumeMounts = allInOneVolumeMounts
podSpec := NewAllInOne(jaeger).Get().Spec.Template.Spec

assert.Len(t, podSpec.Containers[0].VolumeMounts, 1)
// Count includes the sampling configmap
assert.Len(t, podSpec.Containers[0].VolumeMounts, 2)
// allInOne volume is mounted
assert.Equal(t, podSpec.Containers[0].VolumeMounts[0].Name, "globalVolume")
}
Expand All @@ -182,7 +184,8 @@ func TestAllInOneVolumeMountsWithSameName(t *testing.T) {
jaeger.Spec.AllInOne.VolumeMounts = allInOneVolumeMounts
podSpec := NewAllInOne(jaeger).Get().Spec.Template.Spec

assert.Len(t, podSpec.Containers[0].VolumeMounts, 1)
// Count includes the sampling configmap
assert.Len(t, podSpec.Containers[0].VolumeMounts, 2)
// allInOne volume is mounted
assert.Equal(t, podSpec.Containers[0].VolumeMounts[0].ReadOnly, false)
}
Expand All @@ -209,7 +212,8 @@ func TestAllInOneVolumeWithSameName(t *testing.T) {
jaeger.Spec.AllInOne.Volumes = allInOneVolumes
podSpec := NewAllInOne(jaeger).Get().Spec.Template.Spec

assert.Len(t, podSpec.Volumes, 1)
// Count includes the sampling configmap
assert.Len(t, podSpec.Volumes, 2)
// allInOne volume is mounted
assert.Equal(t, podSpec.Volumes[0].VolumeSource.HostPath.Path, "/data2")
}
Expand Down
9 changes: 7 additions & 2 deletions pkg/deployment/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"

"github.com/jaegertracing/jaeger-operator/pkg/apis/io/v1alpha1"
"github.com/jaegertracing/jaeger-operator/pkg/config/sampling"
"github.com/jaegertracing/jaeger-operator/pkg/service"
"github.com/jaegertracing/jaeger-operator/pkg/storage"
"github.com/jaegertracing/jaeger-operator/pkg/util"
Expand Down Expand Up @@ -63,6 +64,11 @@ func (c *Collector) Get() *appsv1.Deployment {
})
}

options := allArgs(c.jaeger.Spec.Collector.Options,
c.jaeger.Spec.Storage.Options.Filter(storage.OptionsPrefix(c.jaeger.Spec.Storage.Type)))

sampling.Update(c.jaeger, commonSpec, &options)

return &appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
APIVersion: "apps/v1",
Expand Down Expand Up @@ -95,8 +101,7 @@ func (c *Collector) Get() *appsv1.Deployment {
Containers: []v1.Container{{
Image: c.jaeger.Spec.Collector.Image,
Name: "jaeger-collector",
Args: allArgs(c.jaeger.Spec.Collector.Options,
c.jaeger.Spec.Storage.Options.Filter(storage.OptionsPrefix(c.jaeger.Spec.Storage.Type))),
Args: options,
Env: []v1.EnvVar{
v1.EnvVar{
Name: "SPAN_STORAGE_TYPE",
Expand Down
Loading

0 comments on commit 9c9f809

Please sign in to comment.