Chore: Add more metrics to annotation service to see its usage (#112651)

This commit is contained in:
Serge Zaitsev
2025-10-23 09:48:07 +02:00
committed by GitHub
parent 2e1704b56f
commit f3eabbf588
5 changed files with 90 additions and 12 deletions
@@ -40,7 +40,7 @@ func ProvideService(
l := log.New("annotations")
l.Debug("Initializing annotations service")
xormStore := NewXormStore(cfg, log.New("annotations.sql"), db, tagService)
xormStore := NewXormStore(cfg, log.New("annotations.sql"), db, tagService, reg)
write := xormStore
var read readStore
@@ -15,7 +15,7 @@ type CleanupServiceImpl struct {
func ProvideCleanupService(db db.DB, cfg *setting.Cfg) *CleanupServiceImpl {
return &CleanupServiceImpl{
store: NewXormStore(cfg, log.New("annotations"), db, nil),
store: NewXormStore(cfg, log.New("annotations"), db, nil, nil),
}
}
@@ -7,6 +7,7 @@ import (
"testing"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -185,7 +186,7 @@ func TestIntegrationOldAnnotationsAreDeletedFirst(t *testing.T) {
// run the clean up task to keep one annotation.
cfg := setting.NewCfg()
cfg.AnnotationCleanupJobBatchSize = 1
cleaner := NewXormStore(cfg, log.New("annotation.test"), fakeSQL, nil)
cleaner := NewXormStore(cfg, log.New("annotation.test"), fakeSQL, nil, prometheus.NewRegistry())
_, err = cleaner.CleanAnnotations(context.Background(), setting.AnnotationCleanupSettings{MaxCount: 1}, alertAnnotationType)
require.NoError(t, err)
@@ -8,12 +8,15 @@ import (
"strings"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/grafana/grafana/pkg/services/annotations/accesscontrol"
"github.com/grafana/grafana/pkg/services/sqlstore/migrations"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics/metricutil"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/tag"
@@ -38,26 +41,59 @@ func validateTimeRange(item *annotations.Item) error {
}
type xormRepositoryImpl struct {
cfg *setting.Cfg
db db.DB
log log.Logger
tagService tag.Service
cfg *setting.Cfg
db db.DB
log log.Logger
tagService tag.Service
queryRangeStart *prometheus.HistogramVec
queryRangeDuration *prometheus.HistogramVec
queryResultsCount *prometheus.HistogramVec
}
func NewXormStore(cfg *setting.Cfg, l log.Logger, db db.DB, tagService tag.Service) *xormRepositoryImpl {
// populate dashboard_uid at startup, to ensure safe downgrades & upgrades after
// the initial migration occurs
func NewXormStore(cfg *setting.Cfg, l log.Logger, db db.DB, tagService tag.Service, reg prometheus.Registerer) *xormRepositoryImpl {
err := migrations.RunDashboardUIDMigrations(db.GetEngine().NewSession(), db.GetEngine().DriverName())
if err != nil {
l.Error("failed to populate dashboard_uid for annotations", "error", err)
}
return &xormRepositoryImpl{
repo := &xormRepositoryImpl{
cfg: cfg,
db: db,
log: l,
tagService: tagService,
}
if reg != nil {
repo.queryRangeStart = metricutil.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: "grafana",
Subsystem: "annotations",
Name: "query_range_start_hours",
Help: "How far back in time (hours from now) annotation queries request",
},
[]string{"query_type"},
)
repo.queryRangeDuration = metricutil.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: "grafana",
Subsystem: "annotations",
Name: "query_range_duration_hours",
Help: "Time range duration (hours) of annotation queries",
},
[]string{"query_type"},
)
repo.queryResultsCount = metricutil.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: "grafana",
Subsystem: "annotations",
Name: "query_results_count",
Help: "Number of annotation results returned per query",
},
[]string{"query_type"},
)
reg.MustRegister(repo.queryRangeStart, repo.queryRangeDuration, repo.queryResultsCount)
}
return repo
}
func (r *xormRepositoryImpl) Type() string {
@@ -166,13 +202,16 @@ func (r *xormRepositoryImpl) update(ctx context.Context, item *annotations.Item)
existing.Text = item.Text
if item.Epoch != 0 {
r.log.Info("updating epoch for annotation", "id", item.ID, "orgId", item.OrgID, "oldEpoch", existing.Epoch, "newEpoch", item.Epoch)
existing.Epoch = item.Epoch
}
if item.EpochEnd != 0 {
r.log.Info("updating epoch_end for annotation", "id", item.ID, "orgId", item.OrgID, "oldEpochEnd", existing.EpochEnd, "newEpochEnd", item.EpochEnd)
existing.EpochEnd = item.EpochEnd
}
if item.Data != nil {
r.log.Info("updating data for annotation", "id", item.ID, "orgId", item.OrgID)
existing.Data = item.Data
}
@@ -383,9 +422,46 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query annotations.ItemQuer
},
)
if err == nil {
r.recordQueryMetrics(query, len(items))
}
return items, err
}
func (r *xormRepositoryImpl) recordQueryMetrics(query annotations.ItemQuery, resultCount int) {
if r.queryRangeStart == nil || query.From == 0 && query.To == 0 {
return
}
queryType := "all"
if query.AnnotationID != 0 {
queryType = "by_id"
} else if query.AlertID != 0 || query.AlertUID != "" {
queryType = "by_alert"
} else if query.DashboardUID != "" || query.DashboardID != 0 { // nolint: staticcheck
queryType = "by_dashboard"
} else if len(query.Tags) > 0 {
queryType = "by_tags"
}
if query.From > 0 && query.To > 0 {
now := time.Now().UnixMilli()
startOffsetHours := float64(now-query.To) / (1000.0 * 3600.0)
if startOffsetHours < 0 {
startOffsetHours = 0
}
r.queryRangeStart.WithLabelValues(queryType).Observe(startOffsetHours)
durationHours := float64(query.To-query.From) / (1000.0 * 3600.0)
if durationHours < 0 {
durationHours = 0
}
r.queryRangeDuration.WithLabelValues(queryType).Observe(durationHours)
}
r.queryResultsCount.WithLabelValues(queryType).Observe(float64(resultCount))
}
func (r *xormRepositoryImpl) getAccessControlFilter(accessResources *accesscontrol.AccessResources, dashboardUID string) (string, []any) {
if accessResources.SkipAccessControlFilter {
return "", nil
@@ -6,6 +6,7 @@ import (
"strings"
"testing"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -39,7 +40,7 @@ func TestIntegrationAnnotations(t *testing.T) {
cfg := setting.NewCfg()
cfg.AnnotationMaximumTagsLength = 60
store := NewXormStore(cfg, log.New("annotation.test"), sql, tagimpl.ProvideService(sql))
store := NewXormStore(cfg, log.New("annotation.test"), sql, tagimpl.ProvideService(sql), prometheus.NewRegistry())
testUser := &user.SignedInUser{
OrgID: 1,