mirror of
https://github.com/grafana/grafana.git
synced 2024-11-28 19:54:10 -06:00
e5519161f2
* Zipkin: Run resource calls througgh backend with feature toggle enabled * Update * Don't return early in createZipkinURL and add tests * Update pkg/tsdb/zipkin/client.go Co-authored-by: Sriram <153843+yesoreyeram@users.noreply.github.com> * Update pkg/tsdb/zipkin/client.go Co-authored-by: Sriram <153843+yesoreyeram@users.noreply.github.com> * Update pkg/tsdb/zipkin/client.go Co-authored-by: Sriram <153843+yesoreyeram@users.noreply.github.com> * Update pkg/tsdb/zipkin/client_test.go Co-authored-by: Sriram <153843+yesoreyeram@users.noreply.github.com> * Update pkg/tsdb/zipkin/client_test.go Co-authored-by: Sriram <153843+yesoreyeram@users.noreply.github.com> * Update pkg/tsdb/zipkin/client_test.go Co-authored-by: Sriram <153843+yesoreyeram@users.noreply.github.com> * Update pkg/tsdb/zipkin/client_test.go Co-authored-by: Sriram <153843+yesoreyeram@users.noreply.github.com> * Fix lint * Fix tests --------- Co-authored-by: Sriram <153843+yesoreyeram@users.noreply.github.com>
169 lines
4.3 KiB
Go
169 lines
4.3 KiB
Go
package zipkin
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
|
"github.com/openzipkin/zipkin-go/model"
|
|
)
|
|
|
|
type ZipkinClient struct {
|
|
logger log.Logger
|
|
url string
|
|
httpClient *http.Client
|
|
}
|
|
|
|
func New(url string, hc *http.Client, logger log.Logger) (ZipkinClient, error) {
|
|
client := ZipkinClient{
|
|
logger: logger,
|
|
url: url,
|
|
httpClient: hc,
|
|
}
|
|
return client, nil
|
|
}
|
|
|
|
// Services returns list of services
|
|
// https://zipkin.io/zipkin-api/#/default/get_services
|
|
func (z *ZipkinClient) Services() ([]string, error) {
|
|
services := []string{}
|
|
u, err := url.JoinPath(z.url, "/api/v2/services")
|
|
if err != nil {
|
|
return services, backend.DownstreamError(fmt.Errorf("failed to join url: %w", err))
|
|
}
|
|
res, err := z.httpClient.Get(u)
|
|
if err != nil {
|
|
return services, err
|
|
}
|
|
|
|
defer func() {
|
|
if err = res.Body.Close(); err != nil {
|
|
z.logger.Error("Failed to close response body", "error", err)
|
|
}
|
|
}()
|
|
if err := json.NewDecoder(res.Body).Decode(&services); err != nil {
|
|
return services, err
|
|
}
|
|
return services, err
|
|
}
|
|
|
|
// Spans returns list of spans for the given service
|
|
// https://zipkin.io/zipkin-api/#/default/get_spans
|
|
func (z *ZipkinClient) Spans(serviceName string) ([]string, error) {
|
|
spans := []string{}
|
|
if serviceName == "" {
|
|
return spans, errors.New("invalid/empty serviceName")
|
|
}
|
|
|
|
spansUrl, err := createZipkinURL(z.url, "/api/v2/spans", map[string]string{"serviceName": serviceName})
|
|
if err != nil {
|
|
return spans, backend.DownstreamError(fmt.Errorf("failed to compose url: %w", err))
|
|
}
|
|
|
|
res, err := z.httpClient.Get(spansUrl)
|
|
defer func() {
|
|
if res != nil {
|
|
if err = res.Body.Close(); err != nil {
|
|
z.logger.Error("Failed to close response body", "error", err)
|
|
}
|
|
}
|
|
}()
|
|
if err != nil {
|
|
return spans, err
|
|
}
|
|
if err := json.NewDecoder(res.Body).Decode(&spans); err != nil {
|
|
return spans, err
|
|
}
|
|
return spans, err
|
|
}
|
|
|
|
// Traces returns list of traces for the given service and span
|
|
// https://zipkin.io/zipkin-api/#/default/get_traces
|
|
func (z *ZipkinClient) Traces(serviceName string, spanName string) ([][]model.SpanModel, error) {
|
|
traces := [][]model.SpanModel{}
|
|
if serviceName == "" {
|
|
return traces, errors.New("invalid/empty serviceName")
|
|
}
|
|
if spanName == "" {
|
|
return traces, errors.New("invalid/empty spanName")
|
|
}
|
|
tracesUrl, err := createZipkinURL(z.url, "/api/v2/traces", map[string]string{"serviceName": serviceName, "spanName": spanName})
|
|
if err != nil {
|
|
return traces, backend.DownstreamError(fmt.Errorf("failed to compose url: %w", err))
|
|
}
|
|
|
|
res, err := z.httpClient.Get(tracesUrl)
|
|
defer func() {
|
|
if res != nil {
|
|
if err = res.Body.Close(); err != nil {
|
|
z.logger.Error("Failed to close response body", "error", err)
|
|
}
|
|
}
|
|
}()
|
|
if err != nil {
|
|
return traces, err
|
|
}
|
|
if err := json.NewDecoder(res.Body).Decode(&traces); err != nil {
|
|
return traces, err
|
|
}
|
|
return traces, err
|
|
}
|
|
|
|
// Trace returns trace for the given traceId
|
|
// https://zipkin.io/zipkin-api/#/default/get_trace__traceId_
|
|
func (z *ZipkinClient) Trace(traceId string) ([]model.SpanModel, error) {
|
|
trace := []model.SpanModel{}
|
|
if traceId == "" {
|
|
return trace, errors.New("invalid/empty traceId")
|
|
}
|
|
|
|
traceUrl, err := url.JoinPath(z.url, "/api/v2/trace", url.QueryEscape(traceId))
|
|
if err != nil {
|
|
return trace, backend.DownstreamError(fmt.Errorf("failed to join url: %w", err))
|
|
}
|
|
|
|
res, err := z.httpClient.Get(traceUrl)
|
|
defer func() {
|
|
if res != nil {
|
|
if err = res.Body.Close(); err != nil {
|
|
z.logger.Error("Failed to close response body", "error", err)
|
|
}
|
|
}
|
|
}()
|
|
if err != nil {
|
|
return trace, err
|
|
}
|
|
if err := json.NewDecoder(res.Body).Decode(&trace); err != nil {
|
|
return trace, err
|
|
}
|
|
return trace, err
|
|
}
|
|
|
|
func createZipkinURL(baseURL string, path string, params map[string]string) (string, error) {
|
|
// Parse the base URL
|
|
finalUrl, err := url.Parse(baseURL)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
// Add the path
|
|
urlPath, err := url.JoinPath(finalUrl.Path, path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
finalUrl.Path = urlPath
|
|
// If there are query parameters, add them
|
|
if len(params) > 0 {
|
|
queryParams := finalUrl.Query()
|
|
for k, v := range params {
|
|
queryParams.Set(k, v)
|
|
}
|
|
finalUrl.RawQuery = queryParams.Encode()
|
|
}
|
|
// Return the composed URL as a string
|
|
return finalUrl.String(), nil
|
|
}
|