Skip to content

[scraperhelper] Add extension-based scraper controller support#15116

Open
axw wants to merge 23 commits into
open-telemetry:mainfrom
axw:extensionscrapercontroller
Open

[scraperhelper] Add extension-based scraper controller support#15116
axw wants to merge 23 commits into
open-telemetry:mainfrom
axw:extensionscrapercontroller

Conversation

@axw

@axw axw commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Description

Implement the extensionscrapercontroller package and integrate it with the scraper controller, allowing extensions to trigger scrapes based on external events instead of (or in addition to) a fixed timer interval.

  • Add extensionscrapercontroller.ControllerExtension interface and DeregisterFunc helper in extension/xextension/extensionscrapercontroller
  • Add Controllers field to ControllerConfig for specifying extension IDs
  • Allow CollectionInterval=0 when Controllers are configured
  • Register scrapers with controller extensions on Start, deregister on Shutdown
  • Update RFC to remove scraperID parameter from RegisterScraper, and only disable ticker on zero interval (negative interval is now rejected as before)

Assisted-by: Claude Opus 4.5

Link to tracking issue

Closes #12449

Testing

Tests added.

Documentation

https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/rfcs/scraper-controller-extension.md

@axw
axw force-pushed the extensionscrapercontroller branch from 43fa995 to e904e60 Compare April 15, 2026 03:25
@codspeed-hq

codspeed-hq Bot commented Apr 15, 2026

Copy link
Copy Markdown

Merging this PR will create unknown performance changes

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

⏩ 4 skipped benchmarks1
🗄️ 2 archived benchmarks run2


Comparing axw:extensionscrapercontroller (808e47d) with main (60a4f0b)

Open in CodSpeed

Footnotes

  1. 4 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. 2 benchmarks were run, but are now archived. If they were deleted in another branch, consider rebasing to remove them from the report. Instead if they were added back, click here to restore them.

@codecov

codecov Bot commented Apr 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.12%. Comparing base (60a4f0b) to head (808e47d).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #15116      +/-   ##
==========================================
+ Coverage   91.09%   91.12%   +0.02%     
==========================================
  Files         725      725              
  Lines       48066    48133      +67     
==========================================
+ Hits        43788    43861      +73     
+ Misses       2979     2975       -4     
+ Partials     1299     1297       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@axw
axw force-pushed the extensionscrapercontroller branch 2 times, most recently from ffacd96 to e6602b9 Compare April 15, 2026 06:27
axw added a commit to axw/opentelemetry-collector that referenced this pull request Apr 16, 2026
Add tests to the internal/controller package, so we have baseline
coverage before making the changes in
open-telemetry#15116.
github-merge-queue Bot pushed a commit that referenced this pull request Apr 17, 2026
#### Description

Add tests to the internal/controller package, so we have baseline
coverage before making the changes in
#15116.

#### Link to tracking issue

N/A

#### Testing

Yes

#### Documentation

No

Co-authored-by: Alex Boten <223565+codeboten@users.noreply.github.com>
@axw
axw force-pushed the extensionscrapercontroller branch 3 times, most recently from 3aa92a2 to 8aef2b0 Compare April 24, 2026 05:47
codeboten added a commit to codeboten/opentelemetry-collector that referenced this pull request Apr 24, 2026
#### Description

Various changes to newTestController to simplify tests:
- newTestController no longer accepts a ticker, it always calls
NewController with a nil ticker so one is created internally; the tests
now use synctest where relevant.
- newTestController no longer conditionally creates a no-op scrapeFunc,
we introduce a nopScrapeFunc function and update relevant tests to pass
it in.
- scrapers has been made the final parameter, and is now variadic. Tests
no longer need to explicitly create a slice.

TestStartScrapingWithNilTickerCh has been removed, since that is now
covered by the use of synctest.

Several tests has been updated to use newTestController rather than
calling NewController directly.

#### Link to tracking issue

Prep for
open-telemetry#15116
(trying to cut the diff down)

#### Testing

Yes

#### Documentation

No

Co-authored-by: Alex Boten <223565+codeboten@users.noreply.github.com>
@axw
axw force-pushed the extensionscrapercontroller branch from 8aef2b0 to 7a80b44 Compare April 28, 2026 08:29
Implement the extensionscrapercontroller package and integrate it with
the scraper controller, allowing extensions to trigger scrapes based on
external events instead of (or in addition to) a fixed timer interval.

- Add extensionscrapercontroller.ControllerExtension interface and
  DeregisterFunc helper in extension/xextension/extensionscrapercontroller
