From ef3ee358d108dff6f74fc505021d618a2ba5555f Mon Sep 17 00:00:00 2001 From: Grische <2787581+grische@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:11:34 +0200 Subject: [PATCH] fix(database/influxdb): replace invisible chars and whitespaces with space (#235) This fixes issues where users use '\n' in tag values (e.g. the owner) that is incompatible with InfluxDB's Line protocol. --- database/influxdb/database.go | 24 ++++++++++++++++++ database/influxdb/database_test.go | 40 +++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/database/influxdb/database.go b/database/influxdb/database.go index cd636be6..b28e31e7 100644 --- a/database/influxdb/database.go +++ b/database/influxdb/database.go @@ -1,8 +1,10 @@ package influxdb import ( + "strings" "sync" "time" + "unicode" "github.com/bdlm/log" "github.com/influxdata/influxdb1-client/models" @@ -94,6 +96,25 @@ func Connect(configuration map[string]interface{}) (database.Connection, error) return db, nil } +func sanitizeValues(tags models.Tags) models.Tags { + // https://docs.influxdata.com/influxdb/v2/reference/syntax/line-protocol/ + // Line protocol does not support the newline character \n in tag or field values. + // To be safe, remove all non-printable characters and spaces except ASCII space and U+0020. + for _, tag := range tags { + cleaned_value := strings.Map(func(r rune) rune { + if unicode.IsPrint(r) { + return r + } + return ' ' + }, string(tag.Value)) + + if cleaned_value != string(tag.Value) { + tags.SetString(string(tag.Key), cleaned_value) + } + } + return tags +} + func (conn *Connection) addPoint(name string, tags models.Tags, fields models.Fields, t ...time.Time) { if configTags := conn.config.Tags(); configTags != nil { for tag, valueInterface := range configTags { @@ -107,6 +128,9 @@ func (conn *Connection) addPoint(name string, tags models.Tags, fields models.Fi } } } + + tags = sanitizeValues(tags) + point, err := client.NewPoint(name, tags.Map(), fields, t...) if err != nil { log.Panicf("could not save points: %s", err) diff --git a/database/influxdb/database_test.go b/database/influxdb/database_test.go index dce80029..673fa752 100644 --- a/database/influxdb/database_test.go +++ b/database/influxdb/database_test.go @@ -7,7 +7,7 @@ import ( "time" "github.com/influxdata/influxdb1-client/models" - "github.com/influxdata/influxdb1-client/v2" + client "github.com/influxdata/influxdb1-client/v2" "github.com/stretchr/testify/assert" ) @@ -98,3 +98,41 @@ func TestAddPoint(t *testing.T) { connection.addPoint("name", models.Tags{}, nil, time.Now()) }) } + +func TestAddPointWithInvalidCharacters(t *testing.T) { + assert := assert.New(t) + + connection := &Connection{ + config: map[string]interface{}{}, + points: make(chan *client.Point, 1), + } + + tagsOrigin := models.Tags{} + tagsOrigin.SetString("owner", "\u00a0this owner\nuses invalid chars\t") + + connection.addPoint("name", tagsOrigin, models.Fields{"clients.total": 10}, time.Now()) + point := <-connection.points + assert.NotNil(point) + tags := point.Tags() + assert.NotNil(tags) + assert.Equal(tags["owner"], " this owner uses invalid chars ") +} + +func TestAddPointWithValidCharacters(t *testing.T) { + assert := assert.New(t) + + connection := &Connection{ + config: map[string]interface{}{}, + points: make(chan *client.Point, 1), + } + + tagsOrigin := models.Tags{} + tagsOrigin.SetString("owner", "📶this owner uses only\u0020valid chars🛜") + + connection.addPoint("name", tagsOrigin, models.Fields{"clients.total": 10}, time.Now()) + point := <-connection.points + assert.NotNil(point) + tags := point.Tags() + assert.NotNil(tags) + assert.Equal(tags["owner"], "📶this owner uses only\u0020valid chars🛜") +}