Skip to content

Commit

Permalink
outputs/postgresql: Refactor initialization to use telegraf convention
Browse files Browse the repository at this point in the history
  • Loading branch information
phemmer committed Aug 13, 2021
1 parent 93aec6f commit ff644a9
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 38 deletions.
99 changes: 71 additions & 28 deletions plugins/outputs/postgresql/postgresql.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import (
"github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/pgxpool"

"github.com/influxdata/toml"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/models"
Expand Down Expand Up @@ -51,53 +49,51 @@ var sampleConfig = `
## with the same name as the user. This dbname is just for instantiating a
## connection with the server and doesn't restrict the databases we are trying
## to grab metrics for.
##
#connection = "host=localhost user=postgres sslmode=verify-full"
## Postgres schema to use.
schema = "public"
# schema = "public"
## Store tags as foreign keys in the metrics table. Default is false.
tags_as_foreign_keys = false
# tags_as_foreign_keys = false
## Suffix to append to table name (measurement name) for the foreign tag table.
tag_table_suffix = "_tag"
# tag_table_suffix = "_tag"
## Deny inserting metrics if the foreign tag can't be inserted.
foreign_tag_constraint = false
# foreign_tag_constraint = false
## Store all tags as a JSONB object in a single 'tags' column.
tags_as_jsonb = false
# tags_as_jsonb = false
## Store all fields as a JSONB object in a single 'fields' column.
fields_as_jsonb = false
# fields_as_jsonb = false
## Templated statements to execute when creating a new table.
create_templates = [
'''CREATE TABLE {{.table}} ({{.columns}})''',
]
# create_templates = [
# '''CREATE TABLE {{.table}} ({{.columns}})''',
# ]
## Templated statements to execute when adding columns to a table.
## Set to an empty list to disable. Points containing tags for which there is no column will be skipped. Points
## containing fields for which there is no column will have the field omitted.
add_column_templates = [
'''ALTER TABLE {{.table}} ADD COLUMN IF NOT EXISTS {{.columns|join ", ADD COLUMN IF NOT EXISTS "}}''',
]
# add_column_templates = [
# '''ALTER TABLE {{.table}} ADD COLUMN IF NOT EXISTS {{.columns|join ", ADD COLUMN IF NOT EXISTS "}}''',
# ]
## Templated statements to execute when creating a new tag table.
tag_table_create_templates = [
'''CREATE TABLE {{.table}} ({{.columns}}, PRIMARY KEY (tag_id))''',
]
# tag_table_create_templates = [
# '''CREATE TABLE {{.table}} ({{.columns}}, PRIMARY KEY (tag_id))''',
# ]
## Templated statements to execute when adding columns to a tag table.
## Set to an empty list to disable. Points containing tags for which there is no column will be skipped.
tag_table_add_column_templates = [
'''ALTER TABLE {{.table}} ADD COLUMN IF NOT EXISTS {{.columns|join ", ADD COLUMN IF NOT EXISTS "}}''',
]
# tag_table_add_column_templates = [
# '''ALTER TABLE {{.table}} ADD COLUMN IF NOT EXISTS {{.columns|join ", ADD COLUMN IF NOT EXISTS "}}''',
# ]
## When using pool_max_conns>1, an a temporary error occurs, the query is retried with an incremental backoff. This
## controls the maximum backoff duration.
retry_max_backoff = "15s"
# retry_max_backoff = "15s"
## Enable & set the log level for the Postgres driver.
# log_level = "info" # trace, debug, info, warn, error, none
Expand Down Expand Up @@ -135,13 +131,60 @@ func init() {
}

func newPostgresql() *Postgresql {
p := &Postgresql{
Logger: models.NewLogger("outputs", "postgresql", ""),
return &Postgresql{}
}

func (p *Postgresql) Init() error {
if p.Schema == "" {
p.Schema = "public"
}

if p.TagTableSuffix == "" {
p.TagTableSuffix = "_tag"
}
if err := toml.Unmarshal([]byte(p.SampleConfig()), p); err != nil {
panic(err.Error())

if p.CreateTemplates == nil {
t := &sqltemplate.Template{}
t.UnmarshalText([]byte(`CREATE TABLE {{.table}} ({{.columns}})`))
p.CreateTemplates = []*sqltemplate.Template{t}
}

if p.AddColumnTemplates == nil {
t := &sqltemplate.Template{}
t.UnmarshalText([]byte(`ALTER TABLE {{.table}} ADD COLUMN IF NOT EXISTS {{.columns|join ", ADD COLUMN IF NOT EXISTS "}}`))
p.AddColumnTemplates = []*sqltemplate.Template{t}
}
return p

if p.TagTableCreateTemplates == nil {
t := &sqltemplate.Template{}
t.UnmarshalText([]byte(`CREATE TABLE {{.table}} ({{.columns}}, PRIMARY KEY (tag_id))`))
p.TagTableCreateTemplates = []*sqltemplate.Template{t}
}

if p.TagTableAddColumnTemplates == nil {
t := &sqltemplate.Template{}
t.UnmarshalText([]byte(`ALTER TABLE {{.table}} ADD COLUMN IF NOT EXISTS {{.columns|join ", ADD COLUMN IF NOT EXISTS "}}`))
p.TagTableAddColumnTemplates = []*sqltemplate.Template{t}
}

if p.RetryMaxBackoff == 0 {
p.RetryMaxBackoff = config.Duration(time.Second * 15)
}

if p.LogLevel == "" {
p.LogLevel = "info"
}

if p.TagTableAddColumnTemplates == nil {
t := &sqltemplate.Template{}
t.UnmarshalText([]byte(`ALTER TABLE {{.table}} ADD COLUMN IF NOT EXISTS {{.columns|join ", ADD COLUMN IF NOT EXISTS "}}`))
}

if p.Logger == nil {
p.Logger = models.NewLogger("outputs", "postgresql", "")
}

return nil
}

func (p *Postgresql) SampleConfig() string { return sampleConfig }
Expand Down
28 changes: 27 additions & 1 deletion plugins/outputs/postgresql/postgresql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ package postgresql

import (
"context"
"encoding/json"
"fmt"
"github.com/influxdata/telegraf/testutil"
"os"
"regexp"
"strings"
"sync"
"testing"
"time"

"github.com/influxdata/toml"

"github.com/influxdata/telegraf/testutil"

"github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -211,6 +216,7 @@ type PostgresqlTest struct {

func newPostgresqlTest(tb testing.TB) *PostgresqlTest {
p := newPostgresql()
p.Init()
logger := NewLogAccumulator(tb)
p.Logger = logger
pt := &PostgresqlTest{Postgresql: *p}
Expand All @@ -220,6 +226,26 @@ func newPostgresqlTest(tb testing.TB) *PostgresqlTest {
return pt
}

// Verify that the documented defaults match the actual defaults.
//
// Sample config must be in the format documented in `docs/developers/SAMPLE_CONFIG.md`.
func TestPostgresqlSampleConfig(t *testing.T) {
p1 := newPostgresql()
require.NoError(t, p1.Init())

p2 := newPostgresql()
re := regexp.MustCompile(`(?m)^\s*#`)
conf := re.ReplaceAllLiteralString(p1.SampleConfig(), "")
require.NoError(t, toml.Unmarshal([]byte(conf), p2))
require.NoError(t, p2.Init())

// Can't use assert.Equal() because it dives into unexported fields that contain unequal values.
// Serializing to JSON is effective as any differences will be visible in exported fields.
p1json, _ := json.Marshal(p1)
p2json, _ := json.Marshal(p2)
assert.JSONEq(t, string(p1json), string(p2json), "Sample config does not match default config")
}

func TestPostgresqlConnect(t *testing.T) {
p := newPostgresqlTest(t)
require.NoError(t, p.Connect())
Expand Down
9 changes: 0 additions & 9 deletions plugins/outputs/postgresql/sqltemplate/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,6 @@ import (
"github.com/Masterminds/sprig"
)

// TableCreateTemplate is the default template used for creating new tables.
var TableCreateTemplate = newTemplate(`CREATE TABLE {{.table}} ({{.columns}})`)

// TagTableCreateTemplate is the default template used when creating a new tag table.
var TagTableCreateTemplate = newTemplate(`CREATE TABLE {{.table}} ({{.columns}}, PRIMARY KEY (tag_id))`)

// TableAddColumnTemplate is the default template used when adding new columns to an existing table.
var TableAddColumnTemplate = newTemplate(`ALTER TABLE {{.table}} ADD COLUMN IF NOT EXISTS {{.columns|join ", ADD COLUMN IF NOT EXISTS "}}`)

var templateFuncs = map[string]interface{}{
"quoteIdentifier": QuoteIdentifier,
"quoteLiteral": QuoteLiteral,
Expand Down

0 comments on commit ff644a9

Please sign in to comment.