Merge pull request #1881 from influxdb/client-readme

Client readme
pull/1893/head
Cory LaNou 2015-03-09 14:50:37 -06:00
commit e11262c398
5 changed files with 49 additions and 20 deletions

View File

@ -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]

View File

@ -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).

View File

@ -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()
} }

View File

@ -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)
} }

View File

@ -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)