greptime

package module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 10, 2023 License: Apache-2.0 Imports: 17 Imported by: 0

README

License Build Status codecov Go Reference

GreptimeDB Go Client

Provide API for using GreptimeDB client in Go.

Installation

go get github.com/GreptimeTeam/greptimedb-client-go

Example

you can visit Documentation for usage details and documentation,

Usage

Datatype Supported
  • int8, int16, int32, int64, int
  • uint8, uint16, uint32, uint64, uint
  • float32, float64
  • bool
  • []byte
  • string
  • time.Time
Timestamp

you can customize timestamp index via calling methods of Metric

precision

The default timestamp column precision is Millisecond, you can set a different precision. And once the precision is setted, you can not change it any more.

  • time.Second
  • time.Millisecond
  • time.Microsecond
  • time.Nanosecond
metric.SetTimePrecision(time.Microsecond)
alias

The default timestamp column name is ts, if you want to use another name, you can change it:

metric.SetTimestampAlias("timestamp")
Prometheus

How to query with RangePromql and Promql, you can visit promql_test.go for details

Stream Insert

You can send several insert requests by Send() and notify GreptimeDB no more messages by CloseAndRecv()

You can visit stream_client_test.go for details

License

This greptimedb-client-go uses the Apache 2.0 license to strike a balance between open contributions and allowing you to use the software however you want.

Documentation

Overview

Package greptime provides API for using GreptimeDB client in Go.

Basic Insert and Query

You can call NewClient with Config to init a concurrent safe Client, and construct rows of data by Metric and Series, call Client.Insert to insert InsertsRequest into greptimedb, and call Client.Query to retrieve data from greptimedb via QueryRequest.

Promql

You can also call Client.PromqlQuery to retrieve data in []byte format, which is absolutely the same as Prometheus. You can choose InstantPromql or RangePromql to get vector or matrix result.

Series

You don't need to create the table, it will be created automatically via Series fields. What you have to know about Series in advance:

  • Tag is like index, it helps you to retrieve data more efficiently
  • Field is like value, it can be used to analyze, calculate, aggregate, etc,.
  • Timestamp is required for timeseries data

Once the schema is created automatically, it can not be changed by Client, it will fail if the column type does not match

Metric

Metric is like multiple Series, it will check if all of the Series are valid:

  • the same column name in different series: data type MUST BE the same
  • Tag and Field MUST NOT contain the same column name
  • timestamp MUST NOT BE empty

Also, Metric can set:

Example
package main

