diff --git a/main.go b/main.go index aab6025..4d4754b 100644 --- a/main.go +++ b/main.go @@ -48,7 +48,6 @@ type config struct { telemetryPath string pgPrometheusConfig pgprometheus.Config logLevel string - readOnly bool haGroupLockId int restElection bool prometheusTimeout time.Duration @@ -150,11 +149,11 @@ func parseFlags() *config { flag.StringVar(&cfg.listenAddr, "web.listen-address", ":9201", "Address to listen on for web endpoints.") flag.StringVar(&cfg.telemetryPath, "web.telemetry-path", "/metrics", "Address to listen on for web endpoints.") flag.StringVar(&cfg.logLevel, "log.level", "debug", "The log level to use [ \"error\", \"warn\", \"info\", \"debug\" ].") - flag.BoolVar(&cfg.readOnly, "read.only", false, "Read-only mode. Don't write to database.") flag.IntVar(&cfg.haGroupLockId, "leader-election.pg-advisory-lock-id", 0, "Unique advisory lock id per adapter high-availability group. Set it if you want to use leader election implementation based on PostgreSQL advisory lock.") flag.DurationVar(&cfg.prometheusTimeout, "leader-election.pg-advisory-lock.prometheus-timeout", -1, "Adapter will resign if there are no requests from Prometheus within a given timeout (0 means no timeout). "+ "Note: make sure that only one Prometheus instance talks to the adapter. Timeout value should be co-related with Prometheus scrape interval but add enough `slack` to prevent random flips.") flag.BoolVar(&cfg.restElection, "leader-election.rest", false, "Enable REST interface for the leader election") + flag.Parse() return cfg @@ -184,7 +183,7 @@ type reader interface { func buildClients(cfg *config) (writer, reader) { pgClient := pgprometheus.NewClient(&cfg.pgPrometheusConfig) - if cfg.readOnly { + if pgClient.ReadOnly() { return &noOpWriter{}, pgClient } return pgClient, pgClient diff --git a/postgresql/client.go b/postgresql/client.go index d3b2bb3..b1952e1 100644 --- a/postgresql/client.go +++ b/postgresql/client.go @@ -39,6 +39,7 @@ type Config struct { pgPrometheusChunkInterval time.Duration useTimescaleDb bool dbConnectRetries int + readOnly bool } // ParseFlags parses the configuration flags specific to PostgreSQL and TimescaleDB @@ -59,6 +60,7 @@ func ParseFlags(cfg *Config) *Config { flag.DurationVar(&cfg.pgPrometheusChunkInterval, "pg.prometheus-chunk-interval", time.Hour*12, "The size of a time-partition chunk in TimescaleDB") flag.BoolVar(&cfg.useTimescaleDb, "pg.use-timescaledb", true, "Use timescaleDB") flag.IntVar(&cfg.dbConnectRetries, "pg.db-connect-retries", 0, "How many times to retry connecting to the database") + flag.BoolVar(&cfg.readOnly, "pg.read-only", false, "Read-only mode. Don't write to database. Useful when pointing adapter to read replica") return cfg } @@ -105,18 +107,23 @@ func NewClient(cfg *Config) *Client { cfg: cfg, } - err = client.setupPgPrometheus() + if !cfg.readOnly { + err = client.setupPgPrometheus() - if err != nil { - log.Error("err", err) - os.Exit(1) - } + if err != nil { + log.Error("err", err) + os.Exit(1) + } - createTmpTableStmt, err = db.Prepare(fmt.Sprintf(sqlCreateTmpTable, cfg.table)) - if err != nil { - log.Error("msg", "Error on preparing create tmp table statement", "err", err) - os.Exit(1) + createTmpTableStmt, err = db.Prepare(fmt.Sprintf(sqlCreateTmpTable, cfg.table)) + if err != nil { + log.Error("msg", "Error on preparing create tmp table statement", "err", err) + os.Exit(1) + } + } else { + log.Info("msg", "Running in read-only mode. Skipping schema/extension setup (should already be present)") } + return client } @@ -165,6 +172,10 @@ func (c *Client) setupPgPrometheus() error { return nil } +func (c *Client) ReadOnly() bool { + return c.cfg.readOnly +} + func metricString(m model.Metric) string { metricName, hasName := m[model.MetricNameLabel] numLabels := len(m) - 1