opentelemetry-collector/service/internal/builder/extensions_builder.go

170 lines
4.6 KiB
Go

// Copyright The OpenTelemetry 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 builder
import (
"context"
"fmt"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config"
"go.opentelemetry.io/collector/consumer/consumererror"
)
// builtExporter is an exporter that is built based on a config. It can have
// a trace and/or a metrics consumer and have a shutdown function.
type builtExtension struct {
logger *zap.Logger
extension component.Extension
}
// Start the receiver.
func (ext *builtExtension) Start(ctx context.Context, host component.Host) error {
return ext.extension.Start(ctx, host)
}
// Shutdown the receiver.
func (ext *builtExtension) Shutdown(ctx context.Context) error {
return ext.extension.Shutdown(ctx)
}
var _ component.Extension = (*builtExtension)(nil)
// Extensions is a map of extensions created from extension configs.
type Extensions map[config.Extension]*builtExtension
// StartAll starts all exporters.
func (exts Extensions) StartAll(ctx context.Context, host component.Host) error {
for _, ext := range exts {
ext.logger.Info("Extension is starting...")
if err := ext.Start(ctx, newHostWrapper(host, ext.logger)); err != nil {
return err
}
ext.logger.Info("Extension started.")
}
return nil
}
// ShutdownAll stops all exporters.
func (exts Extensions) ShutdownAll(ctx context.Context) error {
var errs []error
for _, ext := range exts {
err := ext.Shutdown(ctx)
if err != nil {
errs = append(errs, err)
}
}
return consumererror.Combine(errs)
}
func (exts Extensions) NotifyPipelineReady() error {
for _, ext := range exts {
if pw, ok := ext.extension.(component.PipelineWatcher); ok {
if err := pw.Ready(); err != nil {
ext.logger.Error("Error notifying extension that the pipeline was started.")
return err
}
}
}
return nil
}
func (exts Extensions) NotifyPipelineNotReady() error {
// Notify extensions in reverse order.
var errs []error
for _, ext := range exts {
if pw, ok := ext.extension.(component.PipelineWatcher); ok {
if err := pw.NotReady(); err != nil {
ext.logger.Error("Error notifying extension that the pipeline was shutdown.")
errs = append(errs, err)
}
}
}
return consumererror.Combine(errs)
}
func (exts Extensions) ToMap() map[config.ComponentID]component.Extension {
result := make(map[config.ComponentID]component.Extension, len(exts))
for k, v := range exts {
result[k.ID()] = v.extension
}
return result
}
// BuildExtensions builds Extensions from config.
func BuildExtensions(
logger *zap.Logger,
tracerProvider trace.TracerProvider,
buildInfo component.BuildInfo,
config *config.Config,
factories map[config.Type]component.ExtensionFactory,
) (Extensions, error) {
logger = logger.With(zap.String(zapKindKey, zapKindExtension))
extensions := make(Extensions)
for _, extName := range config.Service.Extensions {
extCfg, exists := config.Extensions[extName]
if !exists {
return nil, fmt.Errorf("extension %q is not configured", extName)
}
set := component.ExtensionCreateSettings{
Logger: logger.With(zap.Stringer(zapNameKey, extCfg.ID())),
TracerProvider: tracerProvider,
BuildInfo: buildInfo,
}
ext, err := buildExtension(context.Background(), factories, set, extCfg)
if err != nil {
return nil, err
}
extensions[extCfg] = ext
}
return extensions, nil
}
func buildExtension(ctx context.Context, factories map[config.Type]component.ExtensionFactory, creationSet component.ExtensionCreateSettings, cfg config.Extension) (*builtExtension, error) {
factory := factories[cfg.ID().Type()]
if factory == nil {
return nil, fmt.Errorf("extension factory for type %q is not configured", cfg.ID().Type())
}
ext := &builtExtension{
logger: creationSet.Logger,
}
ex, err := factory.CreateExtension(ctx, creationSet, cfg)
if err != nil {
return nil, fmt.Errorf("failed to create extension %v: %w", cfg.ID(), err)
}
// Check if the factory really created the extension.
if ex == nil {
return nil, fmt.Errorf("factory for %v produced a nil extension", cfg.ID())
}
ext.extension = ex
return ext, nil
}