- Add Controllers field to ControllerConfig for specifying extension IDs
- Allow CollectionInterval=0 when Controllers are configured
- Register scrapers with controller extensions on Start, deregister on
  Shutdown
- Update RFC to remove scraperID parameter from RegisterScraper

Assisted-by: Claude Opus 4.5
@axw
axw force-pushed the extensionscrapercontroller branch from 7a80b44 to e126197 Compare April 30, 2026 07:59
@axw
axw marked this pull request as ready for review April 30, 2026 08:58
@axw
axw requested review from a team, bogdandrutu, codeboten, dmitryax and mx-psi as code owners April 30, 2026 08:58
@github-actions

Copy link
Copy Markdown
Contributor

This PR was marked stale due to lack of activity. It will be closed in 14 days.

@github-actions github-actions Bot added Stale and removed Stale labels May 19, 2026
Comment thread extension/xextension/extensionscrapercontroller/extensionscrapercontroller.go Outdated

// RegistrationHandle is returned by ControllerExtension.RegisterScraper and
// is used to deregister the scraper during shutdown.
type RegistrationHandle interface {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest making this a closed interface so that you can add methods in the future, with a constructor method (as described in the RFC)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. I think that makes sense for something like Factory, which is a collection of methods. This interface is more akin to io.Reader, i.e. it has a singular purpose, so I don't think expanding methods is realistic.

Perhaps I should just make it a function type, so RegisterScraper becomes:

RegisterScraper(context.Context, ScrapeFunc) (DeregisterFunc, error)

WDYT?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made this change, can easily revert if you're against it

Comment thread scraper/scraperhelper/internal/controller/controller.go
Comment thread scraper/scraperhelper/internal/controller/config.go Outdated
Comment thread scraper/scraperhelper/internal/controller/controller.go Outdated
axw added 3 commits May 27, 2026 10:01
- Create ScrapeFunc type
- Replace RegistrationHandle type with DeregisterFunc type
- Update collection_interval error message per review
axw added 8 commits May 27, 2026 15:52
- Fix timeout validation error message
- Capture deregistration errors
- Call host.GetExtensions() outside loop
- Deregister extensions concurrently in Shutdown so total wait time is
  bounded by the slowest single extension, not the sum of all
- Capture scraper Shutdown errors in Start's failure-cleanup defer
  instead of silently discarding them
- Fix TestStartScrapingNoCollectionInterval to use a valid config
  (zero CollectionInterval requires at least one controller)
- Move MockHost and MockControllerExtension to internal/testhelper,
  eliminating the duplicate definitions across the two test packages;
  the shared mock correctly blocks DeregisterFunc on in-flight scrapes

Assisted-by: Claude Sonnet 4.6
…el teardown

- Document that RegisterScraper must return a non-nil DeregisterFunc when
  err is nil; add defensive nil guard in teardown
- Fix TOCTOU race in MockControllerExtension.Scrape: hold mu across the
  nil/deregistered check and scrapeWG.Add so DeregisterFunc cannot observe
  a zero count between the two
- Extract shared teardown helper used by both Start cleanup and Shutdown:
  deregisters extensions and shuts down scrapers concurrently, clearing
  deregFuncs first to prevent double-invocation
- Fix TestShutdownScrapers: protect shared slice with mutex and use
  ElementsMatch since scraper shutdown order is now non-deterministic

Assisted-by: Claude Sonnet 4.6
Not quite right, but not worth the hassle of breaking contrib tests.
@axw
axw requested a review from jmacd May 28, 2026 03:37
@github-actions

Copy link
Copy Markdown
Contributor

This PR was marked stale due to lack of activity. It will be closed in 14 days.

@github-actions github-actions Bot added the Stale label Jun 14, 2026
@jmacd jmacd removed the Stale label Jun 17, 2026
})
}
wg.Wait()
for _, scrp := range scrapers {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we guard this in a similar way to deregFuncs so we don't call Shutdown twice? (It could happen if Start fails since we call Shutdown in that case

if err = col.service.Start(ctx); err != nil {
return multierr.Combine(err, col.service.Shutdown(ctx))
)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On main we only ever shutdown the scrapers when the controller's Shutdown method is called, and not on when Start fails. I'll revert to that for scrapers, and only call deregFuncs when Start fails, so that there's nothing actively scraping after Start returns an error.

@axw
axw requested a review from mx-psi July 13, 2026 09:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for external scheduling of scraper receivers

5 participants