diff --git a/chronograf.go b/chronograf.go index ec6dbd49ad..0a0beeeddb 100644 --- a/chronograf.go +++ b/chronograf.go @@ -166,6 +166,7 @@ type Query struct { Command string `json:"query"` // Command is the query itself DB string `json:"db,omitempty"` // DB is optional and if empty will not be used. RP string `json:"rp,omitempty"` // RP is a retention policy and optional; if empty will not be used. + Epoch string `json:"epoch,omitempty"` // Epoch is the time format for the return results TemplateVars []TemplateVar `json:"tempVars,omitempty"` // TemplateVars are template variables to replace within an InfluxQL query Wheres []string `json:"wheres,omitempty"` // Wheres restricts the query to certain attributes GroupBys []string `json:"groupbys,omitempty"` // GroupBys collate the query by these tags diff --git a/influx/annotations.go b/influx/annotations.go index be7f41ddfe..6f22f0f45e 100644 --- a/influx/annotations.go +++ b/influx/annotations.go @@ -137,7 +137,8 @@ func (r *annotationResults) Annotations() (res []chronograf.Annotation, err erro func (c *Client) queryAnnotations(ctx context.Context, query string) ([]chronograf.Annotation, error) { res, err := c.Query(ctx, chronograf.Query{ Command: query, - DB: `chronograf`, + DB: DefaultDB, + Epoch: "ns", }) if err != nil { return nil, err diff --git a/influx/influx.go b/influx/influx.go index ecf67b94e9..391e55e3c1 100644 --- a/influx/influx.go +++ b/influx/influx.go @@ -74,7 +74,10 @@ func (c *Client) query(u *url.URL, q chronograf.Query) (chronograf.Response, err params.Set("q", command) params.Set("db", q.DB) params.Set("rp", q.RP) - params.Set("epoch", "ms") // TODO(timraymond): set this based on analysis + params.Set("epoch", "ms") + if q.Epoch != "" { + params.Set("epoch", q.Epoch) + } req.URL.RawQuery = params.Encode() if c.Authorizer != nil { diff --git a/influx/lineprotocol.go b/influx/lineprotocol.go new file mode 100644 index 0000000000..352791d7eb --- /dev/null +++ b/influx/lineprotocol.go @@ -0,0 +1,66 @@ +package influx + +import ( + "fmt" + "sort" + "strings" + + "github.com/influxdata/chronograf" +) + +var ( + escapeMeasurement = strings.NewReplacer( + `,` /* to */, `\,`, + ` ` /* to */, `\ `, + ) + escapeKeys = strings.NewReplacer( + `,` /* to */, `\,`, + `"` /* to */, `\"`, + ` ` /* to */, `\ `, + `=` /* to */, `\=`, + ) + escapeTagValues = strings.NewReplacer( + `,` /* to */, `\,`, + `"` /* to */, `\"`, + ` ` /* to */, `\ `, + `=` /* to */, `\=`, + ) + escapeFieldStrings = strings.NewReplacer( + `"` /* to */, `\"`, + `\` /* to */, `\\`, + ) +) + +func toLineProtocol(point *chronograf.Point) string { + measurement := escapeMeasurement.Replace(point.Measurement) + tags := []string{} + for tag, value := range point.Tags { + t := fmt.Sprintf("%s=%s", escapeKeys.Replace(tag), escapeTagValues.Replace(value)) + tags = append(tags, t) + } + // it is faster to insert data into influx db if the tags are sorted + sort.Strings(tags) + + fields := []string{} + for field, value := range point.Fields { + var format string + switch v := value.(type) { + case int64, int32, int16, int8, int: + format = fmt.Sprintf("%s=%di", escapeKeys.Replace(field), v) + case uint64, uint32, uint16, uint8, uint: + format = fmt.Sprintf("%s=%du", escapeKeys.Replace(field), v) + case float64, float32: + format = fmt.Sprintf("%s=%f", escapeKeys.Replace(field), v) + case string: + format = fmt.Sprintf("%s=%s", escapeKeys.Replace(field), escapeFieldStrings.Replace(v)) + case bool: + format = fmt.Sprintf("%s=%t", escapeKeys.Replace(field), v) + } + fields = append(fields, format) + } + return fmt.Sprintf("%s,%s %s %d\n", + measurement, + strings.Join(tags, ","), + strings.Join(fields, ","), + point.Time) +} diff --git a/server/swagger.json b/server/swagger.json index 0dc228c956..109ad32f7a 100644 --- a/server/swagger.json +++ b/server/swagger.json @@ -550,7 +550,8 @@ "patch": { "tags": ["sources", "users"], "summary": "Update user configuration", - "description": "Update one parameter at a time (one of password, permissions or roles)", + "description": + "Update one parameter at a time (one of password, permissions or roles)", "parameters": [ { "name": "id", @@ -3139,7 +3140,7 @@ "rp": "autogen", "tempVars": [ { - "tempVar": "$myfield", + "tempVar": ":myfield:", "values": [ { "type": "fieldKey", @@ -3160,6 +3161,11 @@ "rp": { "type": "string" }, + "epoch": { + "description": "timestamp return format", + "type": "string", + "enum": ["h", "m", "s", "ms", "u", "ns"] + }, "tempVars": { "type": "array", "description":