import (
	"context"
	"fmt"
	"time"

	greptime "github.com/GreptimeTeam/greptimedb-client-go"
	"github.com/GreptimeTeam/greptimedb-client-go/prom"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

var (
	client *greptime.Client

	// monitorTable used in this Example, you don't have to create it in advance,
	// if the monitorTable not exist, it will be created automatically.
	monitorTable string = "monitor"
)

// initClient creates a client with config.
//
// `Username` and `Password` are needed when connecting to a database that requires authentication.
// Leave the two fields empty if connecting a database without authentication.
func initClient() {
	options := []grpc.DialOption{
		grpc.WithTransportCredentials(insecure.NewCredentials()),
	}
	cfg := greptime.NewCfg("127.0.0.1").
		WithPort(4001).         // default is 4001.
		WithDatabase("public"). // specify your database
		WithAuth("", "").
		WithDialOptions(options...). // specify your gRPC dail options
		WithCallOptions()            // specify your gRPC call options
	c, err := greptime.NewClient(cfg)
	if err != nil {
		panic("failed to init client")
	}
	client = c
}

// insert one Series
//   - Tag is index column, for query efficiency
//   - Field is value column
//   - Timestamp is required
//
// you can specify the column type, or let the type checking to be done by sdk
//
//   - series.AddTag
//   - series.AddField
//   - series.AddXxxTag
//   - series.AddXxxField
func constructInsertRequest(table string) greptime.InsertRequest {
	series := greptime.Series{}
	series.AddTag("region", "az")            // type is checked automatically
	series.AddStringTag("host", "localhost") // type is specified by user
	series.AddFloatField("cpu", 0.90)        // type is specified by user
	series.AddField("memory", 1024)          // type is checked automatically
	series.SetTimestamp(time.Now())

	metric := greptime.Metric{}
	metric.AddSeries(series)

	// Create an InsertRequest using fluent style
	// the specified table will be created automatically if it's not exist
	insertRequest := greptime.InsertRequest{}
	insertRequest.WithTable(table).WithMetric(metric)

	return insertRequest
}

func insert() {
	insertsRequest := greptime.InsertsRequest{}
	// You can insert data of different tables into greptimedb in one InsertsRequest.
	// This insertsRequest includes two InsertRequest of two different tables
	insertsRequest.
		Append(constructInsertRequest(monitorTable)).
		Append(constructInsertRequest("temperatures"))

	// if you want to insert into different table in one request, you can construct
	// another InsertRequest, and include it via: insertsRequest.Insert(insertRequest)

	// if you want to specify another database, you can specify it via: `WithDatabase(database)`
	// insertsRequest.WithDatabase("your database")

	// Fire the real Inserts request and Get the affected number of rows
	resp, err := client.Insert(context.Background(), insertsRequest)
	if err != nil {
		fmt.Printf("fail to insert, err: %+v\n", err)
		return
	}
	fmt.Printf("AffectedRows: %d\n", resp.GetAffectedRows().GetValue())
}

// queryViaSql via Sql
//
// you can get the column by type, or do the type conversion by yourself
//
//   - series.Get     // you have to do the conversion explitely
//   - series.GetXxx  // GetFloat, GetInt, GetUint, GetString, GetBool, GetBytes
func queryViaSql() {
	// Monitor is the metrics used in this Example
	type Monitor struct {
		region string
		host   string
		cpu    float64
		memory int64
		ts     time.Time
	}

	req := greptime.QueryRequest{}
	// if you want to specify another database, you can specify it via: `WithDatabase(database)`
	req.WithSql("SELECT * FROM " + monitorTable) // .WithDatabase(database)

	resMetric, err := client.Query(context.Background(), req)
	if err != nil {
		fmt.Printf("fail to query, err: %+v\n", err)
		return
	}

	monitors := []Monitor{}
	for _, series := range resMetric.GetSeries() {
		monitor := &Monitor{}
		host, exist := series.Get("host") // you can directly call Get and do the type assertion
		if exist {
			monitor.host = host.(string)
		}
		monitor.region, _ = series.GetString("region")
		monitor.cpu, _ = series.GetFloat("cpu")     // also, you can directly GetFloat
		monitor.memory, _ = series.GetInt("memory") // also, you can directly GetInt
		monitor.ts, _ = series.GetTimestamp("ts")   // GetTimestamp
		monitors = append(monitors, *monitor)
	}
	fmt.Println(monitors)
}

// the response format is in []byte, and is absolutely the same as Prometheus
func queryViaInstantPromql() {
	promql := greptime.NewInstantPromql(monitorTable)
	req := greptime.QueryRequest{}
	req.WithInstantPromql(promql)
	resp, err := client.PromqlQuery(context.Background(), req)
	if err != nil {
		fmt.Printf("failed to do instant promql query: %+v\n", err)
		return
	}

	// you can use prom package to unmarshal the response as you want
	result, err := prom.UnmarshalApiResponse(resp.GetBody())
	if err != nil {
		fmt.Printf("failed to unmarshal instant promql, body: %s, err: %+v", string(resp.GetBody()), err)
		return
	}
	fmt.Printf("%s:\n%+v\n", result.Type, result.Val)

}

// the response format is in []byte, and is absolutely the same as Prometheus
func queryViaRangePromql() {
	end := time.Now()
	start := end.Add(time.Duration(-15) * time.Second) // 15 seconds before
	promql := greptime.NewRangePromql(monitorTable).WithStart(start).WithEnd(end).WithStep(time.Second)
	req := greptime.QueryRequest{}
	req.WithRangePromql(promql)
	resp, err := client.PromqlQuery(context.Background(), req)
	if err != nil {
		fmt.Printf("failed to do range promql query: %+v\n", err)
		return
	}

	// you can use prom package to unmarshal the response as you want
	result, err := prom.UnmarshalApiResponse(resp.GetBody())
	if err != nil {
		fmt.Printf("failed to unmarshal instant promql, body: %s, err: %+v", string(resp.GetBody()), err)
		return
	}
	fmt.Printf("%s:\n%+v\n", result.Type, result.Val)
}

func main() {
	initClient()
	insert()

	queryViaSql()
	queryViaInstantPromql()
	queryViaRangePromql()
}
Output:

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrEmptyDatabase        = errors.New("name of database should not be empty")
	ErrEmptyTable           = errors.New("name of table should not be be empty")
	ErrEmptyInserts         = errors.New("at least one insert is required in InsertsRequest")
	ErrEmptyTimestamp       = errors.New("timestamp should not be empty")
	ErrEmptyQuery           = errors.New("query should not be empty, assign Sql, InstantPromql or RangePromql")
	ErrEmptyKey             = errors.New("key should not be empty")
	ErrEmptySql             = errors.New("sql is required in querying")
	ErrEmptyPromql          = errors.New("promql is required in promql querying")
	ErrEmptyStep            = errors.New("step is required in range promql")
	ErrEmptyRange           = errors.New("start and end is required in range promql")
	ErrInvalidTimePrecision = errors.New("precision of timestamp is not valid")
	ErrNoSeriesInMetric     = errors.New("empty series in Metric")
	ErrNotImplemented       = errors.New("not implemented!")
	ErrSqlInPromql          = errors.New("Sql can not be used as Promql")
)

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client helps to Insert/Query data Into/From GreptimeDB. A Client is safe for concurrent use by multiple goroutines,you can have one Client instance in your application.

