commit
e11262c398
|
@ -7,6 +7,7 @@
|
||||||
- [#1877](https://github.com/influxdb/influxdb/pull/1877): Broker clients track broker leader
|
- [#1877](https://github.com/influxdb/influxdb/pull/1877): Broker clients track broker leader
|
||||||
- [#1862](https://github.com/influxdb/influxdb/pull/1862): Fix memory leak in `httpd.serveWait`. Thanks @mountkin
|
- [#1862](https://github.com/influxdb/influxdb/pull/1862): Fix memory leak in `httpd.serveWait`. Thanks @mountkin
|
||||||
- [#1868](https://github.com/influxdb/influxdb/pull/1868): Use `BatchPoints` for `client.Write` method. Thanks @vladlopes, @georgmu, @d2g, @evanphx, @akolosov.
|
- [#1868](https://github.com/influxdb/influxdb/pull/1868): Use `BatchPoints` for `client.Write` method. Thanks @vladlopes, @georgmu, @d2g, @evanphx, @akolosov.
|
||||||
|
- [#1881](https://github.com/influxdb/influxdb/pull/1881): Update documentation for `client` package. Misc library tweaks.
|
||||||
|
|
||||||
## v0.9.0-rc9 [2015-03-06]
|
## v0.9.0-rc9 [2015-03-06]
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
InfluxDB Go Client Library
|
InfluxDB Go Client Library
|
||||||
============
|
============
|
||||||
|
|
||||||
# TODO Add links to the godoc and examples when they are written
|
Please refer to [http://godoc.org/github.com/influxdb/influxdb/client](http://godoc.org/github.com/influxdb/influxdb/client)
|
||||||
|
for documentation.
|
||||||
|
|
||||||
|
# Currently Used:
|
||||||
|
|
||||||
|
You can see a use of the client libray in the [InfluxDB CLI](https://github.com/influxdb/influxdb/blob/master/cmd/influx/main.go).
|
||||||
|
|
|
@ -12,11 +12,16 @@ import (
|
||||||
"github.com/influxdb/influxdb/influxql"
|
"github.com/influxdb/influxdb/influxql"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Query is used to send a command to the server. Both Command and Database are required.
|
||||||
type Query struct {
|
type Query struct {
|
||||||
Command string
|
Command string
|
||||||
Database string
|
Database string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Config is used to specify what server to connect to.
|
||||||
|
// URL: The URL of the server connecting to.
|
||||||
|
// Username/Password are optional. They will be passed via basic auth if provided.
|
||||||
|
// UserAgent: If not provided, will default "InfluxDBClient",
|
||||||
type Config struct {
|
type Config struct {
|
||||||
URL url.URL
|
URL url.URL
|
||||||
Username string
|
Username string
|
||||||
|
@ -24,6 +29,7 @@ type Config struct {
|
||||||
UserAgent string
|
UserAgent string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Client is used to make calls to the server.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
url url.URL
|
url url.URL
|
||||||
username string
|
username string
|
||||||
|
@ -32,6 +38,7 @@ type Client struct {
|
||||||
userAgent string
|
userAgent string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewClient will instantiate and return a connected client to issue commands to the server.
|
||||||
func NewClient(c Config) (*Client, error) {
|
func NewClient(c Config) (*Client, error) {
|
||||||
client := Client{
|
client := Client{
|
||||||
url: c.URL,
|
url: c.URL,
|
||||||
|
@ -40,13 +47,20 @@ func NewClient(c Config) (*Client, error) {
|
||||||
httpClient: &http.Client{},
|
httpClient: &http.Client{},
|
||||||
userAgent: c.UserAgent,
|
userAgent: c.UserAgent,
|
||||||
}
|
}
|
||||||
|
if client.userAgent == "" {
|
||||||
|
client.userAgent = "InfluxDBClient"
|
||||||
|
}
|
||||||
return &client, nil
|
return &client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Query sends a command to the server and returns the Results
|
||||||
func (c *Client) Query(q Query) (*Results, error) {
|
func (c *Client) Query(q Query) (*Results, error) {
|
||||||
u := c.url
|
u := c.url
|
||||||
|
|
||||||
u.Path = "query"
|
u.Path = "query"
|
||||||
|
if c.username != "" {
|
||||||
|
u.User = url.UserPassword(c.username, c.password)
|
||||||
|
}
|
||||||
values := u.Query()
|
values := u.Query()
|
||||||
values.Set("q", q.Command)
|
values.Set("q", q.Command)
|
||||||
values.Set("db", q.Database)
|
values.Set("db", q.Database)
|
||||||
|
@ -56,9 +70,7 @@ func (c *Client) Query(q Query) (*Results, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if c.userAgent != "" {
|
req.Header.Set("User-Agent", c.userAgent)
|
||||||
req.Header.Set("User-Agent", c.userAgent)
|
|
||||||
}
|
|
||||||
resp, err := c.httpClient.Do(req)
|
resp, err := c.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -75,6 +87,9 @@ func (c *Client) Query(q Query) (*Results, error) {
|
||||||
return &results, nil
|
return &results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write takes BatchPoints and allows for writing of multiple points with defaults
|
||||||
|
// If successful, error is nil and Results is nil
|
||||||
|
// If an error occurs, Results may contain additional information if populated.
|
||||||
func (c *Client) Write(bp BatchPoints) (*Results, error) {
|
func (c *Client) Write(bp BatchPoints) (*Results, error) {
|
||||||
c.url.Path = "write"
|
c.url.Path = "write"
|
||||||
|
|
||||||
|
@ -88,9 +103,7 @@ func (c *Client) Write(bp BatchPoints) (*Results, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
if c.userAgent != "" {
|
req.Header.Set("User-Agent", c.userAgent)
|
||||||
req.Header.Set("User-Agent", c.userAgent)
|
|
||||||
}
|
|
||||||
resp, err := c.httpClient.Do(req)
|
resp, err := c.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -109,9 +122,11 @@ func (c *Client) Write(bp BatchPoints) (*Results, error) {
|
||||||
return &results, results.Error()
|
return &results, results.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
return &results, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ping will check to see if the server is up
|
||||||
|
// Ping returns how long the requeset took, the version of the server it connected to, and an error if one occured.
|
||||||
func (c *Client) Ping() (time.Duration, string, error) {
|
func (c *Client) Ping() (time.Duration, string, error) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
u := c.url
|
u := c.url
|
||||||
|
@ -121,9 +136,7 @@ func (c *Client) Ping() (time.Duration, string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, "", err
|
return 0, "", err
|
||||||
}
|
}
|
||||||
if c.userAgent != "" {
|
req.Header.Set("User-Agent", c.userAgent)
|
||||||
req.Header.Set("User-Agent", c.userAgent)
|
|
||||||
}
|
|
||||||
resp, err := c.httpClient.Do(req)
|
resp, err := c.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, "", err
|
return 0, "", err
|
||||||
|
@ -183,7 +196,8 @@ type Results struct {
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Results) MarshalJSON() ([]byte, error) {
|
// MarshalJSON encodes the result into JSON.
|
||||||
|
func (r *Results) MarshalJSON() ([]byte, error) {
|
||||||
// Define a struct that outputs "error" as a string.
|
// Define a struct that outputs "error" as a string.
|
||||||
var o struct {
|
var o struct {
|
||||||
Results []Result `json:"results,omitempty"`
|
Results []Result `json:"results,omitempty"`
|
||||||
|
@ -234,6 +248,9 @@ func (a Results) Error() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Point defines the fields that will be written to the database
|
// Point defines the fields that will be written to the database
|
||||||
|
// Name, Timestamp, and Fields are required
|
||||||
|
// Precision can be specified if the timestamp is in epoch format (integer).
|
||||||
|
// Valid values for Precision are n, u, ms, s, m, and h
|
||||||
type Point struct {
|
type Point struct {
|
||||||
Name string
|
Name string
|
||||||
Tags map[string]string
|
Tags map[string]string
|
||||||
|
@ -341,6 +358,12 @@ func normalizeFields(fields map[string]interface{}) map[string]interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchPoints is used to send batched data in a single write.
|
// BatchPoints is used to send batched data in a single write.
|
||||||
|
// Database and Points are required
|
||||||
|
// If no retention policy is specified, it will use the databases default retention policy.
|
||||||
|
// If tags are specified, they will be "merged" with all points. If a point already has that tag, it is ignored.
|
||||||
|
// If timestamp is specified, it will be applied to any point with an empty timestamp.
|
||||||
|
// Precision can be specified if the timestamp is in epoch format (integer).
|
||||||
|
// Valid values for Precision are n, u, ms, s, m, and h
|
||||||
type BatchPoints struct {
|
type BatchPoints struct {
|
||||||
Points []Point `json:"points,omitempty"`
|
Points []Point `json:"points,omitempty"`
|
||||||
Database string `json:"database,omitempty"`
|
Database string `json:"database,omitempty"`
|
||||||
|
@ -409,6 +432,7 @@ func (bp *BatchPoints) UnmarshalJSON(b []byte) error {
|
||||||
|
|
||||||
// utility functions
|
// utility functions
|
||||||
|
|
||||||
|
// Addr provides the current url as a string of the server the client is connected to.
|
||||||
func (c *Client) Addr() string {
|
func (c *Client) Addr() string {
|
||||||
return c.url.String()
|
return c.url.String()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -134,8 +135,6 @@ func TestClient_UserAgent(t *testing.T) {
|
||||||
t.Fatalf("unexpected error. expected %v, actual %v", nil, err)
|
t.Fatalf("unexpected error. expected %v, actual %v", nil, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultUserAgent := receivedUserAgent
|
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
userAgent string
|
userAgent string
|
||||||
|
@ -144,7 +143,7 @@ func TestClient_UserAgent(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "Empty user agent",
|
name: "Empty user agent",
|
||||||
userAgent: "",
|
userAgent: "",
|
||||||
expected: defaultUserAgent,
|
expected: "InfluxDBClient",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Custom user agent",
|
name: "Custom user agent",
|
||||||
|
@ -167,7 +166,7 @@ func TestClient_UserAgent(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error. expected %v, actual %v", nil, err)
|
t.Fatalf("unexpected error. expected %v, actual %v", nil, err)
|
||||||
}
|
}
|
||||||
if receivedUserAgent != test.expected {
|
if !strings.HasPrefix(receivedUserAgent, test.expected) {
|
||||||
t.Fatalf("Unexpected user agent. expected %v, actual %v", test.expected, receivedUserAgent)
|
t.Fatalf("Unexpected user agent. expected %v, actual %v", test.expected, receivedUserAgent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +176,7 @@ func TestClient_UserAgent(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error. expected %v, actual %v", nil, err)
|
t.Fatalf("unexpected error. expected %v, actual %v", nil, err)
|
||||||
}
|
}
|
||||||
if receivedUserAgent != test.expected {
|
if !strings.HasPrefix(receivedUserAgent, test.expected) {
|
||||||
t.Fatalf("Unexpected user agent. expected %v, actual %v", test.expected, receivedUserAgent)
|
t.Fatalf("Unexpected user agent. expected %v, actual %v", test.expected, receivedUserAgent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -690,7 +690,7 @@ func TestClientLibrary(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no points",
|
name: "no points",
|
||||||
writeExpected: `{}`,
|
writeExpected: `null`,
|
||||||
bp: client.BatchPoints{Database: "mydb"},
|
bp: client.BatchPoints{Database: "mydb"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -701,7 +701,7 @@ func TestClientLibrary(t *testing.T) {
|
||||||
{Name: "cpu", Fields: map[string]interface{}{"value": 1.1}, Timestamp: now},
|
{Name: "cpu", Fields: map[string]interface{}{"value": 1.1}, Timestamp: now},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
writeExpected: `{}`,
|
writeExpected: `null`,
|
||||||
query: client.Query{Command: `select * from "mydb"."myrp".cpu`},
|
query: client.Query{Command: `select * from "mydb"."myrp".cpu`},
|
||||||
queryExpected: fmt.Sprintf(`{"results":[{"series":[{"name":"cpu","columns":["time","value"],"values":[["%s",1.1]]}]}]}`, now.Format(time.RFC3339Nano)),
|
queryExpected: fmt.Sprintf(`{"results":[{"series":[{"name":"cpu","columns":["time","value"],"values":[["%s",1.1]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||||
},
|
},
|
||||||
|
@ -726,7 +726,7 @@ func TestClientLibrary(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if test.query.Command != "" {
|
if test.query.Command != "" {
|
||||||
time.Sleep(50 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
queryResult, err := c.Query(test.query)
|
queryResult, err := c.Query(test.query)
|
||||||
if test.queryErr != errToString(err) {
|
if test.queryErr != errToString(err) {
|
||||||
t.Errorf("unexpected error. expected: %s, got %v", test.queryErr, err)
|
t.Errorf("unexpected error. expected: %s, got %v", test.queryErr, err)
|
||||||
|
|
Loading…
Reference in New Issue