log_project.go (1,194 lines of code) (raw):
package sls
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"reflect"
"regexp"
"strings"
"time"
"github.com/go-kit/kit/log/level"
)
const (
httpScheme = "http://"
httpsScheme = "https://"
ipRegexStr = `\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}.*`
)
var (
ipRegex = regexp.MustCompile(ipRegexStr)
)
// this file is deprecated and no maintenance
// see client_project.go
// DataRedundancyType
const (
PROJECT_DATA_REDUNDANCY_TYPE_UNKNOWN = "Unknown"
PROJECT_DATA_REDUNDANCY_TYPE_LRS = "LRS"
PROJECT_DATA_REDUNDANCY_TYPE_ZRS = "ZRS"
)
// LogProject defines log project
type LogProject struct {
Name string `json:"projectName"` // Project name
Description string `json:"description"` // Project description
Status string `json:"status"` // Normal
Owner string `json:"owner"` // empty
Region string `json:"region"` // region id, eg cn-shanghai
CreateTime string `json:"createTime"` // unix time seconds, eg 1524539357
LastModifyTime string `json:"lastModifyTime"` // unix time seconds, eg 1524539357
DataRedundancyType string `json:"dataRedundancyType,omitempty"` // data redundancy type, valid values: ['LRS', 'ZRS']
Location string `json:"location,omitempty"` // location, eg. cn-beijing-b
Endpoint string // Deprecated: will be made private in the next version
AccessKeyID string // Deprecated: will be made private in the next version
AccessKeySecret string // Deprecated: will be made private in the next version
SecurityToken string // Deprecated: will be made private in the next version
UsingHTTP bool // Deprecated: will be made private in the next version
UserAgent string // Deprecated: will be made private in the next version
AuthVersion AuthVersionType // Deprecated: will be made private in the next version
baseURL string
retryTimeout time.Duration
httpClient *http.Client
credentialProvider CredentialsProvider
// User defined common headers.
//
// When conflict with sdk pre-defined headers, the value will
// be ignored
commonHeaders map[string]string
innerHeaders map[string]string
}
// NewLogProject creates a new SLS project.
//
// Deprecated: use NewLogProjectV2 instead.
func NewLogProject(name, endpoint, accessKeyID, accessKeySecret string) (p *LogProject, err error) {
p = &LogProject{
Name: name,
Endpoint: endpoint,
AccessKeyID: accessKeyID,
AccessKeySecret: accessKeySecret,
httpClient: defaultHttpClient,
retryTimeout: defaultRetryTimeout,
}
p.parseEndpoint()
return p, nil
}
// NewLogProjectV2 creates a new SLS project, with a CredentialsProvider.
func NewLogProjectV2(name, endpoint string, provider CredentialsProvider) (p *LogProject, err error) {
p = &LogProject{
Name: name,
Endpoint: endpoint,
httpClient: defaultHttpClient,
retryTimeout: defaultRetryTimeout,
credentialProvider: provider,
}
p.parseEndpoint()
return p, nil
}
// Deprecated: With credentials provider
func (p *LogProject) WithCredentialsProvider(provider CredentialsProvider) *LogProject {
p.credentialProvider = provider
return p
}
// Deprecated: WithToken add token parameter
func (p *LogProject) WithToken(token string) (*LogProject, error) {
p.SecurityToken = token
return p, nil
}
// Deprecated: WithRequestTimeout with custom timeout for a request
func (p *LogProject) WithRequestTimeout(timeout time.Duration) *LogProject {
if p.httpClient == defaultHttpClient || p.httpClient == nil {
p.httpClient = newDefaultHTTPClient(timeout)
} else {
p.httpClient.Timeout = timeout
}
return p
}
// Deprecated: WithRetryTimeout with custom timeout for a operation
// each operation may send one or more HTTP requests in case of retry required.
func (p *LogProject) WithRetryTimeout(timeout time.Duration) *LogProject {
p.retryTimeout = timeout
return p
}
// RawRequest send raw http request to LogService and return the raw http response
// @note you should call http.Response.Body.Close() to close body stream
func (p *LogProject) RawRequest(method, uri string, headers map[string]string, body []byte) (*http.Response, error) {
ctx := context.Background()
return realRequest(ctx, p, method, uri, headers, body)
}
// ListLogStore returns all logstore names of project p.
func (p *LogProject) ListLogStore() ([]string, error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
uri := "/logstores"
r, err := request(p, "GET", uri, h, nil)
if err != nil {
return nil, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return nil, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
type Body struct {
Count int
LogStores []string
}
body := &Body{}
err = json.Unmarshal(buf, body)
if err != nil {
return nil, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
storeNames := body.LogStores
return storeNames, nil
}
// ListLogStoreV2 ...
func (p *LogProject) ListLogStoreV2(offset, size int, telemetryType string) ([]string, error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
uri := fmt.Sprintf("/logstores?offset=%d&size=%d&telemetryType=%s", offset, size, telemetryType)
r, err := request(p, "GET", uri, h, nil)
if err != nil {
return nil, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return nil, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
type Body struct {
Count int
LogStores []string
}
body := &Body{}
err = json.Unmarshal(buf, body)
if err != nil {
return nil, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
storeNames := body.LogStores
return storeNames, nil
}
// GetLogStore returns logstore according by logstore name.
func (p *LogProject) GetLogStore(name string) (*LogStore, error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "GET", "/logstores/"+name, h, nil)
if err != nil {
return nil, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return nil, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
s := &LogStore{}
err = json.Unmarshal(buf, s)
if err != nil {
return nil, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
s.Name = name
s.project = p
return s, nil
}
// CreateLogStore creates a new logstore in SLS,
// where name is logstore name,
// and ttl is time-to-live(in day) of logs,
// and shardCnt is the number of shards,
// and autoSplit is auto split,
// and maxSplitShard is the max number of shard.
func (p *LogProject) CreateLogStore(name string, ttl, shardCnt int, autoSplit bool, maxSplitShard int) error {
type Body struct {
Name string `json:"logstoreName"`
TTL int `json:"ttl"`
ShardCount int `json:"shardCount"`
AutoSplit bool `json:"autoSplit"`
MaxSplitShard int `json:"maxSplitShard"`
WebTracking bool `json:"enable_tracking"`
}
store := &Body{
Name: name,
TTL: ttl,
ShardCount: shardCnt,
AutoSplit: autoSplit,
MaxSplitShard: maxSplitShard,
}
body, err := json.Marshal(store)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "POST", "/logstores", h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// CreateLogStoreV2 creates a new logstore in SLS
func (p *LogProject) CreateLogStoreV2(logstore *LogStore) error {
body, err := json.Marshal(logstore)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "POST", "/logstores", h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// DeleteLogStore deletes a logstore according by logstore name.
func (p *LogProject) DeleteLogStore(name string) (err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "DELETE", "/logstores/"+name, h, nil)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// UpdateLogStore updates a logstore according by logstore name,
// obviously we can't modify the logstore name itself.
func (p *LogProject) UpdateLogStore(name string, ttl, shardCnt int) (err error) {
type Body struct {
Name string `json:"logstoreName"`
TTL int `json:"ttl"`
ShardCount int `json:"shardCount"`
}
store := &Body{
Name: name,
TTL: ttl,
ShardCount: shardCnt,
}
body, err := json.Marshal(store)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "PUT", "/logstores/"+name, h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// UpdateLogStoreV2 updates a logstore according by logstore name
// obviously we can't modify the logstore name itself.
func (p *LogProject) UpdateLogStoreV2(logstore *LogStore) (err error) {
body, err := json.Marshal(logstore)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "PUT", "/logstores/"+logstore.Name, h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// ListMachineGroup returns machine group name list and the total number of machine groups.
// The offset starts from 0 and the size is the max number of machine groups could be returned.
func (p *LogProject) ListMachineGroup(offset, size int) (m []string, total int, err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
if size <= 0 {
size = 500
}
uri := fmt.Sprintf("/machinegroups?offset=%v&size=%v", offset, size)
r, err := request(p, "GET", uri, h, nil)
if err != nil {
return nil, 0, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, 0, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return nil, 0, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
type Body struct {
MachineGroups []string
Count int
Total int
}
body := &Body{}
err = json.Unmarshal(buf, body)
if err != nil {
return nil, 0, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
m = body.MachineGroups
total = body.Total
return m, total, nil
}
// CheckLogstoreExist check logstore exist or not
func (p *LogProject) CheckLogstoreExist(name string) (bool, error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "GET", "/logstores/"+name, h, nil)
if err != nil {
if _, ok := err.(*Error); ok {
slsErr := err.(*Error)
if slsErr.Code == "LogStoreNotExist" {
return false, nil
}
return false, slsErr
}
return false, err
}
defer r.Body.Close()
return true, nil
}
// CheckMachineGroupExist check machine group exist or not
func (p *LogProject) CheckMachineGroupExist(name string) (bool, error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "GET", "/machinegroups/"+name, h, nil)
if err != nil {
if _, ok := err.(*Error); ok {
slsErr := err.(*Error)
if slsErr.Code == "MachineGroupNotExist" {
return false, nil
}
return false, slsErr
}
return false, err
}
defer r.Body.Close()
return true, nil
}
// GetMachineGroup retruns machine group according by machine group name.
func (p *LogProject) GetMachineGroup(name string) (m *MachineGroup, err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "GET", "/machinegroups/"+name, h, nil)
if err != nil {
return nil, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return nil, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
m = new(MachineGroup)
err = json.Unmarshal(buf, m)
if err != nil {
return nil, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
return m, nil
}
// CreateMachineGroup creates a new machine group in SLS.
func (p *LogProject) CreateMachineGroup(m *MachineGroup) error {
body, err := json.Marshal(m)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "POST", "/machinegroups", h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// UpdateMachineGroup updates a machine group.
func (p *LogProject) UpdateMachineGroup(m *MachineGroup) (err error) {
body, err := json.Marshal(m)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "PUT", "/machinegroups/"+m.Name, h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// DeleteMachineGroup deletes machine group according machine group name.
func (p *LogProject) DeleteMachineGroup(name string) (err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "DELETE", "/machinegroups/"+name, h, nil)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
func (p *LogProject) CreateMetricConfig(metricStore string, metricConfig *MetricsConfig) error {
body, err := json.Marshal(metricConfig)
if err != nil {
return NewClientError(err)
}
jsonBody := map[string]interface{}{
"metricStore": metricStore,
"metricsConfigDetail": string(body),
}
body, err = json.Marshal(jsonBody)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "POST", "/metricsconfigs", h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
body, err = ioutil.ReadAll(r.Body)
if r.StatusCode != http.StatusOK {
err := new(Error)
json.Unmarshal(body, err)
return err
}
return nil
}
func (p *LogProject) DeleteMetricConfig(metricStore string) (err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "DELETE", "/metricsconfigs/"+metricStore, h, nil)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
body, _ := ioutil.ReadAll(r.Body)
if r.StatusCode != http.StatusOK {
err := new(Error)
json.Unmarshal(body, err)
return err
}
return nil
}
func (p *LogProject) GetMetricConfig(metricStore string) (*MetricsConfig, error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "GET", "/metricsconfigs/"+metricStore, h, nil)
if err != nil {
return nil, NewClientError(err)
}
defer r.Body.Close()
buf, _ := ioutil.ReadAll(r.Body)
if r.StatusCode != http.StatusOK {
err := new(Error)
json.Unmarshal(buf, err)
return nil, err
}
type OuterJSON struct {
MetricStore string `json:"metricStore"`
MetricsConfigDetail string `json:"metricsConfigDetail"`
}
var outerData OuterJSON
if err := json.Unmarshal(buf, &outerData); err != nil {
log.Fatalf("Error parsing outer JSON: %v", err)
}
m := &MetricsConfig{}
err = json.Unmarshal([]byte(outerData.MetricsConfigDetail), m)
if err != nil {
return nil, err
}
if IsDebugLevelMatched(4) {
level.Info(Logger).Log("msg", "Get MetricConfig config, result", *m)
}
if reflect.DeepEqual(m, MetricsConfig{}) {
fmt.Println("MetricsConfig is empty")
}
return m, err
}
func (p *LogProject) UpdateMetricConfig(metricStore string, metricConfig *MetricsConfig) (err error) {
body, err := json.Marshal(metricConfig)
if err != nil {
return NewClientError(err)
}
jsonBody := map[string]interface{}{
"metricStore": metricStore,
"metricsConfigDetail": string(body),
}
body, err = json.Marshal(jsonBody)
if err != nil {
return NewClientError(err)
}
body, err = json.Marshal(jsonBody)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "PUT", "/metricsconfigs/"+metricStore, h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
body, _ = ioutil.ReadAll(r.Body)
if r.StatusCode != http.StatusOK {
err := new(Error)
json.Unmarshal(body, err)
return err
}
return nil
}
// ListConfig returns config names list and the total number of configs.
// The offset starts from 0 and the size is the max number of configs could be returned.
func (p *LogProject) ListConfig(offset, size int) (cfgNames []string, total int, err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
if size <= 0 {
size = 100
}
uri := fmt.Sprintf("/configs?offset=%v&size=%v", offset, size)
r, err := request(p, "GET", uri, h, nil)
if err != nil {
return nil, 0, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, 0, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return nil, 0, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
type Body struct {
Total int
Configs []string
}
body := &Body{}
err = json.Unmarshal(buf, body)
if err != nil {
return nil, 0, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
cfgNames = body.Configs
total = body.Total
return cfgNames, total, nil
}
// CheckConfigExist check config exist or not
func (p *LogProject) CheckConfigExist(name string) (bool, error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "GET", "/configs/"+name, h, nil)
if err != nil {
if _, ok := err.(*Error); ok {
slsErr := err.(*Error)
if slsErr.Code == "ConfigNotExist" {
return false, nil
}
return false, slsErr
}
return false, err
}
defer r.Body.Close()
return true, nil
}
// GetConfig returns config according by config name.
func (p *LogProject) GetConfig(name string) (c *LogConfig, err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "GET", "/configs/"+name, h, nil)
if err != nil {
return nil, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return nil, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
c = &LogConfig{}
err = json.Unmarshal(buf, c)
if err != nil {
return nil, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
if IsDebugLevelMatched(4) {
level.Info(Logger).Log("msg", "Get logtail config, result", *c)
}
return c, nil
}
// UpdateConfig updates a config.
func (p *LogProject) UpdateConfig(c *LogConfig) (err error) {
body, err := json.Marshal(c)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "PUT", "/configs/"+c.Name, h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// CreateConfig creates a new config in SLS.
func (p *LogProject) CreateConfig(c *LogConfig) (err error) {
body, err := json.Marshal(c)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "POST", "/configs", h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// GetConfigString returns config according by config name.
func (p *LogProject) GetConfigString(name string) (c string, err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "GET", "/configs/"+name, h, nil)
if err != nil {
return "", NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return "", readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return "", httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
if IsDebugLevelMatched(4) {
level.Info(Logger).Log("msg", "Get logtail config, result", c)
}
return string(buf), err
}
// UpdateConfigString updates a config.
func (p *LogProject) UpdateConfigString(configName, c string) (err error) {
body := []byte(c)
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "PUT", "/configs/"+configName, h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// CreateConfigString creates a new config in SLS.
func (p *LogProject) CreateConfigString(c string) (err error) {
body := []byte(c)
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate", // TODO: support lz4
}
r, err := request(p, "POST", "/configs", h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// DeleteConfig deletes a config according by config name.
func (p *LogProject) DeleteConfig(name string) (err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "DELETE", "/configs/"+name, h, nil)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// GetAppliedMachineGroups returns applied machine group names list according config name.
func (p *LogProject) GetAppliedMachineGroups(confName string) (groupNames []string, err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
uri := fmt.Sprintf("/configs/%v/machinegroups", confName)
r, err := request(p, "GET", uri, h, nil)
if err != nil {
return nil, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return nil, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
type Body struct {
Count int
Machinegroups []string
}
body := &Body{}
err = json.Unmarshal(buf, body)
if err != nil {
return nil, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
groupNames = body.Machinegroups
return groupNames, nil
}
// GetAppliedConfigs returns applied config names list according machine group name groupName.
func (p *LogProject) GetAppliedConfigs(groupName string) (confNames []string, err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
uri := fmt.Sprintf("/machinegroups/%v/configs", groupName)
r, err := request(p, "GET", uri, h, nil)
if err != nil {
return nil, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return nil, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
type Cfg struct {
Count int `json:"count"`
Configs []string `json:"configs"`
}
body := &Cfg{}
err = json.Unmarshal(buf, body)
if err != nil {
return nil, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
confNames = body.Configs
return confNames, nil
}
// ApplyConfigToMachineGroup applies config to machine group.
func (p *LogProject) ApplyConfigToMachineGroup(confName, groupName string) (err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
uri := fmt.Sprintf("/machinegroups/%v/configs/%v", groupName, confName)
r, err := request(p, "PUT", uri, h, nil)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// RemoveConfigFromMachineGroup removes config from machine group.
func (p *LogProject) RemoveConfigFromMachineGroup(confName, groupName string) (err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
uri := fmt.Sprintf("/machinegroups/%v/configs/%v", groupName, confName)
r, err := request(p, "DELETE", uri, h, nil)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
func (p *LogProject) CreateEtlMeta(etlMeta *EtlMeta) (err error) {
body, err := json.Marshal(etlMeta)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate",
}
r, err := request(p, "POST", fmt.Sprintf("/%v", EtlMetaURI), h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
func (p *LogProject) UpdateEtlMeta(etlMeta *EtlMeta) (err error) {
body, err := json.Marshal(etlMeta)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate",
}
r, err := request(p, "PUT", fmt.Sprintf("/%v", EtlMetaURI), h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
func (p *LogProject) DeleteEtlMeta(etlMetaName, etlMetaKey string) (err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
uri := fmt.Sprintf("/%v?etlMetaName=%v&etlMetaKey=%v&etlMetaTag=%v", EtlMetaURI, etlMetaName, etlMetaKey, EtlMetaAllTagMatch)
r, err := request(p, "DELETE", uri, h, nil)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
func (p *LogProject) listEtlMeta(etlMetaName, etlMetaKey, etlMetaTag string, offset, size int) (total int, count int, etlMeta []*EtlMeta, err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
uri := fmt.Sprintf("/%v?offset=%v&size=%v&etlMetaName=%v&etlMetaKey=%v&etlMetaTag=%v", EtlMetaURI, offset, size, etlMetaName, etlMetaKey, etlMetaTag)
r, err := request(p, "GET", uri, h, nil)
if err != nil {
return 0, 0, nil, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return 0, 0, nil, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return 0, 0, nil, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
type BodyMeta struct {
MetaName string `json:"etlMetaName"`
MetaKey string `json:"etlMetaKey"`
MetaTag string `json:"etlMetaTag"`
MetaValue string `json:"etlMetaValue"`
}
type Body struct {
Total int `json:"total"`
Count int `json:"count"`
MetaList []*BodyMeta `json:"etlMetaList"`
}
body := &Body{}
err = json.Unmarshal(buf, body)
if err != nil {
return 0, 0, nil, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
if body.Count == 0 || len(body.MetaList) == 0 {
return body.Total, body.Count, nil, nil
}
var etlMetaList []*EtlMeta = make([]*EtlMeta, len(body.MetaList))
for index, value := range body.MetaList {
var metaValueMap map[string]string
err := json.Unmarshal([]byte(value.MetaValue), &metaValueMap)
if err != nil {
return 0, 0, nil, NewClientError(err)
}
etlMetaList[index] = &EtlMeta{
MetaName: value.MetaName,
MetaKey: value.MetaKey,
MetaTag: value.MetaTag,
MetaValue: metaValueMap,
}
}
return body.Total, body.Count, etlMetaList, nil
}
func (p *LogProject) GetEtlMeta(etlMetaName, etlMetaKey string) (etlMeta *EtlMeta, err error) {
_, count, etlMetaList, err := p.listEtlMeta(etlMetaName, etlMetaKey, EtlMetaAllTagMatch, 0, 1)
if err != nil {
return nil, err
} else if count == 0 {
return nil, nil
}
return etlMetaList[0], nil
}
func (p *LogProject) ListEtlMeta(etlMetaName string, offset, size int) (total int, count int, etlMetaList []*EtlMeta, err error) {
return p.listEtlMeta(etlMetaName, "", EtlMetaAllTagMatch, offset, size)
}
func (p *LogProject) ListEtlMetaWithTag(etlMetaName, etlMetaTag string, offset, size int) (total int, count int, etlMetaList []*EtlMeta, err error) {
return p.listEtlMeta(etlMetaName, "", etlMetaTag, offset, size)
}
func (p *LogProject) ListEtlMetaName(offset, size int) (total int, count int, etlMetaNameList []string, err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
uri := fmt.Sprintf("/%v?offset=%v&size=%v", EtlMetaNameURI, offset, size)
r, err := request(p, "GET", uri, h, nil)
if err != nil {
return 0, 0, nil, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return 0, 0, nil, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return 0, 0, nil, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
type Body struct {
Total int `json:"total"`
Count int `json:"count"`
MetaNameList []string `json:"etlMetaNameList"`
}
body := &Body{}
err = json.Unmarshal(buf, body)
if err != nil {
return 0, 0, nil, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
return body.Total, body.Count, body.MetaNameList, nil
}
func (p *LogProject) CreateLogging(detail *Logging) (err error) {
body, err := json.Marshal(detail)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate",
}
r, err := request(p, "POST", fmt.Sprintf("/%v", LoggingURI), h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
func (p *LogProject) UpdateLogging(detail *Logging) (err error) {
body, err := json.Marshal(detail)
if err != nil {
return NewClientError(err)
}
h := map[string]string{
"x-log-bodyrawsize": fmt.Sprintf("%v", len(body)),
"Content-Type": "application/json",
"Accept-Encoding": "deflate",
}
r, err := request(p, "PUT", fmt.Sprintf("/%v", LoggingURI), h, body)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
func (p *LogProject) GetLogging() (c *Logging, err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
r, err := request(p, "GET", fmt.Sprintf("/%v", LoggingURI), h, nil)
if err != nil {
return nil, NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return nil, httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
c = &Logging{}
err = json.Unmarshal(buf, c)
if err != nil {
return nil, invalidJsonRespError(string(buf), r.Header, r.StatusCode)
}
if IsDebugLevelMatched(4) {
level.Info(Logger).Log("msg", "Get logging, result", *c)
}
return c, nil
}
func (p *LogProject) DeleteLogging() (err error) {
h := map[string]string{
"x-log-bodyrawsize": "0",
}
uri := fmt.Sprintf("/%v", LoggingURI)
r, err := request(p, "DELETE", uri, h, nil)
if err != nil {
return NewClientError(err)
}
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
return readResponseError(err)
}
if r.StatusCode != http.StatusOK {
return httpStatusNotOkError(buf, r.Header, r.StatusCode)
}
return nil
}
// warning: call some method directly from Client lead to requestTimeout not working,
// we should fix it in the future by making breaking changes
func (p *LogProject) init() {
p.parseEndpointIfNeeded()
if p.retryTimeout == 0 {
p.retryTimeout = defaultRetryTimeout
}
if p.httpClient == nil {
p.httpClient = defaultHttpClient
}
}
func (p *LogProject) getBaseURL() string {
p.parseEndpointIfNeeded()
return p.baseURL
}
func (p *LogProject) parseEndpointIfNeeded() {
if len(p.baseURL) > 0 {
return
}
p.parseEndpoint()
}
func (p *LogProject) parseEndpoint() {
scheme := httpScheme // default to http scheme
host := p.Endpoint
if strings.HasPrefix(p.Endpoint, httpScheme) {
scheme = httpScheme
host = strings.TrimPrefix(p.Endpoint, scheme)
} else if strings.HasPrefix(p.Endpoint, httpsScheme) {
scheme = httpsScheme
host = strings.TrimPrefix(p.Endpoint, scheme)
}
if GlobalForceUsingHTTP || p.UsingHTTP {
scheme = httpScheme
}
if len(p.Name) == 0 {
p.baseURL = fmt.Sprintf("%s%s", scheme, host)
} else {
p.baseURL = fmt.Sprintf("%s%s.%s", scheme, p.Name, host)
}
}