func NewClient

func NewClient(cfg *Config) (*Client, error)

NewClient helps to create the greptimedb client, which will be responsible Write/Read data To/From GreptimeDB

func (*Client) Insert

Insert helps to insert multiple rows of multiple tables into greptimedb

func (*Client) PromqlQuery added in v0.0.7

func (c *Client) PromqlQuery(ctx context.Context, req QueryRequest) (*greptimepb.PromqlResponse, error)

PromqlQuery helps to retrieve data from greptimedb via InstantQuery or RangeQuery

func (*Client) Query

func (c *Client) Query(ctx context.Context, req QueryRequest) (*Metric, error)

Query helps to retrieve data from greptimedb

type Config

type Config struct {
	Host     string // example: 127.0.0.1
	Port     int    // default: 4001
	Username string
	Password string
	Database string // the default database for client

	// DialOptions are passed to grpc.DialContext
	// when a new gRPC connection is to be created.
	DialOptions []grpc.DialOption

	// CallOptions are passed to StreamClient
	CallOptions []grpc.CallOption
}

Config is to define how the Client behaves.

  • Host is 127.0.0.1 in local environment.
  • Port default value is 4001.
  • Username and Password can be left to empty in local environment. you can find them in GreptimeCloud service detail page.
  • Database is the default database the client will operate on. But you can change the database in InsertRequest or QueryRequest.
  • DialOptions and CallOptions are for gRPC service. You can specify them or leave them empty.

func NewCfg

func NewCfg(host string) *Config

NewCfg helps to init Config with host only

func (*Config) WithAuth added in v0.0.3

func (c *Config) WithAuth(username, password string) *Config

WithAuth helps to specify the Basic Auth username and password

func (*Config) WithCallOptions

func (c *Config) WithCallOptions(options ...grpc.CallOption) *Config

func (*Config) WithDatabase

func (c *Config) WithDatabase(database string) *Config

WithDatabase helps to specify the default database the client operates on.

func (*Config) WithDialOptions

func (c *Config) WithDialOptions(options ...grpc.DialOption) *Config

func (*Config) WithPort added in v0.0.3

