mirror of
https://github.com/hanzoai/telemetry.git
synced 2026-10-30 20:01:49 +00:00
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [golang.org/x/mod](https://pkg.go.dev/golang.org/x/mod) | [`v0.34.0` → `v0.35.0`](https://cs.opensource.google/go/x/mod/+/refs/tags/v0.34.0...refs/tags/v0.35.0) |  |  | | [golang.org/x/net](https://pkg.go.dev/golang.org/x/net) | [`v0.52.0` → `v0.53.0`](https://cs.opensource.google/go/x/net/+/refs/tags/v0.52.0...refs/tags/v0.53.0) |  |  | | [golang.org/x/sys](https://pkg.go.dev/golang.org/x/sys) | [`v0.42.0` → `v0.43.0`](https://cs.opensource.google/go/x/sys/+/refs/tags/v0.42.0...refs/tags/v0.43.0) |  |  | | [golang.org/x/text](https://pkg.go.dev/golang.org/x/text) | [`v0.35.0` → `v0.36.0`](https://cs.opensource.google/go/x/text/+/refs/tags/v0.35.0...refs/tags/v0.36.0) |  |  | | [golang.org/x/tools](https://pkg.go.dev/golang.org/x/tools) | [`v0.43.0` → `v0.44.0`](https://cs.opensource.google/go/x/tools/+/refs/tags/v0.43.0...refs/tags/v0.44.0) |  |  | | [golang.org/x/vuln](https://pkg.go.dev/golang.org/x/vuln) | [`v1.1.4` → `v1.2.0`](https://cs.opensource.google/go/x/vuln/+/refs/tags/v1.1.4...refs/tags/v1.2.0) |  |  | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/8903) for more information. --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "on tuesday" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/open-telemetry/opentelemetry-collector). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMTAuMiIsInVwZGF0ZWRJblZlciI6IjQzLjExMC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiLCJyZW5vdmF0ZWJvdCJdfQ==--> --------- Signed-off-by: Alex Boten <[email protected]> Co-authored-by: Hanzo Dev <[email protected]> Co-authored-by: otelbot <[email protected]> Co-authored-by: Alex Boten <[email protected]> Co-authored-by: Yang Song <[email protected]>
240 lines
7.0 KiB
Go
240 lines
7.0 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package extensions // import "go.opentelemetry.io/collector/service/extensions"
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"slices"
|
|
"sort"
|
|
|
|
"go.uber.org/multierr"
|
|
"go.uber.org/zap"
|
|
|
|
"go.opentelemetry.io/collector/component"
|
|
"go.opentelemetry.io/collector/component/componentstatus"
|
|
"go.opentelemetry.io/collector/confmap"
|
|
"go.opentelemetry.io/collector/extension"
|
|
"go.opentelemetry.io/collector/extension/extensioncapabilities"
|
|
"go.opentelemetry.io/collector/service/internal/attribute"
|
|
"go.opentelemetry.io/collector/service/internal/builders"
|
|
"go.opentelemetry.io/collector/service/internal/componentattribute"
|
|
"go.opentelemetry.io/collector/service/internal/status"
|
|
"go.opentelemetry.io/collector/service/internal/zpages"
|
|
)
|
|
|
|
const zExtensionName = "zextensionname"
|
|
|
|
// Extensions is a map of extensions created from extension configs.
|
|
type Extensions struct {
|
|
telemetry component.TelemetrySettings
|
|
extMap map[component.ID]extension.Extension
|
|
instanceIDs map[component.ID]*componentstatus.InstanceID
|
|
extensionIDs []component.ID // start order (and reverse stop order)
|
|
reporter status.Reporter
|
|
}
|
|
|
|
// Start starts all extensions.
|
|
func (bes *Extensions) Start(ctx context.Context, host component.Host) error {
|
|
bes.telemetry.Logger.Info("Starting extensions...")
|
|
for _, extID := range bes.extensionIDs {
|
|
extLogger := componentattribute.LoggerWithAttributes(bes.telemetry.Logger,
|
|
attribute.Extension(extID).Set().ToSlice())
|
|
extLogger.Info("Extension is starting...")
|
|
instanceID := bes.instanceIDs[extID]
|
|
ext := bes.extMap[extID]
|
|
bes.reporter.ReportStatus(
|
|
instanceID,
|
|
componentstatus.NewEvent(componentstatus.StatusStarting),
|
|
)
|
|
if err := ext.Start(ctx, host); err != nil {
|
|
bes.reporter.ReportStatus(
|
|
instanceID,
|
|
componentstatus.NewPermanentErrorEvent(err),
|
|
)
|
|
// We log with zap.AddStacktrace(zap.DPanicLevel) to avoid adding the stack trace to the error log
|
|
extLogger.WithOptions(zap.AddStacktrace(zap.DPanicLevel)).Error("Failed to start extension", zap.Error(err))
|
|
return err
|
|
}
|
|
bes.reporter.ReportOKIfStarting(instanceID)
|
|
extLogger.Info("Extension started.")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Shutdown stops all extensions.
|
|
func (bes *Extensions) Shutdown(ctx context.Context) error {
|
|
bes.telemetry.Logger.Info("Stopping extensions...")
|
|
var errs error
|
|
for _, extID := range slices.Backward(bes.extensionIDs) {
|
|
instanceID := bes.instanceIDs[extID]
|
|
ext := bes.extMap[extID]
|
|
bes.reporter.ReportStatus(
|
|
instanceID,
|
|
componentstatus.NewEvent(componentstatus.StatusStopping),
|
|
)
|
|
if err := ext.Shutdown(ctx); err != nil {
|
|
bes.reporter.ReportStatus(
|
|
instanceID,
|
|
componentstatus.NewPermanentErrorEvent(err),
|
|
)
|
|
errs = multierr.Append(errs, err)
|
|
continue
|
|
}
|
|
bes.reporter.ReportStatus(
|
|
instanceID,
|
|
componentstatus.NewEvent(componentstatus.StatusStopped),
|
|
)
|
|
}
|
|
|
|
return errs
|
|
}
|
|
|
|
func (bes *Extensions) NotifyPipelineReady() error {
|
|
for _, extID := range bes.extensionIDs {
|
|
ext := bes.extMap[extID]
|
|
if pw, ok := ext.(extensioncapabilities.PipelineWatcher); ok {
|
|
if err := pw.Ready(); err != nil {
|
|
return fmt.Errorf("failed to notify extension %q: %w", extID, err)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (bes *Extensions) NotifyPipelineNotReady() error {
|
|
var errs error
|
|
for _, extID := range bes.extensionIDs {
|
|
ext := bes.extMap[extID]
|
|
if pw, ok := ext.(extensioncapabilities.PipelineWatcher); ok {
|
|
errs = multierr.Append(errs, pw.NotReady())
|
|
}
|
|
}
|
|
return errs
|
|
}
|
|
|
|
func (bes *Extensions) NotifyConfig(ctx context.Context, conf *confmap.Conf) error {
|
|
var errs error
|
|
for _, extID := range bes.extensionIDs {
|
|
ext := bes.extMap[extID]
|
|
if cw, ok := ext.(extensioncapabilities.ConfigWatcher); ok {
|
|
clonedConf := confmap.NewFromStringMap(conf.ToStringMap())
|
|
errs = multierr.Append(errs, cw.NotifyConfig(ctx, clonedConf))
|
|
}
|
|
}
|
|
return errs
|
|
}
|
|
|
|
func (bes *Extensions) NotifyComponentStatusChange(source *componentstatus.InstanceID, event *componentstatus.Event) {
|
|
for _, extID := range bes.extensionIDs {
|
|
ext := bes.extMap[extID]
|
|
if sw, ok := ext.(componentstatus.Watcher); ok {
|
|
sw.ComponentStatusChanged(source, event)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (bes *Extensions) GetExtensions() map[component.ID]component.Component {
|
|
result := make(map[component.ID]component.Component, len(bes.extMap))
|
|
for extID, v := range bes.extMap {
|
|
result[extID] = v
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (bes *Extensions) HandleZPages(w http.ResponseWriter, r *http.Request) {
|
|
extensionName := r.URL.Query().Get(zExtensionName)
|
|
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
zpages.WriteHTMLPageHeader(w, zpages.HeaderData{Title: "Extensions"})
|
|
data := zpages.SummaryExtensionsTableData{}
|
|
|
|
data.Rows = make([]zpages.SummaryExtensionsTableRowData, 0, len(bes.extMap))
|
|
for _, id := range bes.extensionIDs {
|
|
row := zpages.SummaryExtensionsTableRowData{FullName: id.String()}
|
|
data.Rows = append(data.Rows, row)
|
|
}
|
|
|
|
sort.Slice(data.Rows, func(i, j int) bool {
|
|
return data.Rows[i].FullName < data.Rows[j].FullName
|
|
})
|
|
zpages.WriteHTMLExtensionsSummaryTable(w, data)
|
|
if extensionName != "" {
|
|
zpages.WriteHTMLComponentHeader(w, zpages.ComponentHeaderData{
|
|
Name: extensionName,
|
|
})
|
|
// TODO: Add config + status info.
|
|
}
|
|
zpages.WriteHTMLPageFooter(w)
|
|
}
|
|
|
|
// Settings holds configuration for building Extensions.
|
|
type Settings struct {
|
|
Telemetry component.TelemetrySettings
|
|
BuildInfo component.BuildInfo
|
|
|
|
// Extensions builder for extensions.
|
|
Extensions builders.Extension
|
|
}
|
|
|
|
type Option interface {
|
|
apply(*Extensions)
|
|
}
|
|
|
|
type optionFunc func(*Extensions)
|
|
|
|
func (of optionFunc) apply(e *Extensions) {
|
|
of(e)
|
|
}
|
|
|
|
func WithReporter(reporter status.Reporter) Option {
|
|
return optionFunc(func(e *Extensions) {
|
|
e.reporter = reporter
|
|
})
|
|
}
|
|
|
|
// New creates a new Extensions from Config.
|
|
func New(ctx context.Context, set Settings, cfg Config, options ...Option) (*Extensions, error) {
|
|
exts := &Extensions{
|
|
telemetry: set.Telemetry,
|
|
extMap: make(map[component.ID]extension.Extension),
|
|
instanceIDs: make(map[component.ID]*componentstatus.InstanceID),
|
|
extensionIDs: make([]component.ID, 0, len(cfg)),
|
|
reporter: status.NewNopStatusReporter(),
|
|
}
|
|
|
|
for _, opt := range options {
|
|
opt.apply(exts)
|
|
}
|
|
|
|
for _, extID := range cfg {
|
|
instanceID := componentstatus.NewInstanceID(extID, component.KindExtension)
|
|
extSet := extension.Settings{
|
|
ID: extID,
|
|
TelemetrySettings: componentattribute.TelemetrySettingsWithAttributes(set.Telemetry, *attribute.Extension(extID).Set()),
|
|
BuildInfo: set.BuildInfo,
|
|
}
|
|
|
|
ext, err := set.Extensions.Create(ctx, extSet)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create extension %q: %w", extID, err)
|
|
}
|
|
|
|
// Check if the factory really created the extension.
|
|
if ext == nil {
|
|
return nil, fmt.Errorf("factory for %q produced a nil extension", extID)
|
|
}
|
|
|
|
exts.extMap[extID] = ext
|
|
exts.instanceIDs[extID] = instanceID
|
|
}
|
|
order, err := computeOrder(exts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
exts.extensionIDs = order
|
|
return exts, nil
|
|
}
|