Skip to content

Commit 54a6d31

Browse files
Exporter configuration file (#231)
Signed-off-by: Anders Swanson <[email protected]>
1 parent b8437fa commit 54a6d31

File tree

8 files changed

+389
-96
lines changed

8 files changed

+389
-96
lines changed

README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,8 @@ The following command line arguments (flags) can be passed to the exporter (the
558558

559559
```bash
560560
Usage of oracledb_exporter:
561+
--config.file="example-config.yaml"
562+
File with metrics exporter configuration. (env: CONFIG_FILE)
561563
--web.telemetry-path="/metrics"
562564
Path under which to expose metrics. (env: TELEMETRY_PATH)
563565
--default.metrics="default-metrics.toml"
@@ -597,6 +599,69 @@ You may provide the connection details using these variables:
597599

598600
The following example puts the logfile in the current location with the filename `alert.log` and loads the default matrics file (`default-metrics,toml`) from the current location.
599601

602+
If you prefer to provide configuration via a [config file](./example-config.yaml), you may do so with the `--config.file` argument. The use of a config file over command line arguments is preferred. If a config file is not provided, the default database connection is managed by command line arguments.
603+
604+
```yaml
605+
# Example Oracle Database Metrics Exporter Configuration file.
606+
# Environment variables of the form ${VAR_NAME} will be expanded.
607+
608+
databases:
609+
## Path on which metrics will be served
610+
# metricsPath: /metrics
611+
## Database connection information for the "default" database.
612+
default:
613+
## Database username
614+
username: ${DB_USERNAME}
615+
## Database password
616+
password: ${DB_PASSWORD}
617+
## Database connection url
618+
url: localhost:1521/freepdb1
619+
## Metrics scrape interval for this database
620+
scrapeInterval: 15s
621+
## Metrics query timeout for this database, in seconds
622+
queryTimeout: 5
623+
624+
## Rely on Oracle Database External Authentication by network or OS
625+
# externalAuth: false
626+
## Database role
627+
# role: SYSDBA
628+
## Path to Oracle Database wallet, if using wallet
629+
# tnsAdmin: /path/to/database/wallet
630+
631+
### Connection settings:
632+
### Either the go-sql or Oracle Database connection pool may be used.
633+
### To use the Oracle Database connection pool over the go-sql connection pool,
634+
### set maxIdleConns to zero and configure the pool* settings.
635+
636+
### Connection pooling settings for the go-sql connection pool
637+
## Max open connections for this database using go-sql connection pool
638+
maxOpenConns: 10
639+
## Max idle connections for this database using go-sql connection pool
640+
maxIdleConns: 10
641+
642+
### Connection pooling settings for the Oracle Database connection pool
643+
## Oracle Database connection pool increment.
644+
# poolIncrement: 1
645+
## Oracle Database Connection pool maximum size
646+
# poolMaxConnections: 15
647+
## Oracle Database Connection pool minimum size
648+
# poolMinConnections: 15
649+
650+
metrics:
651+
default: default-metrics.toml
652+
#
653+
custom:
654+
- custom-metrics-example/custom-metrics.toml
655+
656+
log:
657+
# Path of log file
658+
destination: /opt/alert.log
659+
# Interval of log updates
660+
interval: 15s
661+
## Set disable to 1 to disable logging
662+
# disable: 0
663+
```
664+
600665
```shell
601666
./oracledb_exporter --log.destination="./alert.log" --default.metrics="./default-metrics.toml"
602667
```

collector/collector.go

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ func maskDsn(dsn string) string {
4949
}
5050

5151
// NewExporter creates a new Exporter instance
52-
func NewExporter(logger *slog.Logger, cfg *Config) (*Exporter, error) {
52+
func NewExporter(logger *slog.Logger, m *MetricsConfiguration) (*Exporter, error) {
53+
// TODO: support multiple databases
54+
var cfg DatabaseConfig
55+
for _, v := range m.Databases {
56+
cfg = v
57+
}
5358
e := &Exporter{
54-
mu: &sync.Mutex{},
55-
user: cfg.User,
56-
password: cfg.Password,
57-
connectString: cfg.ConnectString,
58-
configDir: cfg.ConfigDir,
59-
externalAuth: cfg.ExternalAuth,
59+
mu: &sync.Mutex{},
6060
duration: prometheus.NewGauge(prometheus.GaugeOpts{
6161
Namespace: namespace,
6262
Subsystem: exporterName,
@@ -91,10 +91,10 @@ func NewExporter(logger *slog.Logger, cfg *Config) (*Exporter, error) {
9191
Name: "dbtype",
9292
Help: "Type of database the exporter is connected to (0=non-CDB, 1=CDB, >1=PDB).",
9393
}),
94-
logger: logger,
95-
config: cfg,
96-
lastScraped: map[string]*time.Time{},
97-
scrapeInterval: cfg.ScrapeInterval,
94+
logger: logger,
95+
databaseConfig: cfg,
96+
metricsConfiguration: m,
97+
lastScraped: map[string]*time.Time{},
9898
}
9999
e.metricsToScrape = e.DefaultMetrics()
100100
err := e.connect()
@@ -133,7 +133,7 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
133133
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
134134
// they are running scheduled scrapes we should only scrape new data
135135
// on the interval
136-
if e.scrapeInterval != 0 {
136+
if e.databaseConfig.ScrapeInterval != 0 {
137137
// read access must be checked
138138
e.mu.Lock()
139139
for _, r := range e.scrapeResults {
@@ -160,7 +160,7 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
160160
func (e *Exporter) RunScheduledScrapes(ctx context.Context) {
161161
e.doScrape(time.Now())
162162

163-
ticker := time.NewTicker(e.scrapeInterval)
163+
ticker := time.NewTicker(e.databaseConfig.ScrapeInterval)
164164
defer ticker.Stop()
165165

166166
for {
@@ -236,7 +236,7 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric, tick *time.Time) {
236236

237237
e.dbtypeGauge.Set(float64(e.dbtype))
238238

239-
e.logger.Debug("Successfully pinged Oracle database: " + maskDsn(e.connectString))
239+
e.logger.Debug("Successfully pinged Oracle database: " + maskDsn(e.databaseConfig.URL))
240240
e.up.Set(1)
241241

242242
if e.checkIfMetricsChanged() {
@@ -323,43 +323,43 @@ func (e *Exporter) afterScrape(begun time.Time, countMetrics int, errChan chan e
323323
}
324324

325325
func (e *Exporter) connect() error {
326-
e.logger.Debug("Launching connection to " + maskDsn(e.connectString))
326+
e.logger.Debug("Launching connection to " + maskDsn(e.databaseConfig.URL))
327327

328328
var P godror.ConnectionParams
329329
// If password is not specified, externalAuth will be true and we'll ignore user input
330-
e.externalAuth = e.password == ""
331-
e.logger.Debug(fmt.Sprintf("external authentication set to %t", e.externalAuth))
330+
e.databaseConfig.ExternalAuth = e.databaseConfig.Password == ""
331+
e.logger.Debug(fmt.Sprintf("external authentication set to %t", e.databaseConfig.ExternalAuth))
332332
msg := "Using Username/Password Authentication."
333-
if e.externalAuth {
333+
if e.databaseConfig.ExternalAuth {
334334
msg = "Database Password not specified; will attempt to use external authentication (ignoring user input)."
335-
e.user = ""
335+
e.databaseConfig.Username = ""
336336
}
337337
e.logger.Info(msg)
338338
externalAuth := sql.NullBool{
339-
Bool: e.externalAuth,
339+
Bool: e.databaseConfig.ExternalAuth,
340340
Valid: true,
341341
}
342-
P.Username, P.Password, P.ConnectString, P.ExternalAuth = e.user, godror.NewPassword(e.password), e.connectString, externalAuth
342+
P.Username, P.Password, P.ConnectString, P.ExternalAuth = e.databaseConfig.Username, godror.NewPassword(e.databaseConfig.Password), e.databaseConfig.URL, externalAuth
343343

344-
if e.config.PoolIncrement > 0 {
345-
e.logger.Debug(fmt.Sprintf("set pool increment to %d", e.config.PoolIncrement))
346-
P.PoolParams.SessionIncrement = e.config.PoolIncrement
344+
if e.databaseConfig.PoolIncrement > 0 {
345+
e.logger.Debug(fmt.Sprintf("set pool increment to %d", e.databaseConfig.PoolIncrement))
346+
P.PoolParams.SessionIncrement = e.databaseConfig.PoolIncrement
347347
}
348-
if e.config.PoolMaxConnections > 0 {
349-
e.logger.Debug(fmt.Sprintf("set pool max connections to %d", e.config.PoolMaxConnections))
350-
P.PoolParams.MaxSessions = e.config.PoolMaxConnections
348+
if e.databaseConfig.PoolMaxConnections > 0 {
349+
e.logger.Debug(fmt.Sprintf("set pool max connections to %d", e.databaseConfig.PoolMaxConnections))
350+
P.PoolParams.MaxSessions = e.databaseConfig.PoolMaxConnections
351351
}
352-
if e.config.PoolMinConnections > 0 {
353-
e.logger.Debug(fmt.Sprintf("set pool min connections to %d", e.config.PoolMinConnections))
354-
P.PoolParams.MinSessions = e.config.PoolMinConnections
352+
if e.databaseConfig.PoolMinConnections > 0 {
353+
e.logger.Debug(fmt.Sprintf("set pool min connections to %d", e.databaseConfig.PoolMinConnections))
354+
P.PoolParams.MinSessions = e.databaseConfig.PoolMinConnections
355355
}
356356

357357
P.PoolParams.WaitTimeout = time.Second * 5
358358

359359
// if TNS_ADMIN env var is set, set ConfigDir to that location
360-
P.ConfigDir = e.configDir
360+
P.ConfigDir = e.databaseConfig.TNSAdmin
361361

362-
switch e.config.DbRole {
362+
switch e.databaseConfig.Role {
363363
case "SYSDBA":
364364
P.AdminRole = dsn.SysDBA
365365
case "SYSOPER":
@@ -381,12 +381,12 @@ func (e *Exporter) connect() error {
381381
// note that this just configures the connection, it does not actually connect until later
382382
// when we call db.Ping()
383383
db := sql.OpenDB(godror.NewConnector(P))
384-
e.logger.Debug(fmt.Sprintf("set max idle connections to %d", e.config.MaxIdleConns))
385-
db.SetMaxIdleConns(e.config.MaxIdleConns)
386-
e.logger.Debug(fmt.Sprintf("set max open connections to %d", e.config.MaxOpenConns))
387-
db.SetMaxOpenConns(e.config.MaxOpenConns)
384+
e.logger.Debug(fmt.Sprintf("set max idle connections to %d", e.databaseConfig.MaxIdleConns))
385+
db.SetMaxIdleConns(e.databaseConfig.MaxIdleConns)
386+
e.logger.Debug(fmt.Sprintf("set max open connections to %d", e.databaseConfig.MaxOpenConns))
387+
db.SetMaxOpenConns(e.databaseConfig.MaxOpenConns)
388388
db.SetConnMaxLifetime(0)
389-
e.logger.Debug(fmt.Sprintf("Successfully configured connection to %s", maskDsn(e.connectString)))
389+
e.logger.Debug(fmt.Sprintf("Successfully configured connection to %s", maskDsn(e.databaseConfig.URL)))
390390
e.db = db
391391

392392
if _, err := db.Exec(`
@@ -417,7 +417,7 @@ func (e *Exporter) GetDB() *sql.DB {
417417
}
418418

419419
func (e *Exporter) checkIfMetricsChanged() bool {
420-
for i, _customMetrics := range strings.Split(e.config.CustomMetrics, ",") {
420+
for i, _customMetrics := range e.metricsConfiguration.Metrics.Custom {
421421
if len(_customMetrics) == 0 {
422422
continue
423423
}
@@ -458,8 +458,8 @@ func (e *Exporter) reloadMetrics() {
458458
e.metricsToScrape.Metric = defaultMetrics.Metric
459459

460460
// If custom metrics, load it
461-
if strings.Compare(e.config.CustomMetrics, "") != 0 {
462-
for _, _customMetrics := range strings.Split(e.config.CustomMetrics, ",") {
461+
if len(e.metricsConfiguration.Metrics.Custom) > 0 {
462+
for _, _customMetrics := range e.metricsConfiguration.Metrics.Custom {
463463
metrics := &Metrics{}
464464
if _, err := toml.DecodeFile(_customMetrics, metrics); err != nil {
465465
e.logger.Error("failed to load custom metrics", "error", err)

0 commit comments

Comments
 (0)