The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/live/survey/survey.go

132 lines
2.9 KiB

package survey
import (
"context"
"encoding/json"
"errors"
"fmt"
"sort"
"strings"
"time"
"github.com/centrifugal/centrifuge"
"github.com/grafana/grafana/pkg/services/live/managedstream"
)
type Caller struct {
managedStreamRunner *managedstream.Runner
node *centrifuge.Node
}
const (
managedStreamsCall = "managed_streams"
)
func NewCaller(managedStreamRunner *managedstream.Runner, node *centrifuge.Node) *Caller {
return &Caller{managedStreamRunner: managedStreamRunner, node: node}
}
func (c *Caller) SetupHandlers() error {
c.node.OnSurvey(c.handleSurvey)
return nil
}
type NodeManagedChannelsRequest struct {
OrgID int64 `json:"orgId"`
}
type NodeManagedChannelsResponse struct {
Channels []*managedstream.ManagedChannel `json:"channels"`
}
func (c *Caller) handleSurvey(e centrifuge.SurveyEvent, cb centrifuge.SurveyCallback) {
var (
resp interface{}
err error
)
switch e.Op {
case managedStreamsCall:
resp, err = c.handleManagedStreams(e.Data)
default:
err = errors.New("method not found")
}
if err != nil {
cb(centrifuge.SurveyReply{Code: 1})
return
}
jsonData, err := json.Marshal(resp)
if err != nil {
cb(centrifuge.SurveyReply{Code: 1})
return
}
cb(centrifuge.SurveyReply{
Code: 0,
Data: jsonData,
})
}
func (c *Caller) handleManagedStreams(data []byte) (interface{}, error) {
var req NodeManagedChannelsRequest
err := json.Unmarshal(data, &req)
if err != nil {
return nil, err
}
channels, err := c.managedStreamRunner.GetManagedChannels(req.OrgID)
if err != nil {
return nil, err
}
return NodeManagedChannelsResponse{
Channels: channels,
}, nil
}
func (c *Caller) CallManagedStreams(orgID int64) ([]*managedstream.ManagedChannel, error) {
req := NodeManagedChannelsRequest{OrgID: orgID}
jsonData, err := json.Marshal(req)
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
resp, err := c.node.Survey(ctx, managedStreamsCall, jsonData)
if err != nil {
return nil, err
}
channels := map[string]*managedstream.ManagedChannel{}
for _, result := range resp {
if result.Code != 0 {
return nil, fmt.Errorf("unexpected survey code: %d", result.Code)
}
var res NodeManagedChannelsResponse
err := json.Unmarshal(result.Data, &res)
if err != nil {
return nil, err
}
for _, ch := range res.Channels {
if _, ok := channels[ch.Channel]; ok {
if strings.HasPrefix(ch.Channel, "plugin/testdata/") {
// Skip adding testdata rates since it works over different
// mechanism (plugin stream) and the minute rate is hardcoded.
continue
}
channels[ch.Channel].MinuteRate += ch.MinuteRate
continue
}
channels[ch.Channel] = ch
}
}
result := make([]*managedstream.ManagedChannel, 0, len(channels))
for _, v := range channels {
result = append(result, v)
}
sort.Slice(result, func(i, j int) bool {
return result[i].Channel < result[j].Channel
})
return result, nil
}