Skip to content

Commit

Permalink
Merge pull request influxdata#4436 from influxdb/tag-names-to-keys
Browse files Browse the repository at this point in the history
WIP tag name --> tag key, field name --> field key
  • Loading branch information
beckettsean committed Oct 14, 2015
2 parents c6992ab + d4bbd6e commit 82f104a
Show file tree
Hide file tree
Showing 9 changed files with 28 additions and 28 deletions.
2 changes: 1 addition & 1 deletion QUERIES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
The top level name is called a measurement. These names can contain any characters. Then there are field names, field values, tag keys and tag values, which can also contain any characters. However, if the measurement, field, or tag contains any character other than [A-Z,a-z,0-9,_], or if it starts with a digit, it must be double-quoted. Therefore anywhere a measurement name, field name, field value, tag name, or tag value appears it should be wrapped in double quotes.
The top level name is called a measurement. These names can contain any characters. Then there are field names, field values, tag keys and tag values, which can also contain any characters. However, if the measurement, field, or tag contains any character other than [A-Z,a-z,0-9,_], or if it starts with a digit, it must be double-quoted. Therefore anywhere a measurement name, field key, or tag key appears it should be wrapped in double quotes.

# Databases & retention policies

Expand Down
2 changes: 1 addition & 1 deletion cluster/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ type WritePointsRequest struct {
Points []models.Point
}