func (c *Config) WithPort(port int) *Config

WithPort set the Port field. Do not change it if you have no idea what it is.

type InsertRequest

type InsertRequest struct {
	// contains filtered or unexported fields
}

InsertRequest insert metric to specified table. You can also specify the database in header.

func (*InsertRequest) RowCount

func (r *InsertRequest) RowCount() uint32

func (*InsertRequest) WithMetric

func (r *InsertRequest) WithMetric(metric Metric) *InsertRequest

func (*InsertRequest) WithTable

func (r *InsertRequest) WithTable(table string) *InsertRequest

type InsertsRequest added in v0.0.8

type InsertsRequest struct {
	// contains filtered or unexported fields
}

func (*InsertsRequest) Append added in v0.1.0

func (r *InsertsRequest) Append(insert InsertRequest) *InsertsRequest

Append will include one insert into this InsertsRequest

func (*InsertsRequest) WithDatabase added in v0.0.8

func (r *InsertsRequest) WithDatabase(database string) *InsertsRequest

WithDatabase helps to specify different database from the default one.

type InstantPromql added in v0.0.7

type InstantPromql struct {
	Query string
	Ts    time.Time
}

InstantPromql helps to fire a request to greptimedb compatible with Prometheus instant query, you can visit instant query for detail.

func NewInstantPromql added in v0.0.7

func NewInstantPromql(query string) *InstantPromql

func (*InstantPromql) WithQuery added in v0.0.7

func (ip *InstantPromql) WithQuery(query string) *InstantPromql

WithQuery helps to update the query

func (*InstantPromql) WithTime added in v0.0.7

func (ip *InstantPromql) WithTime(ts time.Time) *InstantPromql

WithTime to specify the evaluation time. Default is now.

type Metric

type Metric struct {
	// contains filtered or unexported fields
}

Metric represents multiple rows of data, and also Metric can specify the timestamp column name and precision

func (*Metric) AddSeries

func (m *Metric) AddSeries(s Series) error

AddSeries add one row to Metric.

Pay Attention

  • different row can have different fields, Metric will union all the columns, leave empty value of one row if the column is not specified in this row
  • same column name MUST have same schema, which means Tag,Field,Timestamp and data type MUST BE the same of the same column name in different rows

func (*Metric) GetSeries

func (m *Metric) GetSeries() []Series

GetSeries gets all data from metric

func (*Metric) GetTagsAndFields

func (m *Metric) GetTagsAndFields() []string

GetTagsAndFields get all column names from metric, except timestamp column

func (*Metric) GetTimestampAlias

func (m *Metric) GetTimestampAlias() string

GetTimestampAlias get the timestamp column name, default is ts.

func (*Metric) SetTimePrecision

func (m *Metric) SetTimePrecision(precision time.Duration) error

SetTimePrecision set precision for Metric. Valid durations include:

  • time.Nanosecond
  • time.Microsecond
  • time.Millisecond
  • time.Second.

Pay attention

  • once the precision has been set, it can not be changed
  • insert will fail if precision does not match with the existing precision of the schema in greptimedb

func (*Metric) SetTimestampAlias

func (m *Metric) SetTimestampAlias(alias string) error

SetTimestampAlias helps to specify the timestamp column name, default is ts.

type QueryRequest

type QueryRequest struct {
	// contains filtered or unexported fields
}

QueryRequest helps to query data from greptimedb, and the response is in Metric. But if you expect the response format is the same as Prometheus, you should consider [PromqlRequest].

At least one of Sql, InstantPromql, RangePromql MUST be spicified. If multiple fields are specified, the field specified later will be used

func NewQueryRequest added in v0.1.0

func NewQueryRequest() *QueryRequest

func (*QueryRequest) WithDatabase

func (r *QueryRequest) WithDatabase(database string) *QueryRequest

WithDatabase helps to specify different database from the default one.

func (*QueryRequest) WithInstantPromql added in v0.0.7

func (r *QueryRequest) WithInstantPromql(instantPromql *InstantPromql) *QueryRequest

