-
Notifications
You must be signed in to change notification settings - Fork 82
/
jaeger.go
117 lines (105 loc) · 3.24 KB
/
jaeger.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package apis
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/go-resty/resty/v2"
"github.com/kiali/kiali/jaeger"
jaegerModels "github.com/kiali/kiali/jaeger/model/json"
"kubegems.io/kubegems/pkg/log"
)
// Generated by https://quicktype.io
func NewJaegerHandler(server string) *jaegerHandler {
return &jaegerHandler{Server: server}
}
type jaegerHandler struct {
Server string
}
// @Tags Agent.V1
// @Summary Jaeger span count
// @Description Jaeger span count
// @Accept json
// @Produce json
// @Param namespace query string true "workload namespace"
// @Param name query string true "workload name"
// @Param app query string true "workload app label value"
// @Success 200 {object} handlers.ResponseStruct{Data=map[string]int} "span数"
// @Router /v1/proxy/cluster/{cluster}/custom/jaeger/v1/span [get]
// @Security JWT
func (p *jaegerHandler) GetSpanCount(c *gin.Context) {
// 参考kiali实现:
// 1. 获取service链路
// 2. 过滤workload链路
// 3. 取最近的span数
workloadName := c.Query("name")
workloadNamespace := c.Query("namespace")
appName := c.Query("app") // 也就是jaeger中的service名
now := time.Now()
traceResp := jaeger.JaegerResponse{}
req := resty.New().R().
SetQueryParam("start", strconv.Itoa(int(now.Add(-1*time.Hour).UnixMicro()))).
SetQueryParam("end", strconv.Itoa(int(now.UnixMicro()))).
SetQueryParam("limit", "100").
SetQueryParam("service", fmt.Sprintf("%s.%s", appName, workloadNamespace)).
SetResult(&traceResp)
resp, err := req.Get(p.Server + "/api/traces")
if err != nil {
NotOK(c, err)
return
}
log.Info("trace", "url", resp.Request.URL)
traces := []jaegerModels.Trace{}
for _, trace := range traceResp.Data {
if matchesWorkload(&trace, workloadNamespace, workloadName) {
traces = append(traces, trace)
}
}
count := 0
if len(traces) > 0 {
count = len(traces[len(traces)-1].Spans)
}
OK(c, gin.H{
"count": count,
})
}
// copy from kiali
func matchesWorkload(trace *jaegerModels.Trace, namespace, workload string) bool {
for _, span := range trace.Spans {
if process, ok := trace.Processes[span.ProcessID]; ok {
span.Process = &process
}
if spanMatchesWorkload(&span, namespace, workload) {
return true
}
}
return false
}
func spanMatchesWorkload(span *jaegerModels.Span, namespace, workload string) bool {
// For envoy traces, with a workload named "ai-locals", node_id is like:
// sidecar~172.17.0.20~ai-locals-6d8996bff-ztg6z.default~default.svc.cluster.local
for _, tag := range span.Tags {
if tag.Key == "node_id" {
if v, ok := tag.Value.(string); ok {
parts := strings.Split(v, "~")
if len(parts) >= 3 && strings.HasPrefix(parts[2], workload) && strings.HasSuffix(parts[2], namespace) {
return true
}
}
}
}
// Tag not found => try with 'hostname' in process' tags
if span.Process != nil {
for _, tag := range span.Process.Tags {
if tag.Key == "hostname" {
if v, ok := tag.Value.(string); ok {
if strings.HasPrefix(v, workload) {
return true
}
}
}
}
}
return false
}