You need to enable JavaScript to run this app.
导航
使用 Go 语言实现工作区数据写入和查询
最近更新时间:2024.12.24 14:46:07首次发布时间:2024.12.24 14:46:07

托管 Prometheus 工作区兼容原生 Prom,支持通过 Go 语言进行数据写入和查询。本文介绍使用 Go 语言在工作区进行进行数据写入和查询的方法和示例。

写入指标数据

使用 BasicAuth 写入指标

package  main

import  (
   "context"
   "encoding/base64"
   "fmt"
   "net/http"
   "time"
   "github.com/castai/promwrite"
)

// NewRoundTripper ...
func NewRoundTripper(username, password  string)  http.RoundTripper {
   return  &basicAuthTransport{
            transport: http.DefaultTransport,
            basicAuth:  "Basic "  + base64.StdEncoding.EncodeToString([]byte(username+":"+password)),
      }

}

type  basicAuthTransport  struct  {
      transport http.RoundTripper
      basicAuth  string
}

func (bat *basicAuthTransport)  RoundTrip(req *http.Request) (*http.Response,  error) {
      req.Header.Add("Authorization", bat.basicAuth)
   return  bat.transport.RoundTrip(req)

}

func main()  {
   username := "username" // 在 vmp 工作区配置的 basicAuth username
   password := "password" // 在 vmp 工作区配置的 basicAuth password
   remotewriteURL := "remotewrite 地址" // 可在 vmp 工作区详情页复制
      c := promwrite.NewClient(remotewriteURL, promwrite.HttpClient(&http.Client{
            Transport: NewRoundTripper(username, password),
      }))
      resp, err := c.Write(context.Background(), &promwrite.WriteRequest{
            TimeSeries: []promwrite.TimeSeries{
                  {
                        Labels: []promwrite.Label{
                              {
                                    Name:    "__name__",
                                    Value:  "my_metric_name",
                              },
                        },
                        Sample: promwrite.Sample{
                              Time:  time.Now(),
                              Value:  123,
                        },
                  },
            },
      })
      fmt.Println(resp, err)

}

使用 AK/SK 写入指标

package main

import (
    "context"
    "fmt"
    "net/http"
    "time"
    
    "github.com/castai/promwrite"
    
    "github.com/volcengine/volc-sdk-golang/base"
)

// Config is the configuration for signing remote write requests with
// volcengine verification process. Empty values will be retrieved using the
// volcengine default credentials chain.
type Config struct {
   Region    string
   AccessKey string
   SecretKey string
   Service   string
}

// NewRoundTripper returns a new http.RoundTripper that will sign requests
// using Volcengine's Signature Verification signing procedure.  
// Credentials for signing are retrieved using the the default volcengine credential
// chain. If credentials cannot be found, an error will be returned.
func NewRoundTripper(cfg *Config) (http.RoundTripper, error) {
   rt := &volcRoundTripper{
      next: http.DefaultTransport,
      signer: &base.Credentials{
         AccessKeyID:     cfg.AccessKey,
         SecretAccessKey: cfg.SecretKey,
         Region:          cfg.Region,
         Service:         cfg.Service,
      },
   }

   return rt, nil
}

type volcRoundTripper struct {
   next      http.RoundTripper
   signer    *base.Credentials
}

func (rt *volcRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
   q := req.URL.Query()
   req.URL.RawQuery = q.Encode()
   return rt.next.RoundTrip(rt.signer.Sign(req))
}

func main() {
   rt, err := NewRoundTripper(&Config{
      Region:    "region", // workspace 地域
      AccessKey: "ak", // 具有 vmp remotewrite 访问权限的用户 ak
      SecretKey: "sk", // 具有 vmp remotewrite 访问权限的用户 sk
      Service:   "vmp",
   })
   if err != nil {
      panic(err)
   }

   remotewriteURL := "remotewrite 地址" // 可在 vmp 工作区详情页复制
   c := promwrite.NewClient(remotewriteURL, promwrite.HttpClient(&http.Client{
      Transport: rt,
   }))
   resp, err := c.Write(context.Background(), &promwrite.WriteRequest{
      TimeSeries: []promwrite.TimeSeries{
         {
            Labels: []promwrite.Label{
               {
                  Name:  "__name__",
                  Value: "my_metric_name",
               },
            },
            Sample: promwrite.Sample{
               Time:  time.Now(),
               Value: 123,
            },
         },
      },
   })
   fmt.Println(resp, err)
 }

查询指标数据

支持查询的接口

使用 BasicAuth 查询指标

由于托管 Prometheus 产品接口兼容原生 Prom,因此在调用接口时可以使用现成的 Prom SDK,以下是基于 client_go 的实现样例。

import  (
   "net/http"
   "strconv"
   "github.com/prometheus/client_golang/api"
      promv1  "github.com/prometheus/client_golang/api/prometheus/v1"
)