func (*QueryRequest) WithRangePromql

func (r *QueryRequest) WithRangePromql(rangePromql *RangePromql) *QueryRequest

func (*QueryRequest) WithSql

func (r *QueryRequest) WithSql(sql string) *QueryRequest

type RangePromql

type RangePromql struct {
	Query string
	Start time.Time
	End   time.Time
	Step  time.Duration
}

RangePromql helps to fire a request to greptimedb compatible with Prometheus range query, you can visit range query for detail.

func NewRangePromql added in v0.0.7

func NewRangePromql(query string) *RangePromql

func (*RangePromql) WithEnd added in v0.0.7

func (rp *RangePromql) WithEnd(end time.Time) *RangePromql

WithEnd helps to specify the end of the range

func (*RangePromql) WithQuery added in v0.0.7

func (rp *RangePromql) WithQuery(query string) *RangePromql

WithQuery helps to update the query

func (*RangePromql) WithStart added in v0.0.7

func (rp *RangePromql) WithStart(start time.Time) *RangePromql

WithStart helps to specify the start of the range

func (*RangePromql) WithStep added in v0.0.7

func (rp *RangePromql) WithStep(step time.Duration) *RangePromql

WithStep helps to specify the step of the range

type RespHeader added in v0.1.0

type RespHeader struct {
	Code uint32
	Msg  string
}

func ParseRespHeader added in v0.1.0

func ParseRespHeader[T getRespHeader](r T) RespHeader

func (RespHeader) IsNil added in v0.1.0

func (h RespHeader) IsNil() bool

func (RespHeader) IsRateLimited added in v0.1.0

func (h RespHeader) IsRateLimited() bool

func (RespHeader) IsSuccess added in v0.1.0

func (h RespHeader) IsSuccess() bool

type Series

type Series struct {
	// contains filtered or unexported fields
}

Series represents one row of data you want to insert into GreptimeDB.

  • Tag fields are the index columns, which helps you to query data efficiently
  • Field fields are the value columns, which are used for value
  • Timestamp field is the timestamp column, which is required

you do not need to create schema in advance, it will be created based on Series. But once the schema is created, Client has no ability to alert it.

func (*Series) AddBoolField added in v0.0.5

func (s *Series) AddBoolField(key string, val bool) error

AddBoolField helps to constrain the key to be bool type

func (*Series) AddBoolTag added in v0.0.5

func (s *Series) AddBoolTag(key string, val bool) error

AddBoolTag helps to constrain the key to be bool type

func (*Series) AddBytesField added in v0.0.5

func (s *Series) AddBytesField(key string, val []byte) error

AddBytesField helps to constrain the key to be []byte type

func (*Series) AddBytesTag added in v0.0.5

func (s *Series) AddBytesTag(key string, val []byte) error

AddBytesTag helps to constrain the key to be []byte type

func (*Series) AddField

func (s *Series) AddField(key string, val any) error

AddField prepare field column, and old value will be replaced if same field is set. the length of key CAN NOT be longer than 100

func (*Series) AddFloatField added in v0.0.5

func (s *Series) AddFloatField(key string, val float64) error

AddFloatField helps to constrain the key to be float64 type, if you want to add float32 tag instead of float64, you can do it like:

var i float32 = 1.0
return s.AddFloatField("memory", float64(i))

func (*Series) AddFloatTag added in v0.0.5

func (s *Series) AddFloatTag(key string, val float64) error

AddFloatTag helps to constrain the key to be float64 type, if you want to add float32 tag instead of float64, you can do it like:

var i float32 = 1.0
return s.AddFloatTag("memory", float64(i))

func (*Series) AddIntField added in v0.0.5

func (s *Series) AddIntField(key string, val int64) error

AddIntField helps to constrain the key to be int64 type, if you want to add int32 tag instead of int64, you can do it like:

var i int32 = 1
return s.AddIntField("account", int64(i))

func (*Series) AddIntTag added in v0.0.5

func (s *Series) AddIntTag(key string, val int64) error

