feat: Oracle exporter can scrape more than one DB#6008
Conversation
|
💻 Deploy preview available (feat: Oracle exporter can scrape more than one DB): |
.github/workflows/build.yml
Outdated
| # TODO: Try enabling caching later. It might use up too much disk space on runners so needs extra testing. | ||
| cache: false | ||
| - run: GO_TAGS="embedalloyui promtail_journal_enabled" GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} GOARM= make alloy | ||
| - run: GO_TAGS="embedalloyui promtail_journal_enabled godror" GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} GOARM= make alloy |
There was a problem hiding this comment.
I opened an upstream PR for this tag to not be necessary.
There was a problem hiding this comment.
Would we always build and run test with this tag?
Maybe we could just append it to GO_TAGS in our make file and make sure everything pass those tags, like integration tests etc. Then we don't have to do it for every workflow, WDYT?
There was a problem hiding this comment.
In the future we can switch to a different driver (go ora) which would mean Alloy no longer needs the Oracle Client to be installed. I opened an issue for it - #6011
There was a problem hiding this comment.
Would we always build and run test with this tag?
Yes, until the next version of the exporter is released. My upstream PR to not require tag by default was merged. I hope there will be a new release soon - when we upgrade to it, we can delete this tag.
I opened an issue upstream to make the driver configurable in a more flexible way, without build tags. If this happens we can also make a new driver config attribute for people who want to choose the more basic driver that doesn't need an Instant Client installation.
we could just append it to GO_TAGS in our make file
True! I updated the PR to only do this amendment in the makefile. The changes to Actions workflows have been reverted.
🔍 Dependency ReviewBelow is an assessment of each changed dependency in the PR, with required code updates (if any), linked evidence, and concise diffs where appropriate.
github.com/oracle/oracle-db-appdev-monitoring v0.0.0-20250516154730-1d8025fde3b0 -> v0.0.0-20260323143131-1e9bbcecf9eb — ❌ Changes NeededImpact
Evidence
Key API/Behavior Changes to Apply (already applied in this PR)
Code update: - oeExporter, err := oe.NewExporter(slogLogger, &oe.MetricsConfiguration{
- Databases: map[string]oe.DatabaseConfig{ ... },
- Metrics: oe.MetricsFilesConfig{
- Custom: c.CustomMetrics,
- Default: c.DefaultMetrics,
- },
- })
- if err != nil { return nil, err }
+ scrapeInterval := time.Duration(0)
+ oeExporter := oe.NewExporter(slogLogger, &oe.MetricsConfiguration{
+ Databases: databases, // built with ConnectConfig pointer fields
+ Metrics: oe.MetricsFilesConfig{
+ Custom: c.CustomMetrics,
+ Default: c.DefaultMetrics,
+ ScrapeInterval: &scrapeInterval,
+ },
+ })
+ if oeExporter == nil {
+ return nil, errors.New("failed to create oracledb exporter")
+ }
Code update: - ConnectConfig: oe.ConnectConfig{
- MaxIdleConns: c.MaxIdleConns,
- MaxOpenConns: c.MaxOpenConns,
- QueryTimeout: c.QueryTimeout,
- },
+ ConnectConfig: oe.ConnectConfig{
+ MaxIdleConns: ptr.To(c.MaxIdleConns),
+ MaxOpenConns: ptr.To(c.MaxOpenConns),
+ QueryTimeout: ptr.To(c.QueryTimeout),
+ },
Code updates (component): type DatabaseTarget struct {
Name string `alloy:"name,attr"`
ConnectionString alloytypes.Secret `alloy:"connection_string,attr"`
Username string `alloy:"username,attr,optional"`
Password alloytypes.Secret `alloy:"password,attr,optional"`
Labels map[string]string `alloy:"labels,attr,optional"`
}
type Arguments struct {
- ConnectionString alloytypes.Secret `alloy:"connection_string,attr"`
+ ConnectionString alloytypes.Secret `alloy:"connection_string,attr,optional"` // Deprecated
...
- Username string `alloy:"username,attr,optional"`
- Password alloytypes.Secret `alloy:"password,attr,optional"`
+ Username string `alloy:"username,attr,optional"` // Deprecated
+ Password alloytypes.Secret `alloy:"password,attr,optional"` // Deprecated
+ Databases DatabaseTargets `alloy:"database,block,optional"`
}
+var (
+ errBothConfigModes = errors.New("cannot set connection_string together with database blocks; use one or the other")
+ errDuplicateDBName = errors.New("duplicate database name")
+)
func (a *Arguments) Validate() error {
- if a.ConnectionString == "" {
- return errNoConnectionString
- }
+ if len(a.Databases) > 0 && a.ConnectionString != "" { return errBothConfigModes }
+ if len(a.Databases) == 0 && a.ConnectionString == "" { return errNoConnectionString }
+ // validate each database block (non-empty name, unique, valid URL, etc.)
}Code updates (integration): - // required driver for integration
- _ "github.com/sijms/go-ora/v2"
+// driver now selected via build tags; use godror tag and instant client
+func NormalizeConnectionString(connectionString, username, password string) (string, string, string) {
+ // Handle oracle://user:pass@host:port/svc => split out user/pass and strip scheme
+}
- func (c *Config) InstanceKey(agentKey string) (string, error) {
- // previously derived from top-level connection_string
- }
+ func (c *Config) InstanceKey(defaultKey string) (string, error) {
+ // If multiple DBs => return defaultKey to avoid unstable high-cardinality instance
+ }
+ type DatabaseInstance struct {
+ Name string `yaml:"name"`
+ ConnectionString config_util.Secret `yaml:"connection_string"`
+ Username string `yaml:"username,omitempty"`
+ Password config_util.Secret `yaml:"password,omitempty"`
+ Labels map[string]string `yaml:"labels,omitempty"`
+ }
func New(logger log.Logger, c *Config) (integrations.Integration, error) {
- oeExporter, err := oe.NewExporter(slogLogger, &oe.MetricsConfiguration{ ... })
- if err != nil { return nil, err }
+ // Build Databases map[string]DatabaseConfig from single or multi-target config
+ // Set ScrapeInterval pointer
+ oeExporter := oe.NewExporter(slogLogger, &oe.MetricsConfiguration{ ... })
+ if oeExporter == nil { return nil, errors.New("failed to create oracledb exporter") }
}
Recommended follow-up (already in PR)
github.com/godror/godror v0.48.1 -> v0.50.0 —
|
eed205e to
43cf816
Compare
.github/workflows/build.yml
Outdated
| # TODO: Try enabling caching later. It might use up too much disk space on runners so needs extra testing. | ||
| cache: false | ||
| - run: GO_TAGS="embedalloyui promtail_journal_enabled" GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} GOARM= make alloy | ||
| - run: GO_TAGS="embedalloyui promtail_journal_enabled godror" GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} GOARM= make alloy |
There was a problem hiding this comment.
Would we always build and run test with this tag?
Maybe we could just append it to GO_TAGS in our make file and make sure everything pass those tags, like integration tests etc. Then we don't have to do it for every workflow, WDYT?
internal/static/integrations/oracledb_exporter/oracledb_exporter.go
Outdated
Show resolved
Hide resolved
43cf816 to
2842de6
Compare
Pull Request Details
The
prometheus.exporter.oracledbcomponent is currently not able to scrape more than one Oracle DB from oneprometheus.exporter.oracledb. In order to do this, you'd need to setup more than one component. However, the upstream exporter contains global variables which cause bugs when more than one instance is used.This PR updates Alloy to a more recent version of the upstream exporter. That version is able to scrape more than one DB. This PR will also change the configuration parameters of the component so that it's possible to set up different connection strings, usernames, passwords for each DB being scraped.
Notes to the Reviewer
I'd like to add integration tests later on, in a separate PR. I drafted them locally but they need more polish before I open them for review.
For now I tested this change locally, using this configuration:
Alloy config
custom-metrics.toml
Docker compose
PR Checklist