// NewPromAPI ...
func NewPromAPI(queryAddress, username, password  string)  (promv1.API,  error) {
      promClient, err := api.NewClient(api.Config{
            Address:      queryAddress,
            RoundTripper: NewBasicAuthRoundTripper(http.DefaultTransport, username, password),
      })
   if  err !=  nil  {
      return nil, err
      }
   return  promv1.NewAPI(promClient),  nil
}

// NewBasicAuthRoundTripper ...
func NewBasicAuthRoundTripper(next http.RoundTripper, username, password  string)  http.RoundTripper {
   if  next ==  nil  {
            next = http.DefaultTransport
      }
   return  &basicAuthTransport{
            transport: http.DefaultTransport,
            basicAuth:  "Basic "  + base64.StdEncoding.EncodeToString([]byte(username+":"+password)),
      }

}

type  basicAuthTransport  struct  {
      transport http.RoundTripper
      basicAuth  string
}

func (bat *basicAuthTransport)  RoundTrip(req *http.Request) (*http.Response,  error) {
      req.Header.Add("Authorization", bat.basicAuth)
   return  bat.transport.RoundTrip(req)

}

func main(){
    address := "vmp query 地址" // 可在 vmp 工作区详情页复制
    username := "username" // 在 vmp 工作区配置的 basicAuth username
    password := "password" // 在 vmp 工作区配置的 basicAuth password
    
    api, err := NewPromAPI(address, username, password)
    
    res, _, err := api.Query(context.TODO(), "up", time.Now())
    fmt.Println(res, err)
}

使用 AK/SK 查询指标

import  (
   "context"
   "fmt"
   "net/http"
   "time"
   "github.com/prometheus/client_golang/api"
      promv1  "github.com/prometheus/client_golang/api/prometheus/v1"
   "github.com/volcengine/volc-sdk-golang/base"
)

// Config is the configuration for signing query requests with
// volcengine verification process. Empty values will be retrieved using the
// volcengine default credentials chain.
type  Config  struct  {
      Region        string // 访问地区
      AccessKey  string // 服务ak
      SecretKey  string // 服务sk
      Service      string // vmp 服务名,为 vmp
}

type  volcRoundTripper  struct  {
      next   http.RoundTripper
      signer *base.Credentials

}

// NewRoundTripper returns a new http.RoundTripper that will sign requests
// using Volcengine's Signature Verification signing procedure.
//
// Credentials for signing are retrieved using the the default volcengine credential
// chain. If credentials cannot be found, an error will be returned.
func NewRoundTripper(cfg *Config)  (http.RoundTripper,  error) {
      rt := &volcRoundTripper{
            next: http.DefaultTransport,
            signer: &base.Credentials{
                  AccessKeyID:     cfg.AccessKey,
                  SecretAccessKey: cfg.SecretKey,
                  Region:          cfg.Region,
                  Service:         cfg.Service,
            },
      }

   return  rt,  nil
}

func (rt *volcRoundTripper)  RoundTrip(req *http.Request) (*http.Response,  error) {
      q := req.URL.Query()
      req.URL.RawQuery = q.Encode()
   return  rt.next.RoundTrip(rt.signer.Sign(req))

}

// NewPromClient ...
func NewPromClient(cfg *Config, queryAddress  string)  (promv1.API,  error) {
      rt, err := NewRoundTripper(cfg)
   if  err !=  nil  {
      return nil, err
      }
      promClient, err := api.NewClient(api.Config{
            Address:      queryAddress,
            RoundTripper: rt,
      })
   if  err !=  nil  {
      return nil, err
      }
   return  promv1.NewAPI(promClient),  nil
}

func main() {
   api, err := NewPromClient(&Config{
      Region:    "region",
      AccessKey: "ak",
      SecretKey: "sk",
      Service:   "vmp",
   }, "query地址") 
   if err != nil {
      fmt.Println(err.Error())
   }

   res, _, err := api.Query(context.TODO(), "up", time.Now())
   fmt.Println(res, err)
}

结果处理

Query 的结果一般是 ValVector 和 ValScalar 类型,可参考下面对结果进行处理。另外 QueryRange 的查询类型是 prommodel.Matrix,可依据下面做扩展。

func parseQueryResp(value prommodel.Value) (prommodel.Vector, error) {
   var samples prommodel.Vector
   var ok bool
   switch value.Type() {
   case prommodel.ValVector:
      samples, ok = value.(prommodel.Vector)
      if !ok {
         return nil, errors.New("convert result to \"model.Vector\"")
      }
   case prommodel.ValScalar:
      var scalar *prommodel.Scalar
      scalar, ok = value.(*prommodel.Scalar)
      if !ok {
         return nil, errors.New("convert result to \"model.Scalar\"")
      }
      samples = append(samples, &prommodel.Sample{
         Timestamp: scalar.Timestamp,
         Value:     scalar.Value,
      })
   default:
      return nil, errors.New("invalid query result")
   }
   return samples, nil
}