AddIntTag helps to constrain the key to be int64 type, if you want to add int32 tag instead of int64, you can do it like:

var i int32 = 1
return s.AddIntTag("account", int64(i))

func (*Series) AddStringField added in v0.0.5

func (s *Series) AddStringField(key string, val string) error

AddStringField helps to constrain the key to be string type

func (*Series) AddStringTag added in v0.0.5

func (s *Series) AddStringTag(key string, val string) error

AddStringTag helps to constrain the key to be string type

func (*Series) AddTag

func (s *Series) AddTag(key string, val any) error

AddTag prepare tag column, and old value will be replaced if same tag is set. the length of key CAN NOT be longer than 100. If you want to contain the column type, you can directly use like:

func (*Series) AddUintField added in v0.0.5

func (s *Series) AddUintField(key string, val uint64) error

AddUintField helps to constrain the key to be uint64 type, if you want to add uint32 tag instead of uint64, you can do it like:

var i uint32 = 1
return s.AddUintField("account", uint64(i))

func (*Series) AddUintTag added in v0.0.5

func (s *Series) AddUintTag(key string, val uint64) error

AddUintTag helps to constrain the key to be uint64 type, if you want to add uint32 tag instead of uint64, you can do it like:

var i uint32 = 1
return s.AddUintTag("account", uint64(i))

func (*Series) Get

func (s *Series) Get(key string) (any, bool)

Get helps to get value of specified column. The second return value indicates if the key was present in Series

func (*Series) GetBool added in v0.0.4

func (s *Series) GetBool(key string) (bool, bool)

func (*Series) GetBytes added in v0.0.4

func (s *Series) GetBytes(key string) ([]byte, bool)

func (*Series) GetFloat added in v0.0.4

func (s *Series) GetFloat(key string) (float64, bool)

GetFloat helps to get float64 type of the specified key. It can retrieve the following type:

  • float64
  • float32

if you want float32 instead of float64, you can do it like:

if v, ok := s.GetFloat(key); ok {
	val := float32(v)
}

func (*Series) GetInt added in v0.0.4

func (s *Series) GetInt(key string) (int64, bool)

GetInt helps to get int64 type of the specified key. It can retrieve the following type:

  • int64
  • int32
  • int16
  • int8
  • int

if you want int32 instead of int64, you can do it like:

if v, ok := s.GetInt(key); ok {
	val := int32(v)
}

func (*Series) GetString added in v0.0.4

func (s *Series) GetString(key string) (string, bool)

func (*Series) GetTagsAndFields

func (s *Series) GetTagsAndFields() []string

GetTagsAndFields get all column names from metric, except timestamp column

func (*Series) GetTimestamp

func (s *Series) GetTimestamp(key string) (time.Time, bool)

func (*Series) GetUint added in v0.0.4

func (s *Series) GetUint(key string) (uint64, bool)

GetUint helps to get uint64 type of the specified key. It can retrieve the following type:

  • uint64
  • uint32
  • uint16
  • uint8
  • uint

if you want uint32 instead of uint64, you can do it like:

if v, ok := s.GetUint(key); ok {
	val := uint32(v)
}

func (*Series) SetTimestamp

func (s *Series) SetTimestamp(t time.Time) error

SetTimestamp is required

type Sql added in v0.0.7

type Sql struct {
	// contains filtered or unexported fields
}

Sql helps to fire a request to greptimedb in SQL. It can not be used as Promql Query

type StreamClient

type StreamClient struct {
	// contains filtered or unexported fields
}

StreamClient is only for inserting

func NewStreamClient

func NewStreamClient(cfg *Config) (*StreamClient, error)

NewStreamClient helps to create a stream insert client. If Client has performance issue, you can try the stream client.

func (*StreamClient) CloseAndRecv

func (c *StreamClient) CloseAndRecv(ctx context.Context) (*greptimepb.AffectedRows, error)

func (*StreamClient) Send

func (c *StreamClient) Send(ctx context.Context, req InsertsRequest) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL