diff --git a/cmd/agent/app/flags.go b/cmd/agent/app/flags.go index 23ff98ddbc0..abe95408933 100644 --- a/cmd/agent/app/flags.go +++ b/cmd/agent/app/flags.go @@ -66,7 +66,7 @@ func AddFlags(flags *flag.FlagSet) { } // InitFromViper initializes Builder with properties retrieved from Viper. -func (b *Builder) InitFromViper(v *viper.Viper) { +func (b *Builder) InitFromViper(v *viper.Viper) *Builder { b.Metrics.InitFromViper(v) for _, processor := range defaultProcessors { @@ -84,4 +84,5 @@ func (b *Builder) InitFromViper(v *viper.Viper) { } b.HTTPServer.HostPort = v.GetString(httpServerHostPort) b.DiscoveryMinPeers = v.GetInt(discoveryMinPeers) + return b } diff --git a/cmd/builder/builder_options.go b/cmd/builder/builder_options.go index cc0c1f0bad3..faf0a43b93c 100644 --- a/cmd/builder/builder_options.go +++ b/cmd/builder/builder_options.go @@ -17,24 +17,16 @@ package builder import ( "github.com/uber/jaeger-lib/metrics" "go.uber.org/zap" - - cascfg "github.com/jaegertracing/jaeger/pkg/cassandra/config" - escfg "github.com/jaegertracing/jaeger/pkg/es/config" - "github.com/jaegertracing/jaeger/storage/spanstore/memory" ) +// TODO combine with SharedFlags + // BasicOptions is a set of basic building blocks for most Jaeger executables type BasicOptions struct { // Logger is a generic logger used by most executables Logger *zap.Logger // MetricsFactory is the basic metrics factory used by most executables MetricsFactory metrics.Factory - // MemoryStore is the memory store (as reader and writer) that will be used if required - MemoryStore *memory.Store - // CassandraSessionBuilder is the cassandra session builder - CassandraSessionBuilder cascfg.SessionBuilder - // ElasticClientBuilder is the elasticsearch client builder - ElasticClientBuilder escfg.ClientBuilder } // Option is a function that sets some option on StorageBuilder. @@ -57,27 +49,6 @@ func (BasicOptions) MetricsFactoryOption(metricsFactory metrics.Factory) Option } } -// CassandraSessionOption creates an Option that adds Cassandra session builder. -func (BasicOptions) CassandraSessionOption(sessionBuilder cascfg.SessionBuilder) Option { - return func(b *BasicOptions) { - b.CassandraSessionBuilder = sessionBuilder - } -} - -// ElasticClientOption creates an Option that adds ElasticSearch client builder. -func (BasicOptions) ElasticClientOption(clientBuilder escfg.ClientBuilder) Option { - return func(b *BasicOptions) { - b.ElasticClientBuilder = clientBuilder - } -} - -// MemoryStoreOption creates an Option that adds a memory store -func (BasicOptions) MemoryStoreOption(memoryStore *memory.Store) Option { - return func(b *BasicOptions) { - b.MemoryStore = memoryStore - } -} - // ApplyOptions takes a set of options and creates a populated BasicOptions struct func ApplyOptions(opts ...Option) BasicOptions { o := BasicOptions{} diff --git a/cmd/builder/builder_options_test.go b/cmd/builder/builder_options_test.go index cf23c54bf33..b9294033e83 100644 --- a/cmd/builder/builder_options_test.go +++ b/cmd/builder/builder_options_test.go @@ -20,24 +20,14 @@ import ( "github.com/stretchr/testify/assert" "go.uber.org/zap" - cascfg "github.com/jaegertracing/jaeger/pkg/cassandra/config" - escfg "github.com/jaegertracing/jaeger/pkg/es/config" - "github.com/jaegertracing/jaeger/storage/spanstore/memory" "github.com/uber/jaeger-lib/metrics" ) func TestApplyOptions(t *testing.T) { opts := ApplyOptions( - Options.CassandraSessionOption(&cascfg.Configuration{}), Options.LoggerOption(zap.NewNop()), Options.MetricsFactoryOption(metrics.NullFactory), - Options.MemoryStoreOption(memory.NewStore()), - Options.ElasticClientOption(&escfg.Configuration{ - Servers: []string{"127.0.0.1"}, - }), ) - assert.NotNil(t, opts.CassandraSessionBuilder) - assert.NotNil(t, opts.ElasticClientBuilder) assert.NotNil(t, opts.Logger) assert.NotNil(t, opts.MetricsFactory) } diff --git a/cmd/collector/app/builder/builder_flags.go b/cmd/collector/app/builder/builder_flags.go index 5be225589bd..3475cffeb4a 100644 --- a/cmd/collector/app/builder/builder_flags.go +++ b/cmd/collector/app/builder/builder_flags.go @@ -16,7 +16,6 @@ package builder import ( "flag" - "time" "github.com/spf13/viper" @@ -39,8 +38,6 @@ type CollectorOptions struct { QueueSize int // NumWorkers is the number of internal workers in a collector NumWorkers int - // WriteCacheTTL denotes how often to check and re-write a service or operation name - WriteCacheTTL time.Duration // CollectorPort is the port that the collector service listens in on for tchannel requests CollectorPort int // CollectorHTTPPort is the port that the collector service listens in on for http requests @@ -55,7 +52,6 @@ type CollectorOptions struct { func AddFlags(flags *flag.FlagSet) { flags.Int(collectorQueueSize, app.DefaultQueueSize, "The queue size of the collector") flags.Int(collectorNumWorkers, app.DefaultNumWorkers, "The number of workers pulling items from the queue") - flags.Duration(collectorWriteCacheTTL, time.Hour*12, "The duration to wait before rewriting an existing service or operation name") flags.Int(collectorPort, 14267, "The tchannel port for the collector service") flags.Int(collectorHTTPPort, 14268, "The http port for the collector service") flags.Int(collectorZipkinHTTPort, 0, "The http port for the Zipkin collector service e.g. 9411") @@ -66,7 +62,6 @@ func AddFlags(flags *flag.FlagSet) { func (cOpts *CollectorOptions) InitFromViper(v *viper.Viper) *CollectorOptions { cOpts.QueueSize = v.GetInt(collectorQueueSize) cOpts.NumWorkers = v.GetInt(collectorNumWorkers) - cOpts.WriteCacheTTL = v.GetDuration(collectorWriteCacheTTL) cOpts.CollectorPort = v.GetInt(collectorPort) cOpts.CollectorHTTPPort = v.GetInt(collectorHTTPPort) cOpts.CollectorZipkinHTTPPort = v.GetInt(collectorZipkinHTTPort) diff --git a/cmd/collector/app/builder/span_handler_builder.go b/cmd/collector/app/builder/span_handler_builder.go index 61a753972b5..a6ede197db2 100644 --- a/cmd/collector/app/builder/span_handler_builder.go +++ b/cmd/collector/app/builder/span_handler_builder.go @@ -24,12 +24,7 @@ import ( basicB "github.com/jaegertracing/jaeger/cmd/builder" "github.com/jaegertracing/jaeger/cmd/collector/app" zs "github.com/jaegertracing/jaeger/cmd/collector/app/sanitizer/zipkin" - "github.com/jaegertracing/jaeger/cmd/flags" "github.com/jaegertracing/jaeger/model" - cascfg "github.com/jaegertracing/jaeger/pkg/cassandra/config" - escfg "github.com/jaegertracing/jaeger/pkg/es/config" - casSpanstore "github.com/jaegertracing/jaeger/plugin/storage/cassandra/spanstore" - esSpanstore "github.com/jaegertracing/jaeger/plugin/storage/es/spanstore" "github.com/jaegertracing/jaeger/storage/spanstore" ) @@ -48,71 +43,19 @@ type SpanHandlerBuilder struct { } // NewSpanHandlerBuilder returns new SpanHandlerBuilder with configured span storage. -func NewSpanHandlerBuilder(cOpts *CollectorOptions, sFlags *flags.SharedFlags, opts ...basicB.Option) (*SpanHandlerBuilder, error) { +func NewSpanHandlerBuilder(cOpts *CollectorOptions, spanWriter spanstore.Writer, opts ...basicB.Option) (*SpanHandlerBuilder, error) { options := basicB.ApplyOptions(opts...) spanHb := &SpanHandlerBuilder{ collectorOpts: cOpts, logger: options.Logger, metricsFactory: options.MetricsFactory, - } - - var err error - if sFlags.SpanStorage.Type == flags.CassandraStorageType { - if options.CassandraSessionBuilder == nil { - return nil, errMissingCassandraConfig - } - spanHb.spanWriter, err = spanHb.initCassStore(options.CassandraSessionBuilder) - } else if sFlags.SpanStorage.Type == flags.MemoryStorageType { - if options.MemoryStore == nil { - return nil, errMissingMemoryStore - } - spanHb.spanWriter = options.MemoryStore - } else if sFlags.SpanStorage.Type == flags.ESStorageType { - if options.ElasticClientBuilder == nil { - return nil, errMissingElasticSearchConfig - } - spanHb.spanWriter, err = spanHb.initElasticStore(options.ElasticClientBuilder) - } else { - return nil, flags.ErrUnsupportedStorageType - } - - if err != nil { - return nil, err + spanWriter: spanWriter, } return spanHb, nil } -func (spanHb *SpanHandlerBuilder) initCassStore(builder cascfg.SessionBuilder) (spanstore.Writer, error) { - session, err := builder.NewSession() - if err != nil { - return nil, err - } - - return casSpanstore.NewSpanWriter( - session, - spanHb.collectorOpts.WriteCacheTTL, - spanHb.metricsFactory, - spanHb.logger, - ), nil -} - -func (spanHb *SpanHandlerBuilder) initElasticStore(esBuilder escfg.ClientBuilder) (spanstore.Writer, error) { - client, err := esBuilder.NewClient() - if err != nil { - return nil, err - } - - return esSpanstore.NewSpanWriter( - client, - spanHb.logger, - spanHb.metricsFactory, - esBuilder.GetNumShards(), - esBuilder.GetNumReplicas(), - ), nil -} - // BuildHandlers builds span handlers (Zipkin, Jaeger) func (spanHb *SpanHandlerBuilder) BuildHandlers() (app.ZipkinSpansHandler, app.JaegerBatchesHandler) { hostname, _ := os.Hostname() diff --git a/cmd/collector/app/builder/span_handler_builder_test.go b/cmd/collector/app/builder/span_handler_builder_test.go index ca9813ca692..bc41e6cf89f 100644 --- a/cmd/collector/app/builder/span_handler_builder_test.go +++ b/cmd/collector/app/builder/span_handler_builder_test.go @@ -24,127 +24,23 @@ import ( "github.com/jaegertracing/jaeger/cmd/builder" "github.com/jaegertracing/jaeger/cmd/flags" - "github.com/jaegertracing/jaeger/pkg/cassandra" - cascfg "github.com/jaegertracing/jaeger/pkg/cassandra/config" - "github.com/jaegertracing/jaeger/pkg/cassandra/mocks" "github.com/jaegertracing/jaeger/pkg/config" - "github.com/jaegertracing/jaeger/pkg/es" - escfg "github.com/jaegertracing/jaeger/pkg/es/config" - esMocks "github.com/jaegertracing/jaeger/pkg/es/mocks" - "github.com/jaegertracing/jaeger/storage/spanstore/memory" + "github.com/jaegertracing/jaeger/plugin/storage/memory" ) -type mockSessionBuilder struct { -} - -func (*mockSessionBuilder) NewSession() (cassandra.Session, error) { - return &mocks.Session{}, nil -} - -type mockEsBuilder struct { - escfg.Configuration -} - -func (mck *mockEsBuilder) NewClient() (es.Client, error) { - return &esMocks.Client{}, nil -} - func TestNewSpanHandlerBuilder(t *testing.T) { - v, command := config.Viperize(flags.AddFlags) + v, command := config.Viperize(flags.AddFlags, AddFlags) command.ParseFlags([]string{}) - sFlags := new(flags.SharedFlags).InitFromViper(v) cOpts := new(CollectorOptions).InitFromViper(v) - handler, err := NewSpanHandlerBuilder( - cOpts, - sFlags, - builder.Options.LoggerOption(zap.NewNop()), - builder.Options.MetricsFactoryOption(metrics.NullFactory), - builder.Options.CassandraSessionOption(&mockSessionBuilder{}), - ) - require.NoError(t, err) - assert.NotNil(t, handler) - zipkin, jaeger := handler.BuildHandlers() - assert.NotNil(t, zipkin) - assert.NotNil(t, jaeger) -} - -func TestNewSpanHandlerBuilderCassandraNoSession(t *testing.T) { - v, command := config.Viperize(flags.AddFlags) - - command.ParseFlags([]string{}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - cOpts := new(CollectorOptions).InitFromViper(v) + spanWriter := memory.NewStore() handler, err := NewSpanHandlerBuilder( cOpts, - sFlags, + spanWriter, builder.Options.LoggerOption(zap.NewNop()), builder.Options.MetricsFactoryOption(metrics.NullFactory), - builder.Options.CassandraSessionOption(&cascfg.Configuration{}), - ) - require.Error(t, err) - assert.Nil(t, handler) -} - -func TestNewSpanHandlerBuilderCassandraNotConfigured(t *testing.T) { - v, _ := config.Viperize(AddFlags, flags.AddFlags) - sFlags := new(flags.SharedFlags).InitFromViper(v) - cOpts := new(CollectorOptions).InitFromViper(v) - - handler, err := NewSpanHandlerBuilder(cOpts, sFlags) - assert.Error(t, err) - assert.Nil(t, handler) -} - -func TestNewSpanHandlerBuilderBadStorageTypeFailure(t *testing.T) { - v, command := config.Viperize(AddFlags, flags.AddFlags) - command.ParseFlags([]string{"test", "--span-storage.type=sneh"}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - cOpts := new(CollectorOptions).InitFromViper(v) - - handler, err := NewSpanHandlerBuilder(cOpts, sFlags) - assert.Error(t, err) - assert.Nil(t, handler) -} - -func TestNewSpanHandlerBuilderMemoryNotSet(t *testing.T) { - v, command := config.Viperize(AddFlags, flags.AddFlags) - command.ParseFlags([]string{"test", "--span-storage.type=memory"}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - cOpts := new(CollectorOptions).InitFromViper(v) - - handler, err := NewSpanHandlerBuilder(cOpts, sFlags) - assert.Error(t, err) - assert.Nil(t, handler) -} - -func TestNewSpanHandlerBuilderMemorySet(t *testing.T) { - v, command := config.Viperize(AddFlags, flags.AddFlags) - command.ParseFlags([]string{"test", "--span-storage.type=memory"}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - cOpts := new(CollectorOptions).InitFromViper(v) - - handler, err := NewSpanHandlerBuilder(cOpts, sFlags, builder.Options.MemoryStoreOption(memory.NewStore())) - require.NoError(t, err) - assert.NotNil(t, handler) - jHandler, zHandler := handler.BuildHandlers() - assert.NotNil(t, jHandler) - assert.NotNil(t, zHandler) -} - -func TestNewSpanHandlerBuilderElasticSearch(t *testing.T) { - v, command := config.Viperize(AddFlags, flags.AddFlags) - command.ParseFlags([]string{"test", "--span-storage.type=elasticsearch"}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - cOpts := new(CollectorOptions).InitFromViper(v) - - handler, err := NewSpanHandlerBuilder( - cOpts, - sFlags, - builder.Options.LoggerOption(zap.NewNop()), - builder.Options.ElasticClientOption(&mockEsBuilder{}), ) require.NoError(t, err) assert.NotNil(t, handler) @@ -153,32 +49,6 @@ func TestNewSpanHandlerBuilderElasticSearch(t *testing.T) { assert.NotNil(t, jaeger) } -func TestNewSpanHandlerBuilderElasticSearchNoClient(t *testing.T) { - v, command := config.Viperize(AddFlags, flags.AddFlags) - command.ParseFlags([]string{"test", "--span-storage.type=elasticsearch"}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - cOpts := new(CollectorOptions).InitFromViper(v) - - handler, err := NewSpanHandlerBuilder( - cOpts, - sFlags, - builder.Options.LoggerOption(zap.NewNop()), - builder.Options.ElasticClientOption(&escfg.Configuration{}), - ) - require.Error(t, err) - assert.Nil(t, handler) -} - -func TestNewSpanHandlerBuilderElasticSearchFailure(t *testing.T) { - v, command := config.Viperize(AddFlags, flags.AddFlags) - command.ParseFlags([]string{"test", "--span-storage.type=elasticsearch"}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - cOpts := new(CollectorOptions).InitFromViper(v) - handler, err := NewSpanHandlerBuilder(cOpts, sFlags) - assert.EqualError(t, err, "ElasticSearch not configured") - assert.Nil(t, handler) -} - func TestDefaultSpanFilter(t *testing.T) { assert.True(t, defaultSpanFilter(nil)) } diff --git a/cmd/collector/main.go b/cmd/collector/main.go index 5776a9cb54e..e757d64657e 100644 --- a/cmd/collector/main.go +++ b/cmd/collector/main.go @@ -16,6 +16,7 @@ package main import ( "fmt" + "log" "net" "net/http" "os" @@ -35,31 +36,32 @@ import ( "github.com/jaegertracing/jaeger/cmd/collector/app/builder" "github.com/jaegertracing/jaeger/cmd/collector/app/zipkin" "github.com/jaegertracing/jaeger/cmd/flags" - casFlags "github.com/jaegertracing/jaeger/cmd/flags/cassandra" - esFlags "github.com/jaegertracing/jaeger/cmd/flags/es" "github.com/jaegertracing/jaeger/pkg/config" "github.com/jaegertracing/jaeger/pkg/healthcheck" pMetrics "github.com/jaegertracing/jaeger/pkg/metrics" "github.com/jaegertracing/jaeger/pkg/recoveryhandler" "github.com/jaegertracing/jaeger/pkg/version" + "github.com/jaegertracing/jaeger/plugin/storage" jc "github.com/jaegertracing/jaeger/thrift-gen/jaeger" zc "github.com/jaegertracing/jaeger/thrift-gen/zipkincore" ) +const serviceName = "jaeger-collector" + func main() { var signalsChannel = make(chan os.Signal, 0) signal.Notify(signalsChannel, os.Interrupt, syscall.SIGTERM) - serviceName := "jaeger-collector" - casOptions := casFlags.NewOptions("cassandra") - esOptions := esFlags.NewOptions("es") + storageFactory, err := storage.NewFactory() + if err != nil { + log.Fatalf("Cannot initialize storage factory: %v", err) + } v := viper.New() command := &cobra.Command{ Use: "jaeger-collector", Short: "Jaeger collector receives and processes traces from Jaeger agents and clients", - Long: `Jaeger collector receives traces from Jaeger agents and agent and runs them through - a processing pipeline.`, + Long: `Jaeger collector receives traces from Jaeger agents and runs them through a processing pipeline.`, RunE: func(cmd *cobra.Command, args []string) error { err := flags.TryLoadConfigFile(v) if err != nil { @@ -72,28 +74,32 @@ func main() { return err } - casOptions.InitFromViper(v) - esOptions.InitFromViper(v) - mBldr := new(pMetrics.Builder).InitFromViper(v) builderOpts := new(builder.CollectorOptions).InitFromViper(v) + hc, err := healthcheck. + New(healthcheck.Unavailable, healthcheck.Logger(logger)). + Serve(builderOpts.CollectorHealthCheckHTTPPort) + if err != nil { + logger.Fatal("Could not start the health check server.", zap.Error(err)) + } + mBldr := new(pMetrics.Builder).InitFromViper(v) metricsFactory, err := mBldr.CreateMetricsFactory("jaeger-collector") if err != nil { logger.Fatal("Cannot create metrics factory.", zap.Error(err)) } - hc, err := healthcheck. - New(healthcheck.Unavailable, healthcheck.Logger(logger)). - Serve(builderOpts.CollectorHealthCheckHTTPPort) + storageFactory.InitFromViper(v) + if err := storageFactory.Initialize(metricsFactory, logger); err != nil { + logger.Fatal("Failed to init storage factory", zap.Error(err)) + } + spanWriter, err := storageFactory.CreateSpanWriter() if err != nil { - logger.Fatal("Could not start the health check server.", zap.Error(err)) + logger.Fatal("Failed to create span writer", zap.Error(err)) } handlerBuilder, err := builder.NewSpanHandlerBuilder( builderOpts, - sFlags, - basicB.Options.CassandraSessionOption(casOptions.GetPrimary()), - basicB.Options.ElasticClientOption(esOptions.GetPrimary()), + spanWriter, basicB.Options.LoggerOption(logger), basicB.Options.MetricsFactoryOption(metricsFactory), ) @@ -155,8 +161,7 @@ func main() { flags.AddConfigFileFlag, flags.AddFlags, builder.AddFlags, - casOptions.AddFlags, - esOptions.AddFlags, + storageFactory.AddFlags, pMetrics.AddFlags, ) diff --git a/cmd/flags/flags.go b/cmd/flags/flags.go index f17cd1317a3..a446a7ebb45 100644 --- a/cmd/flags/flags.go +++ b/cmd/flags/flags.go @@ -16,8 +16,6 @@ package flags import ( "flag" - "fmt" - "time" "github.com/pkg/errors" "github.com/spf13/viper" @@ -68,27 +66,19 @@ func (flags *SharedFlags) NewLogger(conf zap.Config, options ...zap.Option) (*za // SharedFlags holds flags configuration type SharedFlags struct { - // SpanStorage defines common settings for Span Storage. - SpanStorage spanStorage - // DependencyStorage defines common settings for Dependency Storage. - DependencyStorage dependencyStorage // Logging holds logging configuration Logging logging } // InitFromViper initializes SharedFlags with properties from viper func (flags *SharedFlags) InitFromViper(v *viper.Viper) *SharedFlags { - flags.SpanStorage.Type = v.GetString(spanStorageType) - flags.DependencyStorage.DataFrequency = v.GetDuration(dependencyStorageDataFrequency) flags.Logging.Level = v.GetString(logLevel) return flags } // AddFlags adds flags for SharedFlags func AddFlags(flagSet *flag.FlagSet) { - flagSet.String(spanStorageType, CassandraStorageType, fmt.Sprintf("The type of span storage backend to use, options are currently [%v,%v,%v]", CassandraStorageType, ESStorageType, MemoryStorageType)) flagSet.String(logLevel, "info", "Minimal allowed log Level. For more levels see https://github.com/uber-go/zap") - flagSet.Duration(dependencyStorageDataFrequency, time.Hour*24, "Frequency of service dependency calculations") } // ErrUnsupportedStorageType is the error when dealing with an unsupported storage type @@ -97,11 +87,3 @@ var ErrUnsupportedStorageType = errors.New("Storage Type is not supported") type logging struct { Level string } - -type spanStorage struct { - Type string -} - -type dependencyStorage struct { - DataFrequency time.Duration -} diff --git a/cmd/query/app/builder/cassandra.go b/cmd/query/app/builder/cassandra.go deleted file mode 100644 index 0c65c3a8637..00000000000 --- a/cmd/query/app/builder/cassandra.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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 builder - -import ( - "time" - - "github.com/jaegertracing/jaeger/pkg/cassandra/config" - "github.com/jaegertracing/jaeger/plugin/storage/cassandra/dependencystore" - "github.com/jaegertracing/jaeger/plugin/storage/cassandra/spanstore" -) - -func (sb *StorageBuilder) newCassandraBuilder(sessionBuilder config.SessionBuilder, dependencyDataFreq time.Duration) error { - session, err := sessionBuilder.NewSession() - if err != nil { - return err - } - - sb.SpanReader = spanstore.NewSpanReader(session, sb.metricsFactory, sb.logger) - sb.DependencyReader = dependencystore.NewDependencyStore(session, dependencyDataFreq, sb.metricsFactory, sb.logger) - return nil -} diff --git a/cmd/query/app/builder/cassandra_test.go b/cmd/query/app/builder/cassandra_test.go deleted file mode 100644 index 94bdc3252cb..00000000000 --- a/cmd/query/app/builder/cassandra_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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 builder - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/jaegertracing/jaeger/cmd/flags" - "github.com/jaegertracing/jaeger/pkg/cassandra" - "github.com/jaegertracing/jaeger/pkg/cassandra/config" - "github.com/jaegertracing/jaeger/pkg/cassandra/mocks" -) - -type mockSessionBuilder struct { -} - -func (*mockSessionBuilder) NewSession() (cassandra.Session, error) { - return &mocks.Session{}, nil -} - -func TestNewBuilderFailure(t *testing.T) { - sFlags := &flags.SharedFlags{} - sb := newStorageBuilder() - err := sb.newCassandraBuilder(&config.Configuration{}, sFlags.DependencyStorage.DataFrequency) - require.Error(t, err) - assert.Nil(t, sb.SpanReader) - assert.Nil(t, sb.DependencyReader) -} - -func TestNewBuilderSuccess(t *testing.T) { - sFlags := &flags.SharedFlags{} - - sb := newStorageBuilder() - err := sb.newCassandraBuilder(&mockSessionBuilder{}, sFlags.DependencyStorage.DataFrequency) - require.NoError(t, err) - assert.NotNil(t, sb.SpanReader) - assert.NotNil(t, sb.DependencyReader) -} diff --git a/cmd/query/app/builder/elastic_search.go b/cmd/query/app/builder/elastic_search.go deleted file mode 100644 index 0569f02dbb1..00000000000 --- a/cmd/query/app/builder/elastic_search.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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 builder - -import ( - "github.com/jaegertracing/jaeger/pkg/es/config" - "github.com/jaegertracing/jaeger/plugin/storage/es/dependencystore" - "github.com/jaegertracing/jaeger/plugin/storage/es/spanstore" -) - -func (sb *StorageBuilder) newESBuilder(builder config.ClientBuilder) error { - client, err := builder.NewClient() - if err != nil { - return err - } - - sb.SpanReader = spanstore.NewSpanReader(client, sb.logger, builder.GetMaxSpanAge(), sb.metricsFactory) - sb.DependencyReader = dependencystore.NewDependencyStore(client, sb.logger) - return nil -} diff --git a/cmd/query/app/builder/elastic_search_test.go b/cmd/query/app/builder/elastic_search_test.go deleted file mode 100644 index 5a033cd8ca3..00000000000 --- a/cmd/query/app/builder/elastic_search_test.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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 builder - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/jaegertracing/jaeger/pkg/es" - "github.com/jaegertracing/jaeger/pkg/es/config" - "github.com/jaegertracing/jaeger/pkg/es/mocks" -) - -type mockEsBuilder struct { - config.Configuration -} - -func (mck *mockEsBuilder) NewClient() (es.Client, error) { - return &mocks.Client{}, nil -} - -func TestNewESBuilderSuccess(t *testing.T) { - sb := newStorageBuilder() - err := sb.newESBuilder(&mockEsBuilder{}) - require.NoError(t, err) - assert.NotNil(t, sb.SpanReader) - assert.NotNil(t, sb.DependencyReader) -} - -func TestNewESBuilderFailure(t *testing.T) { - sb := newStorageBuilder() - err := sb.newESBuilder(&config.Configuration{}) - require.Error(t, err) - require.Nil(t, sb.SpanReader) - require.Nil(t, sb.DependencyReader) -} diff --git a/cmd/query/app/builder/storage.go b/cmd/query/app/builder/storage.go deleted file mode 100644 index 79feef8cd47..00000000000 --- a/cmd/query/app/builder/storage.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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 builder - -import ( - "errors" - "time" - - "github.com/uber/jaeger-lib/metrics" - "go.uber.org/zap" - - basicB "github.com/jaegertracing/jaeger/cmd/builder" - "github.com/jaegertracing/jaeger/cmd/flags" - "github.com/jaegertracing/jaeger/storage/dependencystore" - "github.com/jaegertracing/jaeger/storage/spanstore" -) - -// StorageBuilder is the interface that provides the necessary store readers -type StorageBuilder struct { - logger *zap.Logger - metricsFactory metrics.Factory - SpanReader spanstore.Reader - DependencyReader dependencystore.Reader -} - -var ( - errMissingCassandraConfig = errors.New("Cassandra not configured") - errMissingMemoryStore = errors.New("Memory Reader was not provided") - errMissingElasticSearchConfig = errors.New("ElasticSearch not configured") -) - -// NewStorageBuilder creates a StorageBuilder based off the flags that have been set -func NewStorageBuilder(storageType string, dependencyDataFreq time.Duration, opts ...basicB.Option) (*StorageBuilder, error) { - options := basicB.ApplyOptions(opts...) - - sb := &StorageBuilder{ - logger: options.Logger, - metricsFactory: options.MetricsFactory, - } - - // TODO lots of repeated code + if logic, clean up below - var err error - if storageType == flags.CassandraStorageType { - if options.CassandraSessionBuilder == nil { - return nil, errMissingCassandraConfig - } - // TODO technically span and dependency storage might be separate - err = sb.newCassandraBuilder(options.CassandraSessionBuilder, dependencyDataFreq) - } else if storageType == flags.MemoryStorageType { - if options.MemoryStore == nil { - return nil, errMissingMemoryStore - } - sb.newMemoryStoreBuilder(options.MemoryStore) - } else if storageType == flags.ESStorageType { - if options.ElasticClientBuilder == nil { - return nil, errMissingElasticSearchConfig - } - err = sb.newESBuilder(options.ElasticClientBuilder) - } else { - return nil, flags.ErrUnsupportedStorageType - } - - if err != nil { - return nil, err - } - - return sb, nil -} diff --git a/cmd/query/app/builder/storage_test.go b/cmd/query/app/builder/storage_test.go deleted file mode 100644 index a2fdc428ed6..00000000000 --- a/cmd/query/app/builder/storage_test.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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 builder - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/uber/jaeger-lib/metrics" - "go.uber.org/zap" - - basicB "github.com/jaegertracing/jaeger/cmd/builder" - "github.com/jaegertracing/jaeger/cmd/flags" - casCfg "github.com/jaegertracing/jaeger/pkg/cassandra/config" - "github.com/jaegertracing/jaeger/pkg/config" - "github.com/jaegertracing/jaeger/storage/spanstore/memory" -) - -func newStorageBuilder() *StorageBuilder { - return &StorageBuilder{ - logger: zap.NewNop(), - metricsFactory: metrics.NullFactory, - } -} - -func TestNewCassandraSuccess(t *testing.T) { - v, _ := config.Viperize(flags.AddFlags) - sFlags := new(flags.SharedFlags).InitFromViper(v) - sBuilder, err := NewStorageBuilder( - sFlags.SpanStorage.Type, - sFlags.DependencyStorage.DataFrequency, - basicB.Options.LoggerOption(zap.NewNop()), - basicB.Options.MetricsFactoryOption(metrics.NullFactory), - basicB.Options.CassandraSessionOption(&mockSessionBuilder{}), - ) - assert.NoError(t, err) - assert.NotNil(t, sBuilder) -} - -func TestNewCassandraFailure(t *testing.T) { - v, command := config.Viperize(flags.AddFlags) - command.ParseFlags([]string{"test", "--span-storage.type=sneh"}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - sBuilder, err := NewStorageBuilder(sFlags.SpanStorage.Type, sFlags.DependencyStorage.DataFrequency) - assert.EqualError(t, err, "Storage Type is not supported") - assert.Nil(t, sBuilder) - - command.ParseFlags([]string{"test", "--span-storage.type=cassandra"}) - sFlags.InitFromViper(v) - sBuilder, err = NewStorageBuilder(sFlags.SpanStorage.Type, sFlags.DependencyStorage.DataFrequency) - assert.EqualError(t, err, "Cassandra not configured") - assert.Nil(t, sBuilder) -} - -func TestNewCassandraFailureNoSession(t *testing.T) { - v, command := config.Viperize(flags.AddFlags) - sFlags := new(flags.SharedFlags).InitFromViper(v) - command.ParseFlags([]string{"test", "--span-storage.type=cassandra"}) - sFlags.InitFromViper(v) - sBuilder, err := NewStorageBuilder(sFlags.SpanStorage.Type, sFlags.DependencyStorage.DataFrequency, basicB.Options.CassandraSessionOption(&casCfg.Configuration{})) - require.Error(t, err) - assert.Nil(t, sBuilder) -} - -func TestNewMemorySuccess(t *testing.T) { - v, command := config.Viperize(flags.AddFlags) - command.ParseFlags([]string{"test", "--span-storage.type=memory"}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - sBuilder, err := NewStorageBuilder(sFlags.SpanStorage.Type, sFlags.DependencyStorage.DataFrequency, basicB.Options.MemoryStoreOption(memory.NewStore())) - assert.NoError(t, err) - assert.NotNil(t, sBuilder) -} - -func TestNewMemoryFailure(t *testing.T) { - v, command := config.Viperize(flags.AddFlags) - command.ParseFlags([]string{"test", "--span-storage.type=memory"}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - sBuilder, err := NewStorageBuilder(sFlags.SpanStorage.Type, sFlags.DependencyStorage.DataFrequency) - assert.Error(t, err) - assert.Nil(t, sBuilder) -} - -func TestNewElasticSuccess(t *testing.T) { - v, command := config.Viperize(flags.AddFlags) - command.ParseFlags([]string{"test", "--span-storage.type=elasticsearch"}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - sBuilder, err := NewStorageBuilder( - sFlags.SpanStorage.Type, - sFlags.DependencyStorage.DataFrequency, - basicB.Options.LoggerOption(zap.NewNop()), - basicB.Options.ElasticClientOption(&mockEsBuilder{}), - ) - assert.NoError(t, err) - assert.NotNil(t, sBuilder) -} - -func TestNewElasticFailure(t *testing.T) { - v, command := config.Viperize(flags.AddFlags) - command.ParseFlags([]string{"test", "--span-storage.type=elasticsearch"}) - sFlags := new(flags.SharedFlags).InitFromViper(v) - sBuilder, err := NewStorageBuilder(sFlags.SpanStorage.Type, sFlags.DependencyStorage.DataFrequency) - assert.EqualError(t, err, "ElasticSearch not configured") - assert.Nil(t, sBuilder) -} diff --git a/cmd/query/app/builder/builder_flags.go b/cmd/query/app/flags.go similarity index 97% rename from cmd/query/app/builder/builder_flags.go rename to cmd/query/app/flags.go index 89889c250ac..824842a33f6 100644 --- a/cmd/query/app/builder/builder_flags.go +++ b/cmd/query/app/flags.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package builder +package app import ( "flag" @@ -28,7 +28,7 @@ const ( queryHealthCheckHTTPPort = "query.health-check-http-port" ) -// QueryOptions holds configuration for query +// QueryOptions holds configuration for query service type QueryOptions struct { // Port is the port that the query service listens in on Port int diff --git a/cmd/query/app/builder/builder_flags_test.go b/cmd/query/app/flags_test.go similarity index 98% rename from cmd/query/app/builder/builder_flags_test.go rename to cmd/query/app/flags_test.go index c1f67da840d..555d3920290 100644 --- a/cmd/query/app/builder/builder_flags_test.go +++ b/cmd/query/app/flags_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package builder +package app import ( "testing" diff --git a/cmd/query/main.go b/cmd/query/main.go index 45874601d8d..7abf03b3069 100644 --- a/cmd/query/main.go +++ b/cmd/query/main.go @@ -16,6 +16,7 @@ package main import ( "fmt" + "log" "net/http" "os" "os/signal" @@ -29,25 +30,25 @@ import ( jaegerClientConfig "github.com/uber/jaeger-client-go/config" "go.uber.org/zap" - basicB "github.com/jaegertracing/jaeger/cmd/builder" "github.com/jaegertracing/jaeger/cmd/flags" - casFlags "github.com/jaegertracing/jaeger/cmd/flags/cassandra" - esFlags "github.com/jaegertracing/jaeger/cmd/flags/es" "github.com/jaegertracing/jaeger/cmd/query/app" - "github.com/jaegertracing/jaeger/cmd/query/app/builder" "github.com/jaegertracing/jaeger/pkg/config" "github.com/jaegertracing/jaeger/pkg/healthcheck" pMetrics "github.com/jaegertracing/jaeger/pkg/metrics" "github.com/jaegertracing/jaeger/pkg/recoveryhandler" "github.com/jaegertracing/jaeger/pkg/version" + "github.com/jaegertracing/jaeger/plugin/storage" ) func main() { var serverChannel = make(chan os.Signal, 0) signal.Notify(serverChannel, os.Interrupt, syscall.SIGTERM) - casOptions := casFlags.NewOptions("cassandra", "cassandra.archive") - esOptions := esFlags.NewOptions("es", "es.archive") + storageFactory, err := storage.NewFactory() + if err != nil { + log.Fatalf("Cannot initialize storage factory: %v", err) + } + v := viper.New() var command = &cobra.Command{ @@ -66,11 +67,7 @@ func main() { return err } - casOptions.InitFromViper(v) - esOptions.InitFromViper(v) - queryOpts := new(builder.QueryOptions).InitFromViper(v) - mBldr := new(pMetrics.Builder).InitFromViper(v) - + queryOpts := new(app.QueryOptions).InitFromViper(v) hc, err := healthcheck. New(healthcheck.Unavailable, healthcheck.Logger(logger)). Serve(queryOpts.HealthCheckHTTPPort) @@ -78,6 +75,7 @@ func main() { logger.Fatal("Could not start the health check server.", zap.Error(err)) } + mBldr := new(pMetrics.Builder).InitFromViper(v) metricsFactory, err := mBldr.CreateMetricsFactory("jaeger-query") if err != nil { logger.Fatal("Cannot create metrics factory.", zap.Error(err)) @@ -95,21 +93,22 @@ func main() { } defer closer.Close() - storageBuild, err := builder.NewStorageBuilder( - sFlags.SpanStorage.Type, - sFlags.DependencyStorage.DataFrequency, - basicB.Options.LoggerOption(logger), - basicB.Options.MetricsFactoryOption(metricsFactory), - basicB.Options.CassandraSessionOption(casOptions.GetPrimary()), - basicB.Options.ElasticClientOption(esOptions.GetPrimary()), - ) + storageFactory.InitFromViper(v) + if err := storageFactory.Initialize(metricsFactory, logger); err != nil { + logger.Fatal("Failed to init storage factory", zap.Error(err)) + } + spanReader, err := storageFactory.CreateSpanReader() + if err != nil { + logger.Fatal("Failed to create span reader", zap.Error(err)) + } + dependencyReader, err := storageFactory.CreateDependencyReader() if err != nil { - logger.Fatal("Failed to init storage builder", zap.Error(err)) + logger.Fatal("Failed to create dependency reader", zap.Error(err)) } apiHandler := app.NewAPIHandler( - storageBuild.SpanReader, - storageBuild.DependencyReader, + spanReader, + dependencyReader, app.HandlerOptions.Prefix(queryOpts.Prefix), app.HandlerOptions.Logger(logger), app.HandlerOptions.Tracer(tracer)) @@ -151,10 +150,9 @@ func main() { command, flags.AddConfigFileFlag, flags.AddFlags, - casOptions.AddFlags, - esOptions.AddFlags, + storageFactory.AddFlags, pMetrics.AddFlags, - builder.AddFlags, + app.AddFlags, ) if error := command.Execute(); error != nil { @@ -163,7 +161,7 @@ func main() { } } -func registerStaticHandler(r *mux.Router, logger *zap.Logger, qOpts *builder.QueryOptions) { +func registerStaticHandler(r *mux.Router, logger *zap.Logger, qOpts *app.QueryOptions) { staticHandler, err := app.NewStaticAssetsHandler(qOpts.StaticAssets, qOpts.UIConfig) if err != nil { logger.Fatal("Could not create static assets handler", zap.Error(err)) diff --git a/cmd/standalone/Dockerfile b/cmd/standalone/Dockerfile index e1131901487..60769f6543e 100644 --- a/cmd/standalone/Dockerfile +++ b/cmd/standalone/Dockerfile @@ -21,4 +21,4 @@ EXPOSE 16686 COPY ./jaeger-ui-build /go/src/jaeger-ui-build COPY ./cmd/standalone/standalone-linux /go/bin/ -CMD ["/go/bin/standalone-linux","--span-storage.type=memory","--query.static-files=/go/src/jaeger-ui-build/build/"] +CMD ["/go/bin/standalone-linux","--query.static-files=/go/src/jaeger-ui-build/build/"] diff --git a/cmd/standalone/main.go b/cmd/standalone/main.go index 073a21c7f2c..7a7a3a4b67f 100644 --- a/cmd/standalone/main.go +++ b/cmd/standalone/main.go @@ -16,6 +16,7 @@ package main import ( "fmt" + "log" "net" "net/http" "os" @@ -39,18 +40,26 @@ import ( "github.com/jaegertracing/jaeger/cmd/collector/app/zipkin" "github.com/jaegertracing/jaeger/cmd/flags" queryApp "github.com/jaegertracing/jaeger/cmd/query/app" - query "github.com/jaegertracing/jaeger/cmd/query/app/builder" "github.com/jaegertracing/jaeger/pkg/config" pMetrics "github.com/jaegertracing/jaeger/pkg/metrics" "github.com/jaegertracing/jaeger/pkg/recoveryhandler" "github.com/jaegertracing/jaeger/pkg/version" - "github.com/jaegertracing/jaeger/storage/spanstore/memory" + "github.com/jaegertracing/jaeger/plugin/storage" + "github.com/jaegertracing/jaeger/storage/dependencystore" + "github.com/jaegertracing/jaeger/storage/spanstore" jc "github.com/jaegertracing/jaeger/thrift-gen/jaeger" zc "github.com/jaegertracing/jaeger/thrift-gen/zipkincore" ) // standalone/main is a standalone full-stack jaeger backend, backed by a memory store func main() { + if os.Getenv(storage.SpanStorageEnvVar) == "" { + os.Setenv(storage.SpanStorageEnvVar, "memory") // other storage types default to SpanStorage + } + storageFactory, err := storage.NewFactory() + if err != nil { + log.Fatalf("Cannot initialize storage factory: %v", err) + } v := viper.New() command := &cobra.Command{ Use: "jaeger-standalone", @@ -70,21 +79,38 @@ func main() { } runtime.GOMAXPROCS(runtime.NumCPU()) - cOpts := new(collector.CollectorOptions).InitFromViper(v) - qOpts := new(query.QueryOptions).InitFromViper(v) - mBldr := new(pMetrics.Builder).InitFromViper(v) + mBldr := new(pMetrics.Builder).InitFromViper(v) metricsFactory, err := mBldr.CreateMetricsFactory("jaeger-standalone") if err != nil { return errors.Wrap(err, "Cannot create metrics factory") } - memStore := memory.NewStore() - builder := &agentApp.Builder{} - builder.InitFromViper(v) - startAgent(builder, cOpts, logger, metricsFactory) - startCollector(cOpts, sFlags, logger, metricsFactory, memStore) - startQuery(qOpts, sFlags, logger, metricsFactory, mBldr, memStore) + storageFactory.InitFromViper(v) + if err := storageFactory.Initialize(metricsFactory, logger); err != nil { + logger.Fatal("Failed to init storage factory", zap.Error(err)) + } + spanReader, err := storageFactory.CreateSpanReader() + if err != nil { + logger.Fatal("Failed to create span reader", zap.Error(err)) + } + spanWriter, err := storageFactory.CreateSpanWriter() + if err != nil { + logger.Fatal("Failed to create span writer", zap.Error(err)) + } + dependencyReader, err := storageFactory.CreateDependencyReader() + if err != nil { + logger.Fatal("Failed to create dependency reader", zap.Error(err)) + } + + aOpts := new(agentApp.Builder).InitFromViper(v) + cOpts := new(collector.CollectorOptions).InitFromViper(v) + qOpts := new(queryApp.QueryOptions).InitFromViper(v) + + startAgent(aOpts, cOpts, logger, metricsFactory) + startCollector(cOpts, spanWriter, logger, metricsFactory) + startQuery(qOpts, spanReader, dependencyReader, logger, metricsFactory, mBldr) + select {} }, } @@ -96,9 +122,10 @@ func main() { command, flags.AddConfigFileFlag, flags.AddFlags, - collector.AddFlags, - query.AddFlags, + storageFactory.AddFlags, agentApp.AddFlags, + collector.AddFlags, + queryApp.AddFlags, pMetrics.AddFlags, ) @@ -132,19 +159,17 @@ func startAgent( func startCollector( cOpts *collector.CollectorOptions, - sFlags *flags.SharedFlags, + spanWriter spanstore.Writer, logger *zap.Logger, baseFactory metrics.Factory, - memoryStore *memory.Store, ) { metricsFactory := baseFactory.Namespace("jaeger-collector", nil) spanBuilder, err := collector.NewSpanHandlerBuilder( cOpts, - sFlags, + spanWriter, basic.Options.LoggerOption(logger), basic.Options.MetricsFactoryOption(metricsFactory), - basic.Options.MemoryStoreOption(memoryStore), ) if err != nil { logger.Fatal("Unable to set up builder", zap.Error(err)) @@ -201,29 +226,17 @@ func startZipkinHTTPAPI( } func startQuery( - qOpts *query.QueryOptions, - sFlags *flags.SharedFlags, + qOpts *queryApp.QueryOptions, + spanReader spanstore.Reader, + depReader dependencystore.Reader, logger *zap.Logger, baseFactory metrics.Factory, metricsBuilder *pMetrics.Builder, - memoryStore *memory.Store, ) { - metricsFactory := baseFactory.Namespace("jaeger-query", nil) - - storageBuild, err := query.NewStorageBuilder( - sFlags.SpanStorage.Type, - sFlags.DependencyStorage.DataFrequency, - basic.Options.LoggerOption(logger), - basic.Options.MetricsFactoryOption(metricsFactory), - basic.Options.MemoryStoreOption(memoryStore), - ) - if err != nil { - logger.Fatal("Failed to wire up service", zap.Error(err)) - } tracer, closer, err := jaegerClientConfig.Configuration{ Sampler: &jaegerClientConfig.SamplerConfig{ - Type: "probabilistic", - Param: 0.001, + Type: "const", + Param: 1.0, }, RPCMetrics: true, }.New("jaeger-query", jaegerClientConfig.Metrics(baseFactory)) @@ -232,8 +245,8 @@ func startQuery( } defer closer.Close() apiHandler := queryApp.NewAPIHandler( - storageBuild.SpanReader, - storageBuild.DependencyReader, + spanReader, + depReader, queryApp.HandlerOptions.Prefix(qOpts.Prefix), queryApp.HandlerOptions.Logger(logger), queryApp.HandlerOptions.Tracer(tracer)) @@ -255,7 +268,7 @@ func startQuery( } } -func registerStaticHandler(r *mux.Router, logger *zap.Logger, qOpts *query.QueryOptions) { +func registerStaticHandler(r *mux.Router, logger *zap.Logger, qOpts *queryApp.QueryOptions) { staticHandler, err := queryApp.NewStaticAssetsHandler(qOpts.StaticAssets, qOpts.UIConfig) if err != nil { logger.Fatal("Could not create static assets handler", zap.Error(err)) diff --git a/cmd/query/app/builder/memory.go b/plugin/configurable.go similarity index 58% rename from cmd/query/app/builder/memory.go rename to plugin/configurable.go index 5fd9d0475b1..cf0b1dcc4e0 100644 --- a/cmd/query/app/builder/memory.go +++ b/plugin/configurable.go @@ -12,13 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -package builder +package plugin import ( - "github.com/jaegertracing/jaeger/storage/spanstore/memory" + "flag" + + "github.com/spf13/viper" ) -func (sb *StorageBuilder) newMemoryStoreBuilder(memStore *memory.Store) { - sb.SpanReader = memStore - sb.DependencyReader = memStore +// Configurable interface can be implemented by plugins that require external configuration, +// such as CLI flags, config files, or environment variables. +type Configurable interface { + // AddFlags adds CLI flags for configuring this component. + AddFlags(flagSet *flag.FlagSet) + + // InitFromViper initializes this component with properties from spf13/viper. + InitFromViper(v *viper.Viper) } diff --git a/plugin/storage/cassandra/factory.go b/plugin/storage/cassandra/factory.go new file mode 100644 index 00000000000..00e84e4fbdd --- /dev/null +++ b/plugin/storage/cassandra/factory.go @@ -0,0 +1,88 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 cassandra + +import ( + "flag" + + "github.com/spf13/viper" + "github.com/uber/jaeger-lib/metrics" + "go.uber.org/zap" + + "github.com/jaegertracing/jaeger/pkg/cassandra" + "github.com/jaegertracing/jaeger/pkg/cassandra/config" + cDepStore "github.com/jaegertracing/jaeger/plugin/storage/cassandra/dependencystore" + cSpanStore "github.com/jaegertracing/jaeger/plugin/storage/cassandra/spanstore" + "github.com/jaegertracing/jaeger/storage/dependencystore" + "github.com/jaegertracing/jaeger/storage/spanstore" +) + +// Factory implements storage.Factory for Cassandra backend. +type Factory struct { + Options *Options + + metricsFactory metrics.Factory + logger *zap.Logger + + primaryConfig config.SessionBuilder + primarySession cassandra.Session + // archiveSession cassandra.Session TODO +} + +// NewFactory creates a new Factory. +func NewFactory() *Factory { + return &Factory{ + Options: NewOptions("cassandra"), // TODO add "cassandra-archive" once supported + } +} + +// AddFlags implements plugin.Configurable +func (f *Factory) AddFlags(flagSet *flag.FlagSet) { + f.Options.AddFlags(flagSet) +} + +// InitFromViper implements plugin.Configurable +func (f *Factory) InitFromViper(v *viper.Viper) { + f.Options.InitFromViper(v) + f.primaryConfig = f.Options.GetPrimary() +} + +// Initialize implements storage.Factory +func (f *Factory) Initialize(metricsFactory metrics.Factory, logger *zap.Logger) error { + f.metricsFactory, f.logger = metricsFactory, logger + + primarySession, err := f.primaryConfig.NewSession() + if err != nil { + return err + } + f.primarySession = primarySession + // TODO init archive (cf. https://github.com/jaegertracing/jaeger/pull/604) + return nil +} + +// CreateSpanReader implements storage.Factory +func (f *Factory) CreateSpanReader() (spanstore.Reader, error) { + return cSpanStore.NewSpanReader(f.primarySession, f.metricsFactory, f.logger), nil +} + +// CreateSpanWriter implements storage.Factory +func (f *Factory) CreateSpanWriter() (spanstore.Writer, error) { + return cSpanStore.NewSpanWriter(f.primarySession, f.Options.SpanStoreWriteCacheTTL, f.metricsFactory, f.logger), nil +} + +// CreateDependencyReader implements storage.Factory +func (f *Factory) CreateDependencyReader() (dependencystore.Reader, error) { + return cDepStore.NewDependencyStore(f.primarySession, f.Options.DepStoreDataFrequency, f.metricsFactory, f.logger), nil +} diff --git a/plugin/storage/cassandra/factory_test.go b/plugin/storage/cassandra/factory_test.go new file mode 100644 index 00000000000..8b39f6a546a --- /dev/null +++ b/plugin/storage/cassandra/factory_test.go @@ -0,0 +1,66 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 cassandra + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/uber/jaeger-lib/metrics" + "go.uber.org/zap" + + "github.com/jaegertracing/jaeger/pkg/cassandra" + "github.com/jaegertracing/jaeger/pkg/cassandra/mocks" + "github.com/jaegertracing/jaeger/pkg/config" + "github.com/jaegertracing/jaeger/storage" +) + +var _ storage.Factory = new(Factory) + +type mockSessionBuilder struct { + err error +} + +func (m *mockSessionBuilder) NewSession() (cassandra.Session, error) { + if m.err == nil { + return &mocks.Session{}, nil + } + return nil, m.err +} + +func TestCassandraFactory(t *testing.T) { + f := NewFactory() + v, command := config.Viperize(f.AddFlags) + command.ParseFlags([]string{}) + f.InitFromViper(v) + + // after InitFromViper, f.primaryConfig points to a real session builder that will fail in unit tests, + // so we override it with a mock. + f.primaryConfig = &mockSessionBuilder{err: errors.New("made-up error")} + assert.EqualError(t, f.Initialize(metrics.NullFactory, zap.NewNop()), "made-up error") + + f.primaryConfig = &mockSessionBuilder{} + assert.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop())) + + _, err := f.CreateSpanReader() + assert.NoError(t, err) + + _, err = f.CreateSpanWriter() + assert.NoError(t, err) + + _, err = f.CreateDependencyReader() + assert.NoError(t, err) +} diff --git a/cmd/flags/cassandra/options.go b/plugin/storage/cassandra/options.go similarity index 85% rename from cmd/flags/cassandra/options.go rename to plugin/storage/cassandra/options.go index ea81f7ee1e0..d6a84cffc1d 100644 --- a/cmd/flags/cassandra/options.go +++ b/plugin/storage/cassandra/options.go @@ -17,6 +17,7 @@ package cassandra import ( "flag" "strings" + "time" "github.com/spf13/viper" @@ -24,6 +25,7 @@ import ( ) const ( + // session settings suffixConnPerHost = ".connections-per-host" suffixMaxRetryAttempts = ".max-retry-attempts" suffixTimeout = ".timeout" @@ -40,17 +42,20 @@ const ( suffixCA = ".tls.ca" suffixServerName = ".tls.server-name" suffixVerifyHost = ".tls.verify-host" -) -// TODO this should be moved next to config.Configuration struct (maybe ./flags package) + // common storage settings + suffixSpanStoreWriteCacheTTL = ".span-store-write-cache-ttl" + suffixDepStoreDataFrequency = ".dependency-store-data-frequency" +) // Options contains various type of Cassandra configs and provides the ability // to bind them to command line flag and apply overlays, so that some configurations // (e.g. archive) may be underspecified and infer the rest of its parameters from primary. type Options struct { - primary *namespaceConfig - - others map[string]*namespaceConfig + primary *namespaceConfig + others map[string]*namespaceConfig + SpanStoreWriteCacheTTL time.Duration + DepStoreDataFrequency time.Duration } // the Servers field in config.Configuration is a list, which we cannot represent with flags. @@ -80,7 +85,9 @@ func NewOptions(primaryNamespace string, otherNamespaces ...string) *Options { servers: "127.0.0.1", namespace: primaryNamespace, }, - others: make(map[string]*namespaceConfig, len(otherNamespaces)), + others: make(map[string]*namespaceConfig, len(otherNamespaces)), + SpanStoreWriteCacheTTL: time.Hour * 12, + DepStoreDataFrequency: time.Hour * 24, } for _, namespace := range otherNamespaces { @@ -96,6 +103,12 @@ func (opt *Options) AddFlags(flagSet *flag.FlagSet) { for _, cfg := range opt.others { addFlags(flagSet, cfg) } + flagSet.Duration(opt.primary.namespace+suffixSpanStoreWriteCacheTTL, + opt.SpanStoreWriteCacheTTL, + "The duration to wait before rewriting an existing service or operation name") + flagSet.Duration(opt.primary.namespace+suffixDepStoreDataFrequency, + opt.DepStoreDataFrequency, + "Frequency of service dependency calculations") } func addFlags(flagSet *flag.FlagSet, nsConfig *namespaceConfig) { @@ -167,13 +180,15 @@ 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) + opt.primary.initFromViper(v) for _, cfg := range opt.others { - initFromViper(cfg, v) + cfg.initFromViper(v) } + opt.SpanStoreWriteCacheTTL = v.GetDuration(opt.primary.namespace + suffixSpanStoreWriteCacheTTL) + opt.DepStoreDataFrequency = v.GetDuration(opt.primary.namespace + suffixDepStoreDataFrequency) } -func initFromViper(cfg *namespaceConfig, v *viper.Viper) { +func (cfg *namespaceConfig) initFromViper(v *viper.Viper) { cfg.ConnectionsPerHost = v.GetInt(cfg.namespace + suffixConnPerHost) cfg.MaxRetryAttempts = v.GetInt(cfg.namespace + suffixMaxRetryAttempts) cfg.Timeout = v.GetDuration(cfg.namespace + suffixTimeout) diff --git a/cmd/flags/cassandra/options_test.go b/plugin/storage/cassandra/options_test.go similarity index 100% rename from cmd/flags/cassandra/options_test.go rename to plugin/storage/cassandra/options_test.go diff --git a/plugin/storage/es/factory.go b/plugin/storage/es/factory.go new file mode 100644 index 00000000000..5aca99e88fd --- /dev/null +++ b/plugin/storage/es/factory.go @@ -0,0 +1,89 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 es + +import ( + "flag" + + "github.com/spf13/viper" + "github.com/uber/jaeger-lib/metrics" + "go.uber.org/zap" + + "github.com/jaegertracing/jaeger/pkg/es" + "github.com/jaegertracing/jaeger/pkg/es/config" + esDepStore "github.com/jaegertracing/jaeger/plugin/storage/es/dependencystore" + esSpanStore "github.com/jaegertracing/jaeger/plugin/storage/es/spanstore" + "github.com/jaegertracing/jaeger/storage/dependencystore" + "github.com/jaegertracing/jaeger/storage/spanstore" +) + +// Factory implements storage.Factory for Elasticsearch backend. +type Factory struct { + Options *Options + + metricsFactory metrics.Factory + logger *zap.Logger + + primaryConfig config.ClientBuilder + primaryClient es.Client +} + +// NewFactory creates a new Factory. +func NewFactory() *Factory { + return &Factory{ + Options: NewOptions("es"), // TODO add "es-archive" once supported + } +} + +// AddFlags implements plugin.Configurable +func (f *Factory) AddFlags(flagSet *flag.FlagSet) { + f.Options.AddFlags(flagSet) +} + +// InitFromViper implements plugin.Configurable +func (f *Factory) InitFromViper(v *viper.Viper) { + f.Options.InitFromViper(v) + f.primaryConfig = f.Options.GetPrimary() +} + +// Initialize implements storage.Factory +func (f *Factory) Initialize(metricsFactory metrics.Factory, logger *zap.Logger) error { + f.metricsFactory, f.logger = metricsFactory, logger + + primaryClient, err := f.primaryConfig.NewClient() + if err != nil { + return err + } + f.primaryClient = primaryClient + // TODO init archive (cf. https://github.com/jaegertracing/jaeger/pull/604) + return nil +} + +// CreateSpanReader implements storage.Factory +func (f *Factory) CreateSpanReader() (spanstore.Reader, error) { + cfg := f.primaryConfig + return esSpanStore.NewSpanReader(f.primaryClient, f.logger, cfg.GetMaxSpanAge(), f.metricsFactory), nil +} + +// CreateSpanWriter implements storage.Factory +func (f *Factory) CreateSpanWriter() (spanstore.Writer, error) { + cfg := f.primaryConfig + return esSpanStore.NewSpanWriter(f.primaryClient, f.logger, f.metricsFactory, cfg.GetNumShards(), cfg.GetNumReplicas()), nil +} + +// CreateDependencyReader implements storage.Factory +func (f *Factory) CreateDependencyReader() (dependencystore.Reader, error) { + return esDepStore.NewDependencyStore(f.primaryClient, f.logger), nil +} diff --git a/plugin/storage/es/factory_test.go b/plugin/storage/es/factory_test.go new file mode 100644 index 00000000000..cc9edffae21 --- /dev/null +++ b/plugin/storage/es/factory_test.go @@ -0,0 +1,68 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 es + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/uber/jaeger-lib/metrics" + "go.uber.org/zap" + + "github.com/jaegertracing/jaeger/pkg/config" + "github.com/jaegertracing/jaeger/pkg/es" + escfg "github.com/jaegertracing/jaeger/pkg/es/config" + "github.com/jaegertracing/jaeger/pkg/es/mocks" + "github.com/jaegertracing/jaeger/storage" +) + +var _ storage.Factory = new(Factory) + +type mockClientBuilder struct { + escfg.Configuration + err error +} + +func (m *mockClientBuilder) NewClient() (es.Client, error) { + if m.err == nil { + return &mocks.Client{}, nil + } + return nil, m.err +} + +func TestElasticsearchFactory(t *testing.T) { + f := NewFactory() + v, command := config.Viperize(f.AddFlags) + command.ParseFlags([]string{}) + f.InitFromViper(v) + + // after InitFromViper, f.primaryConfig points to a real session builder that will fail in unit tests, + // so we override it with a mock. + f.primaryConfig = &mockClientBuilder{err: errors.New("made-up error")} + assert.EqualError(t, f.Initialize(metrics.NullFactory, zap.NewNop()), "made-up error") + + f.primaryConfig = &mockClientBuilder{} + assert.NoError(t, f.Initialize(metrics.NullFactory, zap.NewNop())) + + _, err := f.CreateSpanReader() + assert.NoError(t, err) + + _, err = f.CreateSpanWriter() + assert.NoError(t, err) + + _, err = f.CreateDependencyReader() + assert.NoError(t, err) +} diff --git a/cmd/flags/es/options.go b/plugin/storage/es/options.go similarity index 100% rename from cmd/flags/es/options.go rename to plugin/storage/es/options.go diff --git a/cmd/flags/es/options_test.go b/plugin/storage/es/options_test.go similarity index 100% rename from cmd/flags/es/options_test.go rename to plugin/storage/es/options_test.go diff --git a/plugin/storage/factory.go b/plugin/storage/factory.go new file mode 100644 index 00000000000..28512490e14 --- /dev/null +++ b/plugin/storage/factory.go @@ -0,0 +1,153 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 storage + +import ( + "flag" + "fmt" + "os" + + "github.com/spf13/viper" + "github.com/uber/jaeger-lib/metrics" + "go.uber.org/zap" + + "github.com/jaegertracing/jaeger/plugin" + "github.com/jaegertracing/jaeger/plugin/storage/cassandra" + "github.com/jaegertracing/jaeger/plugin/storage/es" + "github.com/jaegertracing/jaeger/plugin/storage/memory" + "github.com/jaegertracing/jaeger/storage" + "github.com/jaegertracing/jaeger/storage/dependencystore" + "github.com/jaegertracing/jaeger/storage/spanstore" +) + +const ( + // SpanStorageEnvVar is the name of the env var that defines the type of backend used for span storage. + SpanStorageEnvVar = "SPAN_STORAGE" + dependencyStorageEnvVar = "DEPENDENCY_STORAGE" + + cassandraStorageType = "cassandra" + elasticsearchStorageType = "elasticsearch" + memoryStorageType = "memory" +) + +var allStorageTypes = []string{cassandraStorageType, elasticsearchStorageType, memoryStorageType} + +// Factory implements storage.Factory interface as a meta-factory for storage components. +// It reads the desired types of storage backends from SPAN_STORAGE and DEPENDENCY_STORAGE +// environment variable. Allowed values: +// * `cassandra` - built-in +// * `elasticsearch` - built-in +// * `memory` - built-in +// * `plugin` - loads a dynamic plugin that implements storage.Factory interface (not supported at the moment) +type Factory struct { + spanStoreType string + depStoreType string + + factories map[string]storage.Factory +} + +// NewFactory creates the meta-factory. +func NewFactory() (*Factory, error) { + f := &Factory{} + f.spanStoreType = os.Getenv(SpanStorageEnvVar) + if f.spanStoreType == "" { + f.spanStoreType = cassandraStorageType + } + f.depStoreType = os.Getenv(dependencyStorageEnvVar) + if f.depStoreType == "" { + f.depStoreType = f.spanStoreType + } + uniqueTypes := map[string]struct{}{ + f.spanStoreType: {}, + f.depStoreType: {}, + } + f.factories = make(map[string]storage.Factory) + for t := range uniqueTypes { + ff, err := f.getFactoryOfType(t) + if err != nil { + return nil, err + } + f.factories[t] = ff + } + return f, nil +} + +func (f *Factory) getFactoryOfType(factoryType string) (storage.Factory, error) { + switch factoryType { + case cassandraStorageType: + return cassandra.NewFactory(), nil + case elasticsearchStorageType: + return es.NewFactory(), nil + case memoryStorageType: + return memory.NewFactory(), nil + default: + return nil, fmt.Errorf("Unknown storage type %s. Valid types are %v", factoryType, allStorageTypes) + } +} + +// Initialize implements storage.Factory +func (f *Factory) Initialize(metricsFactory metrics.Factory, logger *zap.Logger) error { + for _, factory := range f.factories { + if err := factory.Initialize(metricsFactory, logger); err != nil { + return err + } + } + return nil +} + +// CreateSpanReader implements storage.Factory +func (f *Factory) CreateSpanReader() (spanstore.Reader, error) { + factory, ok := f.factories[f.spanStoreType] + if !ok { + return nil, fmt.Errorf("No %s backend registered for span store", f.spanStoreType) + } + return factory.CreateSpanReader() +} + +// CreateSpanWriter implements storage.Factory +func (f *Factory) CreateSpanWriter() (spanstore.Writer, error) { + factory, ok := f.factories[f.spanStoreType] + if !ok { + return nil, fmt.Errorf("No %s backend registered for span store", f.spanStoreType) + } + return factory.CreateSpanWriter() +} + +// CreateDependencyReader implements storage.Factory +func (f *Factory) CreateDependencyReader() (dependencystore.Reader, error) { + factory, ok := f.factories[f.spanStoreType] + if !ok { + return nil, fmt.Errorf("No %s backend registered for span store", f.spanStoreType) + } + return factory.CreateDependencyReader() +} + +// AddFlags implements plugin.Configurable +func (f *Factory) AddFlags(flagSet *flag.FlagSet) { + for _, factory := range f.factories { + if conf, ok := factory.(plugin.Configurable); ok { + conf.AddFlags(flagSet) + } + } +} + +// InitFromViper implements plugin.Configurable +func (f *Factory) InitFromViper(v *viper.Viper) { + for _, factory := range f.factories { + if conf, ok := factory.(plugin.Configurable); ok { + conf.InitFromViper(v) + } + } +} diff --git a/plugin/storage/memory/factory.go b/plugin/storage/memory/factory.go new file mode 100644 index 00000000000..454bc2923fa --- /dev/null +++ b/plugin/storage/memory/factory.go @@ -0,0 +1,57 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 memory + +import ( + "github.com/uber/jaeger-lib/metrics" + "go.uber.org/zap" + + "github.com/jaegertracing/jaeger/storage/dependencystore" + "github.com/jaegertracing/jaeger/storage/spanstore" +) + +// Factory implements storage.Factory and creates storage components backed by memory store. +type Factory struct { + metricsFactory metrics.Factory + logger *zap.Logger + store *Store +} + +// NewFactory creates a new Factory. +func NewFactory() *Factory { + return &Factory{} +} + +// Initialize implements storage.Factory +func (f *Factory) Initialize(metricsFactory metrics.Factory, logger *zap.Logger) error { + f.metricsFactory, f.logger = metricsFactory, logger + f.store = NewStore() + return nil +} + +// CreateSpanReader implements storage.Factory +func (f *Factory) CreateSpanReader() (spanstore.Reader, error) { + return f.store, nil +} + +// CreateSpanWriter implements storage.Factory +func (f *Factory) CreateSpanWriter() (spanstore.Writer, error) { + return f.store, nil +} + +// CreateDependencyReader implements storage.Factory +func (f *Factory) CreateDependencyReader() (dependencystore.Reader, error) { + return f.store, nil +} diff --git a/cmd/query/app/builder/memory_test.go b/plugin/storage/memory/factory_test.go similarity index 59% rename from cmd/query/app/builder/memory_test.go rename to plugin/storage/memory/factory_test.go index d95f35b9d58..a80156ccaeb 100644 --- a/cmd/query/app/builder/memory_test.go +++ b/plugin/storage/memory/factory_test.go @@ -12,20 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -package builder +package memory import ( "testing" "github.com/stretchr/testify/assert" - - "github.com/jaegertracing/jaeger/storage/spanstore/memory" ) -func TestMemoryStoreBuilder(t *testing.T) { - sb := newStorageBuilder() - memStore := memory.NewStore() - sb.newMemoryStoreBuilder(memStore) - assert.Equal(t, memStore, sb.SpanReader) - assert.Equal(t, memStore, sb.DependencyReader) +func TestMemoryStorageFactory(t *testing.T) { + f := NewFactory() + assert.NoError(t, f.Initialize(nil, nil)) + assert.NotNil(t, f.store) + reader, err := f.CreateSpanReader() + assert.NoError(t, err) + assert.Equal(t, f.store, reader) + writer, err := f.CreateSpanWriter() + assert.NoError(t, err) + assert.Equal(t, f.store, writer) + depReader, err := f.CreateDependencyReader() + assert.NoError(t, err) + assert.Equal(t, f.store, depReader) } diff --git a/storage/spanstore/memory/memory.go b/plugin/storage/memory/memory.go similarity index 100% rename from storage/spanstore/memory/memory.go rename to plugin/storage/memory/memory.go diff --git a/storage/spanstore/memory/memory_test.go b/plugin/storage/memory/memory_test.go similarity index 100% rename from storage/spanstore/memory/memory_test.go rename to plugin/storage/memory/memory_test.go diff --git a/storage/factory.go b/storage/factory.go new file mode 100644 index 00000000000..9228defbbec --- /dev/null +++ b/storage/factory.go @@ -0,0 +1,44 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// 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 storage + +import ( + "github.com/uber/jaeger-lib/metrics" + "go.uber.org/zap" + + "github.com/jaegertracing/jaeger/storage/dependencystore" + "github.com/jaegertracing/jaeger/storage/spanstore" +) + +// Factory defines an interface for a factory that can create implementations of different storage components. +// Implementations are also encouraged to implement plugin.Configurable interface. +// +// See also +// +// plugin.Configurable +type Factory interface { + // Initialize performs internal initialization of the factory, such as opening connections to the backend store. + // It is called after all configuration of the factory itself has been done. + Initialize(metricsFactory metrics.Factory, logger *zap.Logger) error + + // CreateSpanReader creates a spanstore.Reader. + CreateSpanReader() (spanstore.Reader, error) + + // CreateSpanWriter creates a spanstore.Writer. + CreateSpanWriter() (spanstore.Writer, error) + + // CreateDependencyReader creates a dependencystore.Reader. + CreateDependencyReader() (dependencystore.Reader, error) +}