Skip to content

Commit

Permalink
feat(jaeger-v2): Create default config for all-in-one (#4842)
Browse files Browse the repository at this point in the history
## Which problem is this PR solving?
In Jaeger V1 the all-in-one binary can be run without any arguments /
configuration, but since `jaeger-v2` is built on OTel Collector it
requires a config file. This is unnecessary friction for local /
development use of all-in-one.

## Description of the changes
- Allows all-in-one with memory storage to be run without any additional
config file
- Hardcodes a configuration in the code, relying on default
configuration from each component.

## How was this change tested?
- Ran locally
```
$ go run -tags=ui ./cmd/jaeger-v2
```

---------

Signed-off-by: Yuri Shkuro <github@ysh.us>
  • Loading branch information
yurishkuro authored Oct 15, 2023
1 parent 7ba0058 commit e0da3c9
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 15 deletions.
1 change: 1 addition & 0 deletions cmd/jaeger-v2/internal/all-in-one/.nocover
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
FIXME
133 changes: 133 additions & 0 deletions cmd/jaeger-v2/internal/all-in-one/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright (c) 2023 The Jaeger Authors.
// SPDX-License-Identifier: Apache-2.0

package allinone

import (
"context"
"fmt"
"time"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configtelemetry"
"go.opentelemetry.io/collector/otelcol"
"go.opentelemetry.io/collector/service"
"go.opentelemetry.io/collector/service/extensions"
"go.opentelemetry.io/collector/service/pipelines"
"go.opentelemetry.io/collector/service/telemetry"
"go.uber.org/zap/zapcore"

"github.com/jaegertracing/jaeger/cmd/jaeger-v2/internal/exporters/storageexporter"
"github.com/jaegertracing/jaeger/cmd/jaeger-v2/internal/extension/jaegerquery"
"github.com/jaegertracing/jaeger/cmd/jaeger-v2/internal/extension/jaegerstorage"
)

type configProvider struct {
watcher chan error
}

var _ otelcol.ConfigProvider = (*configProvider)(nil)

// NewConfigProvider creates a new ConfigProvider.
func NewConfigProvider() *configProvider {
return &configProvider{
watcher: make(chan error, 1),
}
}

func (cp *configProvider) Get(ctx context.Context, factories otelcol.Factories) (*otelcol.Config, error) {
cfg := &otelcol.Config{
Service: cp.makeServiceConfig(),
Extensions: make(map[component.ID]component.Config),
Receivers: make(map[component.ID]component.Config),
Processors: make(map[component.ID]component.Config),
Exporters: make(map[component.ID]component.Config),
}
defaultConfigs("extension", cfg.Service.Extensions, cfg.Extensions, factories.Extensions)
for _, pipeCfg := range cfg.Service.Pipelines {
defaultConfigs("receiver", pipeCfg.Receivers, cfg.Receivers, factories.Receivers)
defaultConfigs("processor", pipeCfg.Processors, cfg.Processors, factories.Processors)
defaultConfigs("exporter", pipeCfg.Exporters, cfg.Exporters, factories.Exporters)
}
return cfg, nil
}

func defaultConfigs[TFactory component.Factory](
componentType string,
comps []component.ID,
outCfg map[component.ID]component.Config,
factories map[component.Type]TFactory,
) error {
for _, compID := range comps {
f, ok := factories[compID.Type()]
if !ok {
return fmt.Errorf("no factory registered for %s %v", componentType, compID)
}
cfg := f.CreateDefaultConfig()
outCfg[compID] = cfg
}
return nil
}

// makeServiceConfig creates default config that contains
// all standard all-in-one extensions and pipelines.
func (cp *configProvider) makeServiceConfig() service.Config {
return service.Config{
Extensions: extensions.Config([]component.ID{
jaegerstorage.ID,
jaegerquery.ID,
}),
Pipelines: pipelines.Config(map[component.ID]*pipelines.PipelineConfig{
component.NewID("traces"): {
Receivers: []component.ID{
component.NewID("otlp"),
component.NewID("jaeger"),
component.NewID("zipkin"),
},
Processors: []component.ID{
component.NewID("batch"),
},
Exporters: []component.ID{
storageexporter.ID,
},
},
}),
// OTel Collector currently (v0.87) hardcodes telemetry settings, this is a copy.
// https://github.com/open-telemetry/opentelemetry-collector/blob/35512c466577036b0cc306673d2d4ad039c77f1c/otelcol/unmarshaler.go#L43
Telemetry: telemetry.Config{
Logs: telemetry.LogsConfig{
Level: zapcore.InfoLevel,
Development: false,
Encoding: "console",
Sampling: &telemetry.LogsSamplingConfig{
Enabled: true,
Tick: 10 * time.Second,
Initial: 10,
Thereafter: 100,
},
OutputPaths: []string{"stderr"},
ErrorOutputPaths: []string{"stderr"},
DisableCaller: false,
DisableStacktrace: false,
InitialFields: map[string]any(nil),
},
Metrics: telemetry.MetricsConfig{
Level: configtelemetry.LevelNone,
// Address: ":8888",
},
// TODO initialize tracer
},
}
}

// Watch implements otelcol.ConfigProvider.
// The returned channel is never written to, as there is no configuration to watch.
func (cp *configProvider) Watch() <-chan error {
return cp.watcher
}

// Shutdown implements otelcol.ConfigProvider.
func (cp *configProvider) Shutdown(ctx context.Context) error {
close(cp.watcher)
return nil
}
47 changes: 38 additions & 9 deletions cmd/jaeger-v2/internal/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ package internal

import (
"log"
"strings"

"github.com/spf13/cobra"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/otelcol"

allinone "github.com/jaegertracing/jaeger/cmd/jaeger-v2/internal/all-in-one"
"github.com/jaegertracing/jaeger/pkg/version"
)

Expand All @@ -21,20 +23,47 @@ func Command() *cobra.Command {
log.Fatalf("failed to build components: %v", err)
}

versionInfo := version.Get()

info := component.BuildInfo{
Command: "jaeger-v2",
Description: description,
Version: versionInfo.GitVersion,
Version: version.Get().String(),
}

settings := otelcol.CollectorSettings{
BuildInfo: info,
Factories: factories,
}

cmd := otelcol.NewCommand(
otelcol.CollectorSettings{
BuildInfo: info,
Factories: factories,
},
)
cmd := otelcol.NewCommand(settings)

// We want to support running the binary in all-in-one mode without a config file.
// Since there are no explicit hooks in OTel Collector for that today (as of v0.87),
// we intercept the official RunE implementation and check if any --config flags are
// present in the args. If not, we pass a custom ConfigProvider, and create the
// collector manually. Unfortunately, `set`(ings) is passed to NewCommand above
// by value, otherwise we could've overwritten it in the interceptor and then delegated
// back to the official RunE.
otelRunE := cmd.RunE
cmd.RunE = func(cmd *cobra.Command, args []string) error {
configProvided := false
for _, arg := range args {
if strings.HasPrefix(arg, "--config") {
configProvided = true
break
}
}
if configProvided {
return otelRunE(cmd, args)
}
log.Print("No '--config' flags detected, using default All-in-One configuration with memory storage.")
log.Print("To customize All-in-One behavior, pass a proper configuration.")
settings.ConfigProvider = allinone.NewConfigProvider()
col, err := otelcol.NewCollector(settings)
if err != nil {
return err
}
return col.Run(cmd.Context())
}

cmd.Short = description
cmd.Long = description
Expand Down
9 changes: 8 additions & 1 deletion cmd/jaeger-v2/internal/exporters/storageexporter/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ import (
"go.opentelemetry.io/collector/consumer"
"go.opentelemetry.io/collector/exporter"
"go.opentelemetry.io/collector/exporter/exporterhelper"

"github.com/jaegertracing/jaeger/cmd/jaeger-v2/internal/extension/jaegerstorage"
)

// componentType is the name of this extension in configuration.
const componentType = component.Type("jaeger_storage_exporter")

// ID is the identifier of this extension.
var ID = component.NewID(componentType)

// NewFactory creates a factory for jaeger_storage_exporter.
func NewFactory() exporter.Factory {
return exporter.NewFactory(
Expand All @@ -25,7 +30,9 @@ func NewFactory() exporter.Factory {
}

func createDefaultConfig() component.Config {
return &Config{}
return &Config{
TraceStorage: jaegerstorage.DefaultMemoryStore,
}
}

func createTracesExporter(ctx context.Context, set exporter.CreateSettings, config component.Config) (exporter.Traces, error) {
Expand Down
5 changes: 5 additions & 0 deletions cmd/jaeger-v2/internal/extension/jaegerquery/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,23 @@ import (
"go.opentelemetry.io/collector/config/confighttp"
"go.opentelemetry.io/collector/extension"

"github.com/jaegertracing/jaeger/cmd/jaeger-v2/internal/extension/jaegerstorage"
"github.com/jaegertracing/jaeger/ports"
)

// componentType is the name of this extension in configuration.
const componentType = component.Type("jaeger_query")

// ID is the identifier of this extension.
var ID = component.NewID(componentType)

func NewFactory() extension.Factory {
return extension.NewFactory(componentType, createDefaultConfig, createExtension, component.StabilityLevelBeta)
}

func createDefaultConfig() component.Config {
return &Config{
TraceStorage: jaegerstorage.DefaultMemoryStore,
HTTPServerSettings: confighttp.HTTPServerSettings{
Endpoint: ports.PortToHostPort(ports.QueryHTTP),
},
Expand Down
22 changes: 19 additions & 3 deletions cmd/jaeger-v2/internal/extension/jaegerstorage/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,20 @@ import (

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/extension"

memoryCfg "github.com/jaegertracing/jaeger/pkg/memory/config"
)

const (
// componentType is the name of this extension in configuration.
componentType = component.Type("jaeger_storage")

// DefaultMemoryStore is the name of the memory storage included in the default configuration.
DefaultMemoryStore = "memstore"
)

// componentType is the name of this extension in configuration.
const componentType = component.Type("jaeger_storage")
// ID is the identifier of this extension.
var ID = component.NewID(componentType)

func NewFactory() extension.Factory {
return extension.NewFactory(
Expand All @@ -23,7 +33,13 @@ func NewFactory() extension.Factory {
}

func createDefaultConfig() component.Config {
return &Config{}
return &Config{
Memory: map[string]memoryCfg.Configuration{
DefaultMemoryStore: {
MaxTraces: 100_000,
},
},
}
}

// createExtension creates the extension based on this config.
Expand Down
2 changes: 1 addition & 1 deletion pkg/version/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func NewInfoMetrics(metricsFactory metrics.Factory) *InfoMetrics {

func (i Info) String() string {
return fmt.Sprintf(
"application version: git-commit=%s, git-version=%s, build-date=%s",
"git-commit=%s, git-version=%s, build-date=%s",
i.GitCommit, i.GitVersion, i.BuildDate,
)
}
2 changes: 1 addition & 1 deletion pkg/version/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
// Command creates version command
func Command() *cobra.Command {
info := Get()
log.Println(info)
log.Println("applicatio version:", info)
return &cobra.Command{
Use: "version",
Short: "Print the version.",
Expand Down

0 comments on commit e0da3c9

Please sign in to comment.