// AddPoint adds a point to the WritePointRequest with field name 'value'
// AddPoint adds a point to the WritePointRequest with field key 'value'
func (w *WritePointsRequest) AddPoint(name string, value interface{}, timestamp time.Time, tags map[string]string) {
w.Points = append(w.Points, models.NewPoint(
name, tags, map[string]interface{}{"value": value}, timestamp,
Expand Down
10 changes: 5 additions & 5 deletions cmd/influxd/run/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (c *Config) applyEnvOverrides(prefix string, spec reflect.Value) error {
configName := typeOfSpec.Field(i).Tag.Get("toml")
// Replace hyphens with underscores to avoid issues with shells
configName = strings.Replace(configName, "-", "_", -1)
fieldName := typeOfSpec.Field(i).Name
fieldKey := typeOfSpec.Field(i).Name

// Skip any fields that we cannot set
if f.CanSet() || f.Kind() == reflect.Slice {
Expand Down Expand Up @@ -188,29 +188,29 @@ func (c *Config) applyEnvOverrides(prefix string, spec reflect.Value) error {
if f.Type().Name() == "Duration" {
dur, err := time.ParseDuration(value)
if err != nil {
return fmt.Errorf("failed to apply %v to %v using type %v and value '%v'", key, fieldName, f.Type().String(), value)
return fmt.Errorf("failed to apply %v to %v using type %v and value '%v'", key, fieldKey, f.Type().String(), value)
}
intValue = dur.Nanoseconds()
} else {
var err error
intValue, err = strconv.ParseInt(value, 0, f.Type().Bits())
if err != nil {
return fmt.Errorf("failed to apply %v to %v using type %v and value '%v'", key, fieldName, f.Type().String(), value)
return fmt.Errorf("failed to apply %v to %v using type %v and value '%v'", key, fieldKey, f.Type().String(), value)
}
}

f.SetInt(intValue)
case reflect.Bool:
boolValue, err := strconv.ParseBool(value)
if err != nil {
return fmt.Errorf("failed to apply %v to %v using type %v and value '%v'", key, fieldName, f.Type().String(), value)
return fmt.Errorf("failed to apply %v to %v using type %v and value '%v'", key, fieldKey, f.Type().String(), value)

}
f.SetBool(boolValue)
case reflect.Float32, reflect.Float64:
floatValue, err := strconv.ParseFloat(value, f.Type().Bits())
if err != nil {
return fmt.Errorf("failed to apply %v to %v using type %v and value '%v'", key, fieldName, f.Type().String(), value)
return fmt.Errorf("failed to apply %v to %v using type %v and value '%v'", key, fieldKey, f.Type().String(), value)

}
f.SetFloat(floatValue)
Expand Down
2 changes: 1 addition & 1 deletion cmd/influxd/run/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3432,7 +3432,7 @@ func TestServer_Query_WildcardExpansion(t *testing.T) {
exp: `{"results":[{"series":[{"name":"wildcard","columns":["time","c","h","region","value"],"values":[["2000-01-01T00:00:00Z",80,"A","us-east",10],["2000-01-01T00:00:10Z",90,"B","us-east",20],["2000-01-01T00:00:20Z",70,"B","us-west",30],["2000-01-01T00:00:30Z",60,"A","us-east",40]]}]}]}`,
},
&Query{
name: "duplicate tag and field name, always favor field over tag",
name: "duplicate tag and field key, always favor field over tag",
command: `SELECT * FROM dupnames`,
params: url.Values{"db": []string{"db0"}},
exp: `{"results":[{"series":[{"name":"dupnames","columns":["time","day","region","value"],"values":[["2000-01-01T00:00:00Z",3,"us-east",10],["2000-01-01T00:00:10Z",2,"us-east",20],["2000-01-01T00:00:20Z",1,"us-west",30]]}]}]}`,
Expand Down
4 changes: 2 additions & 2 deletions influxql/INFLUXQL.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ digit = "0" … "9" .

## Identifiers

Identifiers are tokens which refer to database names, retention policy names, user names, measurement names, tag keys, and field names.
Identifiers are tokens which refer to database names, retention policy names, user names, measurement names, tag keys, and field keys.

The rules:

Expand Down Expand Up @@ -652,7 +652,7 @@ privilege = "ALL" [ "PRIVILEGES" ] | "READ" | "WRITE" .
series_id = int_lit .
sort_field = field_name [ ASC | DESC ] .
sort_field = field_key [ ASC | DESC ] .
sort_fields = sort_field { "," sort_field } .
Expand Down
12 changes: 6 additions & 6 deletions models/points.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,21 +248,21 @@ func scanKey(buf []byte, i int) (int, []byte, error) {
break
}

// equals is special in the tags section. It must be escaped if part of a tag name or value.
// equals is special in the tags section. It must be escaped if part of a tag key or value.
// It does not need to be escaped if part of the measurement.
if buf[i] == '=' && commas > 0 {
if i-1 < 0 || i-2 < 0 {
return i, buf[start:i], fmt.Errorf("missing tag name")
return i, buf[start:i], fmt.Errorf("missing tag key")
}

// Check for "cpu,=value" but allow "cpu,a\,=value"
if buf[i-1] == ',' && buf[i-2] != '\\' {
return i, buf[start:i], fmt.Errorf("missing tag name")
return i, buf[start:i], fmt.Errorf("missing tag key")
}

// Check for "cpu,\ =value"
if buf[i-1] == ' ' && buf[i-2] != '\\' {
return i, buf[start:i], fmt.Errorf("missing tag name")
return i, buf[start:i], fmt.Errorf("missing tag key")
}

i += 1
Expand Down Expand Up @@ -459,12 +459,12 @@ func scanFields(buf []byte, i int) (int, []byte, error) {

// check for "... =123" but allow "a\ =123"
if buf[i-1] == ' ' && buf[i-2] != '\\' {
return i, buf[start:i], fmt.Errorf("missing field name")
return i, buf[start:i], fmt.Errorf("missing field key")
}

// check for "...a=123,=456" but allow "a=123,a\,=456"
if buf[i-1] == ',' && buf[i-2] != '\\' {
return i, buf[start:i], fmt.Errorf("missing field name")
return i, buf[start:i], fmt.Errorf("missing field key")
}

// check for "... value="
Expand Down
16 changes: 8 additions & 8 deletions models/points_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ func TestParsePointMissingQuote(t *testing.T) {
}
}

func TestParsePointMissingTagName(t *testing.T) {
func TestParsePointMissingTagKey(t *testing.T) {
_, err := models.ParsePointsString(`cpu,host=serverA,=us-east value=1i`)
if err == nil {
t.Errorf(`ParsePoints("%s") mismatch. got nil, exp error`, `cpu,host=serverA,=us-east value=1i`)
Expand Down Expand Up @@ -560,7 +560,7 @@ func TestParsePointUnescape(t *testing.T) {
test(t, `cpu,region\,zone=east value=1.0`,
models.NewPoint("cpu",
models.Tags{
"region,zone": "east", // comma in the tag name
"region,zone": "east", // comma in the tag key
},
models.Fields{
"value": 1.0,
Expand All @@ -571,7 +571,7 @@ func TestParsePointUnescape(t *testing.T) {
test(t, `cpu,region\ zone=east value=1.0`,
models.NewPoint("cpu",
models.Tags{
"region zone": "east", // comma in the tag name
"region zone": "east", // comma in the tag key
},
models.Fields{
"value": 1.0,
Expand Down Expand Up @@ -600,25 +600,25 @@ func TestParsePointUnescape(t *testing.T) {
},
time.Unix(0, 0)))

// commas in field names
// commas in field keys
test(t, `cpu,regions=east value\,ms=1.0`,
models.NewPoint("cpu",
models.Tags{
"regions": "east",
},
models.Fields{
"value,ms": 1.0, // comma in the field name
"value,ms": 1.0, // comma in the field keys
},
time.Unix(0, 0)))

// spaces in field names
// spaces in field keys
test(t, `cpu,regions=east value\ ms=1.0`,
models.NewPoint("cpu",
models.Tags{
"regions": "east",
},
models.Fields{
"value ms": 1.0, // comma in the field name
"value ms": 1.0, // comma in the field keys
},
time.Unix(0, 0)))

Expand Down Expand Up @@ -657,7 +657,7 @@ func TestParsePointUnescape(t *testing.T) {
},
time.Unix(0, 0)))

// field name using escape char.
// field keys using escape char.
test(t, `cpu \a=1i`,
models.NewPoint(
"cpu",
Expand Down
6 changes: 3 additions & 3 deletions services/graphite/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ To extract tags from metrics, one or more templates must be configured to parse

## Templates

Templates allow matching parts of a metric name to be used as tag names in the stored metric. They have a similar format to graphite metric names. The values in between the separators are used as the tag name. The location of the tag name that matches the same position as the graphite metric section is used as the value. If there is no value, the graphite portion is skipped.
Templates allow matching parts of a metric name to be used as tag keys in the stored metric. They have a similar format to graphite metric names. The values in between the separators are used as the tag keys. The location of the tag key that matches the same position as the graphite metric section is used as the value. If there is no value, the graphite portion is skipped.

The special value _measurement_ is used to define the measurement name. It can have a trailing `*` to indicate that the remainder of the metric should be used. If a _measurement_ is not specified, the full metric name is used.

Expand Down Expand Up @@ -50,7 +50,7 @@ Additional tags can be added to a metric that don't exist on the received metric

### Fields

A field name can be specified by using the keyword _field_. By default if no _field_ keyword is specified then the metric will be written to a field named _value_.
A field key can be specified by using the keyword _field_. By default if no _field_ keyword is specified then the metric will be written to a field named _value_.

When using the current default engine _BZ1_, it's recommended to use a single field per value for performance reasons.

Expand Down Expand Up @@ -158,7 +158,7 @@ If you need to add the same set of tags to all metrics, you can define them glob
# filter + template + extra tag
"stats.* .host.measurement* region=us-west,agent=sensu",
# filter + template with field name
# filter + template with field key
"stats.* .host.measurement.field",
# default template. Ignore the first graphite component "servers"
Expand Down
2 changes: 1 addition & 1 deletion tsdb/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (db *DatabaseIndex) measurementsByExpr(expr influxql.Expr) (Measurements, e
case influxql.EQ, influxql.NEQ, influxql.EQREGEX, influxql.NEQREGEX:
tag, ok := e.LHS.(*influxql.VarRef)
if !ok {
return nil, fmt.Errorf("left side of '%s' must be a tag name", e.Op.String())
return nil, fmt.Errorf("left side of '%s' must be a tag key", e.Op.String())
}

tf := &TagFilter{
Expand Down

0 comments on commit 82f104a

Please sign in to comment.