mirror of
https://github.com/hanzoai/telemetry.git
synced 2026-10-30 20:01:49 +00:00
#### Description Change the scraper controller's scrapeFunc signature to accept a context and return an error. This is preparation for scraper controller extensions (#12449). NewController wraps the user-supplied scrapeFunc to apply Timeout to the incoming context when non-zero, so scrapeMetrics/scrapeLogs/ scrapeProfiles no longer build their own context, and WithScrapeContext is removed. Scraper and consumer errors are now returned. The timer path discards the returned error, preserving existing behavior. #### Link to tracking issue Relates to https://github.com/open-telemetry/opentelemetry-collector/issues/12449 #### Testing Unit tests updated #### Documentation N/A --------- Co-authored-by: Florian Lehner <[email protected]> Co-authored-by: Alex Boten <[email protected]>
143 lines
3.5 KiB
Go
143 lines
3.5 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// package controller provides functionality used in scraperhelper and xscraperhelper.
|
|
|
|
package controller // import "go.opentelemetry.io/collector/scraper/scraperhelper/internal/controller"
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
|
|
"go.uber.org/multierr"
|
|
"go.uber.org/zap"
|
|
|
|
"go.opentelemetry.io/collector/component"
|
|
"go.opentelemetry.io/collector/receiver"
|
|
"go.opentelemetry.io/collector/receiver/receiverhelper"
|
|
"go.opentelemetry.io/collector/scraper"
|
|
)
|
|
|
|
type Controller[T component.Component] struct {
|
|
collectionInterval time.Duration
|
|
initialDelay time.Duration
|
|
Timeout time.Duration
|
|
|
|
Scrapers []T
|
|
scrapeFunc func(context.Context, *Controller[T]) error
|
|
tickerCh <-chan time.Time
|
|
|
|
done chan struct{}
|
|
wg sync.WaitGroup
|
|
|
|
Obsrecv *receiverhelper.ObsReport
|
|
}
|
|
|
|
func NewController[T component.Component](
|
|
cfg *ControllerConfig,
|
|
rSet receiver.Settings,
|
|
scrapers []T,
|
|
scrapeFunc func(context.Context, *Controller[T]) error,
|
|
tickerCh <-chan time.Time,
|
|
) (*Controller[T], error) {
|
|
obsrecv, err := receiverhelper.NewObsReport(receiverhelper.ObsReportSettings{
|
|
ReceiverID: rSet.ID,
|
|
Transport: "",
|
|
ReceiverCreateSettings: rSet,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cs := &Controller[T]{
|
|
collectionInterval: cfg.CollectionInterval,
|
|
initialDelay: cfg.InitialDelay,
|
|
Timeout: cfg.Timeout,
|
|
Scrapers: scrapers,
|
|
scrapeFunc: scrapeFunc,
|
|
done: make(chan struct{}),
|
|
tickerCh: tickerCh,
|
|
Obsrecv: obsrecv,
|
|
}
|
|
|
|
if cfg.Timeout > 0 {
|
|
cs.scrapeFunc = func(ctx context.Context, c *Controller[T]) error {
|
|
ctx, cancel := context.WithTimeout(ctx, cfg.Timeout)
|
|
defer cancel()
|
|
return scrapeFunc(ctx, c)
|
|
}
|
|
}
|
|
|
|
return cs, nil
|
|
}
|
|
|
|
// Start the receiver, invoked during service start.
|
|
func (sc *Controller[T]) Start(ctx context.Context, host component.Host) error {
|
|
for _, scrp := range sc.Scrapers {
|
|
if err := scrp.Start(ctx, host); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
sc.startScraping()
|
|
return nil
|
|
}
|
|
|
|
// Shutdown the receiver, invoked during service shutdown.
|
|
func (sc *Controller[T]) Shutdown(ctx context.Context) error {
|
|
// Signal the goroutine to stop.
|
|
close(sc.done)
|
|
sc.wg.Wait()
|
|
var errs error
|
|
for _, scrp := range sc.Scrapers {
|
|
errs = multierr.Append(errs, scrp.Shutdown(ctx))
|
|
}
|
|
|
|
return errs
|
|
}
|
|
|
|
// startScraping initiates a ticker that calls Scrape based on the configured
|
|
// collection interval.
|
|
func (sc *Controller[T]) startScraping() {
|
|
sc.wg.Go(func() {
|
|
if sc.initialDelay > 0 {
|
|
select {
|
|
case <-time.After(sc.initialDelay):
|
|
case <-sc.done:
|
|
return
|
|
}
|
|
}
|
|
|
|
if sc.tickerCh == nil {
|
|
ticker := time.NewTicker(sc.collectionInterval)
|
|
defer ticker.Stop()
|
|
|
|
sc.tickerCh = ticker.C
|
|
}
|
|
// Call scrape method during initialization to ensure
|
|
// that scrapers start from when the component starts
|
|
// instead of waiting for the full duration to start.
|
|
_ = sc.scrapeFunc(context.Background(), sc)
|
|
for {
|
|
select {
|
|
case <-sc.tickerCh:
|
|
_ = sc.scrapeFunc(context.Background(), sc)
|
|
case <-sc.done:
|
|
return
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func GetSettings(sType component.Type, rSet receiver.Settings) scraper.Settings {
|
|
id := component.NewID(sType)
|
|
telemetry := rSet.TelemetrySettings
|
|
telemetry.Logger = telemetry.Logger.With(zap.String("scraper", id.String()))
|
|
return scraper.Settings{
|
|
ID: id,
|
|
TelemetrySettings: telemetry,
|
|
BuildInfo: rSet.BuildInfo,
|
|
}
|
|
}
|