diff --git a/tsdb/points.go b/tsdb/points.go index 92e8e1c7dc..468e19dc6c 100644 --- a/tsdb/points.go +++ b/tsdb/points.go @@ -91,6 +91,11 @@ var ( } escapeCodesStr = map[string]string{} + + measurementEscapeCodes = map[byte][]byte{ + ',': []byte(`\,`), + ' ': []byte(`\ `), + } ) func init() { @@ -707,7 +712,7 @@ func scanLine(buf []byte, i int) (int, []byte) { } // If we see a double quote, makes sure it is not escaped - if buf[i] == '"' && buf[i-1] != '\\' { + if buf[i] == '"' && (i-1 > 0 && buf[i-1] != '\\') { i += 1 quoted = !quoted continue @@ -827,6 +832,20 @@ func scanFieldValue(buf []byte, i int) (int, []byte) { return i, buf[start:i] } +func escapeMeasurement(in []byte) []byte { + for b, esc := range measurementEscapeCodes { + in = bytes.Replace(in, []byte{b}, esc, -1) + } + return in +} + +func unescapeMeasurement(in []byte) []byte { + for b, esc := range measurementEscapeCodes { + in = bytes.Replace(in, esc, []byte{b}, -1) + } + return in +} + func escape(in []byte) []byte { for b, esc := range escapeCodes { in = bytes.Replace(in, []byte{b}, esc, -1) @@ -948,7 +967,7 @@ func (p *point) Tags() Tags { func MakeKey(name []byte, tags Tags) []byte { // unescape the name and then re-escape it to avoid double escaping. // The key should always be stored in escaped form. - return append(escape(unescape(name)), tags.HashKey()...) + return append(escapeMeasurement(unescapeMeasurement(name)), tags.HashKey()...) } // SetTags replaces the tags for the point diff --git a/tsdb/points_test.go b/tsdb/points_test.go index 2e9f873a90..a502100b28 100644 --- a/tsdb/points_test.go +++ b/tsdb/points_test.go @@ -740,7 +740,22 @@ func TestParsePointWithStringWithCommas(t *testing.T) { }, time.Unix(1, 0)), ) +} +func TestParsePointQuotedMeasurement(t *testing.T) { + // non-escaped comma + test(t, `"cpu",host=serverA,region=us-east value=1.0 1000000000`, + tsdb.NewPoint( + `"cpu"`, + tsdb.Tags{ + "host": "serverA", + "region": "us-east", + }, + tsdb.Fields{ + "value": 1.0, + }, + time.Unix(1, 0)), + ) } func TestParsePointEscapedStringsAndCommas(t *testing.T) { @@ -771,7 +786,6 @@ func TestParsePointEscapedStringsAndCommas(t *testing.T) { }, time.Unix(1, 0)), ) - } func TestParsePointWithStringWithEquals(t *testing.T) { @@ -1193,7 +1207,7 @@ func TestNewPointEscaped(t *testing.T) { // equals pt = tsdb.NewPoint("cpu=main", tsdb.Tags{"tag=bar": "value=foo"}, tsdb.Fields{"name=bar": 1.0}, time.Unix(0, 0)) - if exp := `cpu\=main,tag\=bar=value\=foo name\=bar=1.0 0`; pt.String() != exp { + if exp := `cpu=main,tag\=bar=value\=foo name\=bar=1.0 0`; pt.String() != exp { t.Errorf("NewPoint().String() mismatch.\ngot %v\nexp %v", pt.String(), exp) } }