annotation_query.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package stackdriver
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "github.com/grafana/grafana/pkg/tsdb"
  9. )
  10. func (e *StackdriverExecutor) executeAnnotationQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
  11. result := &tsdb.Response{
  12. Results: make(map[string]*tsdb.QueryResult),
  13. }
  14. firstQuery := tsdbQuery.Queries[0]
  15. queries, err := e.buildQueries(tsdbQuery)
  16. if err != nil {
  17. return nil, err
  18. }
  19. queryRes, resp, err := e.executeQuery(ctx, queries[0], tsdbQuery)
  20. if err != nil {
  21. return nil, err
  22. }
  23. title := firstQuery.Model.Get("title").MustString()
  24. text := firstQuery.Model.Get("text").MustString()
  25. tags := firstQuery.Model.Get("tags").MustString()
  26. err = e.parseToAnnotations(queryRes, resp, queries[0], title, text, tags)
  27. result.Results[firstQuery.RefId] = queryRes
  28. return result, err
  29. }
  30. func (e *StackdriverExecutor) parseToAnnotations(queryRes *tsdb.QueryResult, data StackdriverResponse, query *StackdriverQuery, title string, text string, tags string) error {
  31. annotations := make([]map[string]string, 0)
  32. for _, series := range data.TimeSeries {
  33. // reverse the order to be ascending
  34. for i := len(series.Points) - 1; i >= 0; i-- {
  35. point := series.Points[i]
  36. value := strconv.FormatFloat(point.Value.DoubleValue, 'f', 6, 64)
  37. if series.ValueType == "STRING" {
  38. value = point.Value.StringValue
  39. }
  40. annotation := make(map[string]string)
  41. annotation["time"] = point.Interval.EndTime.UTC().Format(time.RFC3339)
  42. annotation["title"] = formatAnnotationText(title, value, series.Metric.Type, series.Metric.Labels, series.Resource.Labels)
  43. annotation["tags"] = tags
  44. annotation["text"] = formatAnnotationText(text, value, series.Metric.Type, series.Metric.Labels, series.Resource.Labels)
  45. annotations = append(annotations, annotation)
  46. }
  47. }
  48. transformAnnotationToTable(annotations, queryRes)
  49. return nil
  50. }
  51. func transformAnnotationToTable(data []map[string]string, result *tsdb.QueryResult) {
  52. table := &tsdb.Table{
  53. Columns: make([]tsdb.TableColumn, 4),
  54. Rows: make([]tsdb.RowValues, 0),
  55. }
  56. table.Columns[0].Text = "time"
  57. table.Columns[1].Text = "title"
  58. table.Columns[2].Text = "tags"
  59. table.Columns[3].Text = "text"
  60. for _, r := range data {
  61. values := make([]interface{}, 4)
  62. values[0] = r["time"]
  63. values[1] = r["title"]
  64. values[2] = r["tags"]
  65. values[3] = r["text"]
  66. table.Rows = append(table.Rows, values)
  67. }
  68. result.Tables = append(result.Tables, table)
  69. result.Meta.Set("rowCount", len(data))
  70. slog.Info("anno", "len", len(data))
  71. }
  72. func formatAnnotationText(annotationText string, pointValue string, metricType string, metricLabels map[string]string, resourceLabels map[string]string) string {
  73. result := legendKeyFormat.ReplaceAllFunc([]byte(annotationText), func(in []byte) []byte {
  74. metaPartName := strings.Replace(string(in), "{{", "", 1)
  75. metaPartName = strings.Replace(metaPartName, "}}", "", 1)
  76. metaPartName = strings.TrimSpace(metaPartName)
  77. if metaPartName == "metric.type" {
  78. return []byte(metricType)
  79. }
  80. metricPart := replaceWithMetricPart(metaPartName, metricType)
  81. if metricPart != nil {
  82. return metricPart
  83. }
  84. if metaPartName == "value" {
  85. return []byte(fmt.Sprintf("%f", pointValue))
  86. }
  87. metaPartName = strings.Replace(metaPartName, "metric.label.", "", 1)
  88. if val, exists := metricLabels[metaPartName]; exists {
  89. return []byte(val)
  90. }
  91. metaPartName = strings.Replace(metaPartName, "resource.label.", "", 1)
  92. if val, exists := resourceLabels[metaPartName]; exists {
  93. return []byte(val)
  94. }
  95. return in
  96. })
  97. return string(result)
  98. }