diff --git a/cmd/opentelemetry-collector/app/defaults/default_config.go b/cmd/opentelemetry-collector/app/defaults/default_config.go index f370ab48bc3..d0bf771438f 100644 --- a/cmd/opentelemetry-collector/app/defaults/default_config.go +++ b/cmd/opentelemetry-collector/app/defaults/default_config.go @@ -25,6 +25,7 @@ import ( "go.opentelemetry.io/collector/receiver/jaegerreceiver" "go.opentelemetry.io/collector/receiver/zipkinreceiver" + "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/badger" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/cassandra" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/elasticsearch" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/grpcplugin" @@ -145,6 +146,9 @@ func createExporters(component ComponentType, storageTypes string, factories con case "memory": mem := factories.Exporters[memory.TypeStr].CreateDefaultConfig() exporters[memory.TypeStr] = mem + case "badger": + badg := factories.Exporters[badger.TypeStr].CreateDefaultConfig() + exporters[badger.TypeStr] = badg case "cassandra": cass := factories.Exporters[cassandra.TypeStr].CreateDefaultConfig() exporters[cassandra.TypeStr] = cass diff --git a/cmd/opentelemetry-collector/app/defaults/defaults.go b/cmd/opentelemetry-collector/app/defaults/defaults.go index 6de842bc081..1950adaac6f 100644 --- a/cmd/opentelemetry-collector/app/defaults/defaults.go +++ b/cmd/opentelemetry-collector/app/defaults/defaults.go @@ -27,6 +27,7 @@ import ( "go.opentelemetry.io/collector/service/defaultcomponents" ingesterApp "github.com/jaegertracing/jaeger/cmd/ingester/app" + "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/badger" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/cassandra" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/elasticsearch" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/grpcplugin" @@ -37,6 +38,7 @@ import ( "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/receiver/jaegerreceiver" kafkaRec "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/receiver/kafka" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/receiver/zipkinreceiver" + storageBadger "github.com/jaegertracing/jaeger/plugin/storage/badger" storageCassandra "github.com/jaegertracing/jaeger/plugin/storage/cassandra" storageEs "github.com/jaegertracing/jaeger/plugin/storage/es" storageGrpc "github.com/jaegertracing/jaeger/plugin/storage/grpc" @@ -70,6 +72,11 @@ func Components(v *viper.Viper) config.Factories { return opts }} memoryExp := memory.NewFactory(v) + badgerExp := badger.NewFactory(func() *storageBadger.Options { + opts := badger.DefaultOptions() + opts.InitFromViper(v) + return opts + }) kafkaRec := &kafkaRec.Factory{OptionsFactory: func() *ingesterApp.Options { opts := kafkaRec.DefaultOptions() opts.InitFromViper(v) @@ -82,6 +89,7 @@ func Components(v *viper.Viper) config.Factories { factories.Exporters[esExp.Type()] = esExp factories.Exporters[grpcExp.Type()] = grpcExp factories.Exporters[memoryExp.Type()] = memoryExp + factories.Exporters[badgerExp.Type()] = badgerExp factories.Receivers[kafkaRec.Type()] = kafkaRec jaegerRec := factories.Receivers["jaeger"].(*otelJaegerReceiver.Factory) diff --git a/cmd/opentelemetry-collector/app/defaults/defaults_test.go b/cmd/opentelemetry-collector/app/defaults/defaults_test.go index 65d1cce7d40..00d48797f63 100644 --- a/cmd/opentelemetry-collector/app/defaults/defaults_test.go +++ b/cmd/opentelemetry-collector/app/defaults/defaults_test.go @@ -19,6 +19,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/badger" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/cassandra" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/elasticsearch" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/grpcplugin" @@ -43,6 +44,7 @@ func TestComponents(t *testing.T) { assert.IsType(t, &elasticsearch.Factory{}, factories.Exporters[elasticsearch.TypeStr]) assert.IsType(t, &grpcplugin.Factory{}, factories.Exporters[grpcplugin.TypeStr]) assert.IsType(t, &memory.Factory{}, factories.Exporters[memory.TypeStr]) + assert.IsType(t, &badger.Factory{}, factories.Exporters[badger.TypeStr]) assert.IsType(t, &jaegerreceiver.Factory{}, factories.Receivers["jaeger"]) assert.IsType(t, &jaegerexporter.Factory{}, factories.Exporters["jaeger"]) assert.IsType(t, &kafkaRec.Factory{}, factories.Receivers[kafkaRec.TypeStr]) diff --git a/cmd/opentelemetry-collector/app/exporter/badger/config.go b/cmd/opentelemetry-collector/app/exporter/badger/config.go new file mode 100644 index 00000000000..45b584f7c3d --- /dev/null +++ b/cmd/opentelemetry-collector/app/exporter/badger/config.go @@ -0,0 +1,27 @@ +// Copyright (c) 2020 The Jaeger 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 badger + +import ( + "go.opentelemetry.io/collector/config/configmodels" + + "github.com/jaegertracing/jaeger/plugin/storage/badger" +) + +// Config holds configuration of Jaeger Badger exporter/storage. +type Config struct { + badger.Options `mapstructure:",squash"` + configmodels.ExporterSettings `mapstructure:",squash"` +} diff --git a/cmd/opentelemetry-collector/app/exporter/badger/config_test.go b/cmd/opentelemetry-collector/app/exporter/badger/config_test.go new file mode 100644 index 00000000000..5d63775219a --- /dev/null +++ b/cmd/opentelemetry-collector/app/exporter/badger/config_test.go @@ -0,0 +1,77 @@ +// Copyright (c) 2020 The Jaeger 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 badger + +import ( + "path" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/config" + + "github.com/jaegertracing/jaeger/cmd/flags" + jConfig "github.com/jaegertracing/jaeger/pkg/config" + "github.com/jaegertracing/jaeger/plugin/storage/badger" +) + +func TestDefaultConfig(t *testing.T) { + factory := NewFactory(func() *badger.Options { + opts := DefaultOptions() + v, _ := jConfig.Viperize(opts.AddFlags) + opts.InitFromViper(v) + return opts + }) + defaultCfg := factory.CreateDefaultConfig().(*Config) + opts := defaultCfg.Options.GetPrimary() + assert.Contains(t, opts.KeyDirectory, "/data/keys") + assert.Contains(t, opts.ValueDirectory, "/data/values") + assert.Equal(t, true, opts.Ephemeral) + assert.Equal(t, false, opts.ReadOnly) + assert.Equal(t, false, opts.SyncWrites) + assert.Equal(t, false, opts.Truncate) + assert.Equal(t, time.Second*10, opts.MetricsUpdateInterval) + assert.Equal(t, time.Minute*5, opts.MaintenanceInterval) + assert.Equal(t, time.Hour*72, opts.SpanStoreTTL) +} + +func TestLoadConfigAndFlags(t *testing.T) { + factories, err := config.ExampleComponents() + require.NoError(t, err) + + v, c := jConfig.Viperize(DefaultOptions().AddFlags) + err = c.ParseFlags([]string{"--badger.directory-key=bar"}) + require.NoError(t, err) + + err = flags.TryLoadConfigFile(v) + require.NoError(t, err) + + factory := NewFactory(func() *badger.Options { + opts := DefaultOptions() + opts.InitFromViper(v) + require.Equal(t, "bar", opts.GetPrimary().KeyDirectory) + return opts + }) + + factories.Exporters[TypeStr] = factory + colConfig, err := config.LoadConfigFile(t, path.Join(".", "testdata", "config.yaml"), factories) + require.NoError(t, err) + require.NotNil(t, colConfig) + + cfg := colConfig.Exporters[TypeStr].(*Config) + assert.Equal(t, TypeStr, cfg.Name()) + assert.Equal(t, "key", cfg.GetPrimary().KeyDirectory) +} diff --git a/cmd/opentelemetry-collector/app/exporter/badger/factory.go b/cmd/opentelemetry-collector/app/exporter/badger/factory.go new file mode 100644 index 00000000000..44a255e6f50 --- /dev/null +++ b/cmd/opentelemetry-collector/app/exporter/badger/factory.go @@ -0,0 +1,131 @@ +// Copyright (c) 2020 The Jaeger 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 badger + +import ( + "context" + "fmt" + "sync" + + "github.com/uber/jaeger-lib/metrics" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/configerror" + "go.opentelemetry.io/collector/config/configmodels" + + "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter" + "github.com/jaegertracing/jaeger/plugin/storage/badger" + "github.com/jaegertracing/jaeger/storage" +) + +const ( + // TypeStr defines type of the Badger exporter. + TypeStr = "jaeger_badger" +) + +// OptionsFactory returns initialized badger.Options structure. +type OptionsFactory func() *badger.Options + +// DefaultOptions creates Badger options supported by this exporter. +func DefaultOptions() *badger.Options { + return badger.NewOptions("badger") +} + +// Factory is the factory for Jaeger Cassandra exporter. +type Factory struct { + mutex *sync.Mutex + optionsFactory OptionsFactory +} + +// NewFactory creates new Factory instance. +func NewFactory(optionsFactory OptionsFactory) *Factory { + return &Factory{ + optionsFactory: optionsFactory, + mutex: &sync.Mutex{}, + } +} + +var _ component.ExporterFactory = (*Factory)(nil) + +// singleton instance of the factory +// the badger exporter factory always returns this instance +// the singleton instance is shared between OTEL collector and query service +var instance storage.Factory + +// GetFactory returns singleton instance of the storage factory. +func GetFactory() storage.Factory { + return instance +} + +// Type gets the type of exporter. +func (f Factory) Type() configmodels.Type { + return TypeStr +} + +// CreateDefaultConfig returns default configuration of Factory. +// This function implements OTEL component.ExporterFactoryBase interface. +func (f Factory) CreateDefaultConfig() configmodels.Exporter { + opts := f.optionsFactory() + return &Config{ + Options: *opts, + ExporterSettings: configmodels.ExporterSettings{ + TypeVal: TypeStr, + NameVal: TypeStr, + }, + } +} + +// CreateTraceExporter creates Jaeger Cassandra trace exporter. +// This function implements OTEL component.ExporterFactory interface. +func (f Factory) CreateTraceExporter( + _ context.Context, + params component.ExporterCreateParams, + cfg configmodels.Exporter, +) (component.TraceExporter, error) { + factory, err := f.createStorageFactory(params, cfg) + if err != nil { + return nil, err + } + return exporter.NewSpanWriterExporter(cfg, factory) +} + +// CreateMetricsExporter is not implemented. +// This function implements OTEL component.ExporterFactory interface. +func (f Factory) CreateMetricsExporter( + _ context.Context, + _ component.ExporterCreateParams, + _ configmodels.Exporter, +) (component.MetricsExporter, error) { + return nil, configerror.ErrDataTypeIsNotSupported +} + +func (f Factory) createStorageFactory(params component.ExporterCreateParams, cfg configmodels.Exporter) (storage.Factory, error) { + config, ok := cfg.(*Config) + if !ok { + return nil, fmt.Errorf("could not cast configuration to %s", TypeStr) + } + f.mutex.Lock() + if instance != nil { + return instance, nil + } + factory := badger.NewFactory() + factory.InitFromOptions(config.Options) + err := factory.Initialize(metrics.NullFactory, params.Logger) + if err != nil { + return nil, err + } + instance = factory + f.mutex.Unlock() + return factory, nil +} diff --git a/cmd/opentelemetry-collector/app/exporter/badger/factory_test.go b/cmd/opentelemetry-collector/app/exporter/badger/factory_test.go new file mode 100644 index 00000000000..299e100eed4 --- /dev/null +++ b/cmd/opentelemetry-collector/app/exporter/badger/factory_test.go @@ -0,0 +1,69 @@ +// Copyright (c) 2020 The Jaeger 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 badger + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/configcheck" + "go.opentelemetry.io/collector/config/configerror" + "go.opentelemetry.io/collector/config/configmodels" + "go.uber.org/zap" + + jConfig "github.com/jaegertracing/jaeger/pkg/config" + "github.com/jaegertracing/jaeger/plugin/storage/badger" +) + +func TestCreateTraceExporter(t *testing.T) { + v, _ := jConfig.Viperize(DefaultOptions().AddFlags) + opts := DefaultOptions() + opts.InitFromViper(v) + factory := NewFactory(func() *badger.Options { + return opts + }) + exporter, err := factory.CreateTraceExporter(context.Background(), component.ExporterCreateParams{Logger: zap.NewNop()}, factory.CreateDefaultConfig()) + require.NoError(t, err) + assert.NotNil(t, exporter) +} + +func TestCreateTraceExporter_NilConfig(t *testing.T) { + factory := Factory{} + exporter, err := factory.CreateTraceExporter(context.Background(), component.ExporterCreateParams{}, nil) + require.Nil(t, exporter) + assert.Contains(t, err.Error(), "could not cast configuration to jaeger_badger") +} + +func TestCreateDefaultConfig(t *testing.T) { + factory := NewFactory(DefaultOptions) + cfg := factory.CreateDefaultConfig() + assert.NotNil(t, cfg, "failed to create default config") + assert.NoError(t, configcheck.ValidateConfig(cfg)) +} + +func TestCreateMetricsExporter(t *testing.T) { + f := NewFactory(DefaultOptions) + mReceiver, err := f.CreateMetricsExporter(context.Background(), component.ExporterCreateParams{}, f.CreateDefaultConfig()) + assert.Equal(t, err, configerror.ErrDataTypeIsNotSupported) + assert.Nil(t, mReceiver) +} + +func TestType(t *testing.T) { + factory := Factory{} + assert.Equal(t, configmodels.Type(TypeStr), factory.Type()) +} diff --git a/cmd/opentelemetry-collector/app/exporter/badger/testdata/config.yaml b/cmd/opentelemetry-collector/app/exporter/badger/testdata/config.yaml new file mode 100644 index 00000000000..74a821a5266 --- /dev/null +++ b/cmd/opentelemetry-collector/app/exporter/badger/testdata/config.yaml @@ -0,0 +1,17 @@ +receivers: + examplereceiver: + +processors: + exampleprocessor: + +exporters: + jaeger_badger: + ephemeral: false + directory_key: key + +service: + pipelines: + traces: + receivers: [examplereceiver] + processors: [exampleprocessor] + exporters: [jaeger_badger] diff --git a/cmd/opentelemetry-collector/app/exporter/memory/config_test.go b/cmd/opentelemetry-collector/app/exporter/memory/config_test.go index 41df34f9760..8fb968ee1db 100644 --- a/cmd/opentelemetry-collector/app/exporter/memory/config_test.go +++ b/cmd/opentelemetry-collector/app/exporter/memory/config_test.go @@ -28,7 +28,7 @@ import ( func TestDefaultConfig(t *testing.T) { v, _ := jConfig.Viperize(AddFlags) - factory := &Factory{Viper: v} + factory := NewFactory(v) defaultCfg := factory.CreateDefaultConfig().(*Config) assert.Equal(t, 0, defaultCfg.Configuration.MaxTraces) } @@ -44,9 +44,7 @@ func TestLoadConfigAndFlags(t *testing.T) { err = flags.TryLoadConfigFile(v) require.NoError(t, err) - factory := &Factory{ - Viper: v, - } + factory := NewFactory(v) assert.Equal(t, 15, factory.CreateDefaultConfig().(*Config).Configuration.MaxTraces) factories.Exporters[TypeStr] = factory diff --git a/cmd/opentelemetry-collector/app/exporter/memory/factory.go b/cmd/opentelemetry-collector/app/exporter/memory/factory.go index 32877e50b53..e5b54d73c7c 100644 --- a/cmd/opentelemetry-collector/app/exporter/memory/factory.go +++ b/cmd/opentelemetry-collector/app/exporter/memory/factory.go @@ -35,14 +35,14 @@ const TypeStr = "jaeger_memory" // Factory is the factory for Jaeger in-memory exporter. type Factory struct { - Viper *viper.Viper + viper *viper.Viper mutex *sync.Mutex } // NewFactory creates Factory. func NewFactory(v *viper.Viper) *Factory { return &Factory{ - Viper: v, + viper: v, mutex: &sync.Mutex{}, } } @@ -59,27 +59,6 @@ func GetFactory() storage.Factory { return instance } -// CreateStorageFactory creates Jaeger storage factory. -func (f Factory) CreateStorageFactory(params component.ExporterCreateParams, cfg configmodels.Exporter) (storage.Factory, error) { - config, ok := cfg.(*Config) - if !ok { - return nil, fmt.Errorf("could not cast configuration to %s", TypeStr) - } - f.mutex.Lock() - if instance != nil { - return instance, nil - } - factory := memory.NewFactory() - factory.InitFromOptions(config.Options) - err := factory.Initialize(metrics.NullFactory, params.Logger) - if err != nil { - return nil, err - } - instance = factory - f.mutex.Unlock() - return factory, nil -} - // Type gets the type of exporter. func (f Factory) Type() configmodels.Type { return TypeStr @@ -89,7 +68,7 @@ func (f Factory) Type() configmodels.Type { // This function implements OTEL component.ExporterFactoryBase interface. func (f Factory) CreateDefaultConfig() configmodels.Exporter { opts := memory.Options{} - opts.InitFromViper(f.Viper) + opts.InitFromViper(f.viper) return &Config{ Options: opts, ExporterSettings: configmodels.ExporterSettings{ @@ -106,7 +85,7 @@ func (f Factory) CreateTraceExporter( params component.ExporterCreateParams, cfg configmodels.Exporter, ) (component.TraceExporter, error) { - factory, err := f.CreateStorageFactory(params, cfg) + factory, err := f.createStorageFactory(params, cfg) if err != nil { return nil, err } @@ -122,3 +101,23 @@ func (Factory) CreateMetricsExporter( ) (component.MetricsExporter, error) { return nil, configerror.ErrDataTypeIsNotSupported } + +func (f Factory) createStorageFactory(params component.ExporterCreateParams, cfg configmodels.Exporter) (storage.Factory, error) { + config, ok := cfg.(*Config) + if !ok { + return nil, fmt.Errorf("could not cast configuration to %s", TypeStr) + } + f.mutex.Lock() + if instance != nil { + return instance, nil + } + factory := memory.NewFactory() + factory.InitFromOptions(config.Options) + err := factory.Initialize(metrics.NullFactory, params.Logger) + if err != nil { + return nil, err + } + instance = factory + f.mutex.Unlock() + return factory, nil +} diff --git a/cmd/opentelemetry-collector/app/flags.go b/cmd/opentelemetry-collector/app/flags.go index 6a4c03e89ca..5d541cbbb25 100644 --- a/cmd/opentelemetry-collector/app/flags.go +++ b/cmd/opentelemetry-collector/app/flags.go @@ -20,6 +20,7 @@ import ( "strings" jConfigFile "github.com/jaegertracing/jaeger/cmd/flags" + "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/badger" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/cassandra" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/elasticsearch" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/grpcplugin" @@ -54,6 +55,8 @@ func AddStorageFlags(storage string, enableArchive bool) (func(*flag.FlagSet), e if enableArchive { flagFn = append(flagFn, cassandra2.NewOptions("cassandra-archive").AddFlags) } + case "badger": + flagFn = append(flagFn, badger.DefaultOptions().AddFlags) case "elasticsearch": flagFn = append(flagFn, elasticsearch.DefaultOptions().AddFlags) if enableArchive { diff --git a/cmd/opentelemetry-collector/cmd/all-in-one/main.go b/cmd/opentelemetry-collector/cmd/all-in-one/main.go index 216ac7293e3..991c2e88040 100644 --- a/cmd/opentelemetry-collector/cmd/all-in-one/main.go +++ b/cmd/opentelemetry-collector/cmd/all-in-one/main.go @@ -37,6 +37,7 @@ import ( jflags "github.com/jaegertracing/jaeger/cmd/flags" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/defaults" + "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/badger" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/cassandra" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/elasticsearch" "github.com/jaegertracing/jaeger/cmd/opentelemetry-collector/app/exporter/grpcplugin" @@ -146,14 +147,17 @@ func main() { queryServer, tracerCloser, err := startQuery(v, svc.GetLogger(), exp) if err != nil { svc.ReportFatalError(err) - } else { - for state := range svc.GetStateChannel() { - if state == service.Closing { + } + for state := range svc.GetStateChannel() { + if state == service.Closing { + if queryServer != nil { queryServer.Close() + } + if tracerCloser != nil { tracerCloser.Close() - } else if state == service.Closed { - break } + } else if state == service.Closed { + break } } } @@ -232,6 +236,8 @@ func getFactory(exporter configmodels.Exporter, v *viper.Viper, logger *zap.Logg return f, nil case "jaeger_memory": return memory.GetFactory(), nil + case "jaeger_badger": + return badger.GetFactory(), nil default: return nil, fmt.Errorf("storage type %s cannot be used with all-in-one", exporter.Name()) } diff --git a/plugin/storage/badger/factory.go b/plugin/storage/badger/factory.go index 5572ffec72b..e6fafef7513 100644 --- a/plugin/storage/badger/factory.go +++ b/plugin/storage/badger/factory.go @@ -85,6 +85,11 @@ func (f *Factory) InitFromViper(v *viper.Viper) { f.Options.InitFromViper(v) } +// InitFromOptions initializes Factory from supplied options +func (f *Factory) InitFromOptions(opts Options) { + f.Options = &opts +} + // Initialize implements storage.Factory func (f *Factory) Initialize(metricsFactory metrics.Factory, logger *zap.Logger) error { f.logger = logger @@ -92,7 +97,7 @@ func (f *Factory) Initialize(metricsFactory metrics.Factory, logger *zap.Logger) opts := badger.DefaultOptions opts.TableLoadingMode = options.MemoryMap - if f.Options.primary.Ephemeral { + if f.Options.Primary.Ephemeral { opts.SyncWrites = false // Error from TempDir is ignored to satisfy Codecov dir, _ := ioutil.TempDir("", "badger") @@ -100,20 +105,20 @@ func (f *Factory) Initialize(metricsFactory metrics.Factory, logger *zap.Logger) opts.Dir = f.tmpDir opts.ValueDir = f.tmpDir - f.Options.primary.KeyDirectory = f.tmpDir - f.Options.primary.ValueDirectory = f.tmpDir + f.Options.Primary.KeyDirectory = f.tmpDir + f.Options.Primary.ValueDirectory = f.tmpDir } else { // Errors are ignored as they're caught in the Open call - initializeDir(f.Options.primary.KeyDirectory) - initializeDir(f.Options.primary.ValueDirectory) + initializeDir(f.Options.Primary.KeyDirectory) + initializeDir(f.Options.Primary.ValueDirectory) - opts.SyncWrites = f.Options.primary.SyncWrites - opts.Dir = f.Options.primary.KeyDirectory - opts.ValueDir = f.Options.primary.ValueDirectory + opts.SyncWrites = f.Options.Primary.SyncWrites + opts.Dir = f.Options.Primary.KeyDirectory + opts.ValueDir = f.Options.Primary.ValueDirectory // These options make no sense with ephemeral data - opts.Truncate = f.Options.primary.Truncate - opts.ReadOnly = f.Options.primary.ReadOnly + opts.Truncate = f.Options.Primary.Truncate + opts.ReadOnly = f.Options.Primary.ReadOnly } store, err := badger.Open(opts) @@ -122,7 +127,7 @@ func (f *Factory) Initialize(metricsFactory metrics.Factory, logger *zap.Logger) } f.store = store - f.cache = badgerStore.NewCacheStore(f.store, f.Options.primary.SpanStoreTTL, true) + f.cache = badgerStore.NewCacheStore(f.store, f.Options.Primary.SpanStoreTTL, true) f.metrics.ValueLogSpaceAvailable = metricsFactory.Gauge(metrics.Options{Name: valueLogSpaceAvailableName}) f.metrics.KeyLogSpaceAvailable = metricsFactory.Gauge(metrics.Options{Name: keyLogSpaceAvailableName}) @@ -153,7 +158,7 @@ func (f *Factory) CreateSpanReader() (spanstore.Reader, error) { // CreateSpanWriter implements storage.Factory func (f *Factory) CreateSpanWriter() (spanstore.Writer, error) { - return badgerStore.NewSpanWriter(f.store, f.cache, f.Options.primary.SpanStoreTTL, f), nil + return badgerStore.NewSpanWriter(f.store, f.cache, f.Options.Primary.SpanStoreTTL, f), nil } // CreateDependencyReader implements storage.Factory @@ -168,7 +173,7 @@ func (f *Factory) Close() error { err := f.store.Close() // Remove tmp files if this was ephemeral storage - if f.Options.primary.Ephemeral { + if f.Options.Primary.Ephemeral { errSecondary := os.RemoveAll(f.tmpDir) if err == nil { err = errSecondary @@ -180,7 +185,7 @@ func (f *Factory) Close() error { // Maintenance starts a background maintenance job for the badger K/V store, such as ValueLogGC func (f *Factory) maintenance() { - maintenanceTicker := time.NewTicker(f.Options.primary.MaintenanceInterval) + maintenanceTicker := time.NewTicker(f.Options.Primary.MaintenanceInterval) defer maintenanceTicker.Stop() for { select { @@ -206,7 +211,7 @@ func (f *Factory) maintenance() { } func (f *Factory) metricsCopier() { - metricsTicker := time.NewTicker(f.Options.primary.MetricsUpdateInterval) + metricsTicker := time.NewTicker(f.Options.Primary.MetricsUpdateInterval) defer metricsTicker.Stop() for { select { diff --git a/plugin/storage/badger/factory_test.go b/plugin/storage/badger/factory_test.go index 1917d017624..5506572efa3 100644 --- a/plugin/storage/badger/factory_test.go +++ b/plugin/storage/badger/factory_test.go @@ -187,3 +187,10 @@ func TestBadgerMetrics(t *testing.T) { err := f.Close() assert.NoError(t, err) } + +func TestInitFromOptions(t *testing.T) { + f := NewFactory() + opts := Options{} + f.InitFromOptions(opts) + assert.Equal(t, &opts, f.Options) +} diff --git a/plugin/storage/badger/options.go b/plugin/storage/badger/options.go index 4d9d5395304..e6c4562c50f 100644 --- a/plugin/storage/badger/options.go +++ b/plugin/storage/badger/options.go @@ -25,22 +25,23 @@ import ( // Options store storage plugin related configs type Options struct { - primary *NamespaceConfig + Primary NamespaceConfig `mapstructure:",squash"` // This storage plugin does not support additional namespaces } // NamespaceConfig is badger's internal configuration data type NamespaceConfig struct { - namespace string - SpanStoreTTL time.Duration - ValueDirectory string - KeyDirectory string - Ephemeral bool // Setting this to true will ignore ValueDirectory and KeyDirectory - SyncWrites bool - MaintenanceInterval time.Duration - MetricsUpdateInterval time.Duration - Truncate bool - ReadOnly bool + namespace string + SpanStoreTTL time.Duration `mapstructure:"span_store_ttl"` + ValueDirectory string `mapstructure:"directory_value"` + KeyDirectory string `mapstructure:"directory_key"` + // Setting this to true will ignore ValueDirectory and KeyDirectory + Ephemeral bool `mapstructure:"ephemeral"` + SyncWrites bool `mapstructure:"consistency"` + MaintenanceInterval time.Duration `mapstructure:"maintenance_interval"` + MetricsUpdateInterval time.Duration `mapstructure:"metrics_update_interval"` + Truncate bool `mapstructure:"truncate"` + ReadOnly bool `mapstructure:"read_only"` } const ( @@ -70,7 +71,7 @@ func NewOptions(primaryNamespace string, otherNamespaces ...string) *Options { defaultBadgerDataDir := getCurrentExecutableDir() options := &Options{ - primary: &NamespaceConfig{ + Primary: NamespaceConfig{ namespace: primaryNamespace, SpanStoreTTL: defaultTTL, SyncWrites: false, // Performance over durability @@ -93,10 +94,10 @@ func getCurrentExecutableDir() string { // AddFlags adds flags for Options func (opt *Options) AddFlags(flagSet *flag.FlagSet) { - addFlags(flagSet, opt.primary) + addFlags(flagSet, opt.Primary) } -func addFlags(flagSet *flag.FlagSet, nsConfig *NamespaceConfig) { +func addFlags(flagSet *flag.FlagSet, nsConfig NamespaceConfig) { flagSet.Bool( nsConfig.namespace+suffixEphemeral, nsConfig.Ephemeral, @@ -146,7 +147,7 @@ func addFlags(flagSet *flag.FlagSet, nsConfig *NamespaceConfig) { // InitFromViper initializes Options with properties from viper func (opt *Options) InitFromViper(v *viper.Viper) { - initFromViper(opt.primary, v) + initFromViper(&opt.Primary, v) } func initFromViper(cfg *NamespaceConfig, v *viper.Viper) { @@ -162,6 +163,6 @@ func initFromViper(cfg *NamespaceConfig, v *viper.Viper) { } // GetPrimary returns the primary namespace configuration -func (opt *Options) GetPrimary() *NamespaceConfig { - return opt.primary +func (opt *Options) GetPrimary() NamespaceConfig { + return opt.Primary }