• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mindersec / minder / 13912518563

18 Mar 2025 12:19AM UTC coverage: 56.561% (+0.006%) from 56.555%
13912518563

Pull #5518

github

web-flow
Merge 4b09b9980 into a1767e80d
Pull Request #5518: build(deps): bump github.com/containerd/containerd from 1.7.25 to 1.7.27 in /tools

18177 of 32137 relevant lines covered (56.56%)

37.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/internal/controlplane/metrics/metrics.go
1
// SPDX-FileCopyrightText: Copyright 2024 The Minder Authors
2
// SPDX-License-Identifier: Apache-2.0
3

4
// Package metrics defines the primitives available for the controlplane metrics
5
package metrics
6

7
import (
8
        "context"
9
        "fmt"
10
        "sync"
11

12
        "go.opentelemetry.io/otel"
13
        "go.opentelemetry.io/otel/attribute"
14
        "go.opentelemetry.io/otel/metric"
15

16
        "github.com/mindersec/minder/internal/db"
17
)
18

19
// WebhookEventState represents the state of a webhook event
20
type WebhookEventState struct {
21
        // Typ is the type of the event, e.g. pull_request, repository, workflow_run, ...
22
        Typ string
23
        // Accepted is whether the event was accepted by engine or filtered out
24
        Accepted bool
25
        // Error is whether there was an error processing the event
26
        Error bool
27
}
28

29
// Metrics implements metrics management for the control plane
30
type Metrics interface {
31
        // Initialize metrics engine
32
        Init(db.Store) error
33

34
        // AddWebhookEventTypeCount adds a count to the webhook event type counter
35
        AddWebhookEventTypeCount(context.Context, *WebhookEventState)
36

37
        // AddTokenOpCount records a token operation (issued, check) and whether the
38
        // github ID was present at the time of check.
39
        AddTokenOpCount(context.Context, string, bool)
40
}
41

42
type metricsImpl struct {
43
        meter           metric.Meter
44
        instrumentsOnce sync.Once
45

46
        // webhook http codes by type
47
        webhookStatusCodeCounter metric.Int64Counter
48
        // webhook event type counter
49
        webhookEventTypeCounter metric.Int64Counter
50

51
        // Track how often users who register a token are correlated with the
52
        // GitHub user from GetAuthorizationURL
53
        tokenOpCounter metric.Int64Counter
54
}
55

56
// NewMetrics creates a new controlplane metrics instance.
57
func NewMetrics() Metrics {
×
58
        return &metricsImpl{
×
59
                meter: otel.Meter("controlplane"),
×
60
        }
×
61
}
×
62

63
// Init initializes the metrics engine
64
func (m *metricsImpl) Init(store db.Store) error {
×
65
        var err error
×
66
        m.instrumentsOnce.Do(func() {
×
67
                err = m.initInstrumentsOnce(store)
×
68
        })
×
69
        return err
×
70
}
71

72
func (m *metricsImpl) initInstrumentsOnce(store db.Store) error {
×
73
        _, err := m.meter.Int64ObservableGauge("user.count",
×
74
                metric.WithDescription("Number of users in the database"),
×
75
                metric.WithUnit("users"),
×
76
                metric.WithInt64Callback(func(ctx context.Context, observer metric.Int64Observer) error {
×
77
                        c, err := store.CountUsers(ctx)
×
78
                        if err != nil {
×
79
                                return err
×
80
                        }
×
81
                        observer.Observe(c)
×
82
                        return nil
×
83
                }),
84
        )
85
        if err != nil {
×
86
                return fmt.Errorf("failed to create user count gauge: %w", err)
×
87
        }
×
88

89
        _, err = m.meter.Int64ObservableGauge("repository.count",
×
90
                metric.WithDescription("Number of repositories in the database"),
×
91
                metric.WithUnit("repositories"),
×
92
                metric.WithInt64Callback(func(ctx context.Context, observer metric.Int64Observer) error {
×
93
                        c, err := store.CountRepositories(ctx)
×
94
                        if err != nil {
×
95
                                return err
×
96
                        }
×
97
                        observer.Observe(c)
×
98
                        return nil
×
99
                }),
100
        )
101
        if err != nil {
×
102
                return fmt.Errorf("failed to create repository count gauge: %w", err)
×
103
        }
×
104

105
        _, err = m.meter.Int64ObservableGauge("profile_entity.count",
×
106
                metric.WithDescription("Number of profiles in the database, labeled by entity type"),
×
107
                metric.WithUnit("profiles"),
×
108
                metric.WithInt64Callback(func(ctx context.Context, observer metric.Int64Observer) error {
×
109
                        rows, err := store.CountProfilesByEntityType(ctx)
×
110
                        if err != nil {
×
111
                                return err
×
112
                        }
×
113
                        for _, row := range rows {
×
114
                                labels := []attribute.KeyValue{
×
115
                                        attribute.String("entity_type", string(row.ProfileEntity)),
×
116
                                }
×
117
                                observer.Observe(row.NumProfiles, metric.WithAttributes(labels...))
×
118
                        }
×
119
                        return nil
×
120
                }),
121
        )
122
        if err != nil {
×
123
                return fmt.Errorf("failed to create profile count gauge: %w", err)
×
124
        }
×
125

126
        _, err = m.meter.Int64ObservableGauge("profile.quickstart.count",
×
127
                metric.WithDescription("Number of quickstart profiles in the database"),
×
128
                metric.WithUnit("profiles"),
×
129
                metric.WithInt64Callback(func(ctx context.Context, observer metric.Int64Observer) error {
×
130
                        // the profile name is currently hardcoded in cmd/cli/app/quickstart/embed/profile.yaml
×
131
                        const quickstartProfileName = "quickstart-profile"
×
132

×
133
                        num, err := store.CountProfilesByName(ctx, quickstartProfileName)
×
134
                        if err != nil {
×
135
                                return err
×
136
                        }
×
137
                        observer.Observe(num)
×
138
                        return nil
×
139
                }),
140
        )
141
        if err != nil {
×
142
                return fmt.Errorf("failed to create the quickstart profile count gauge: %w", err)
×
143
        }
×
144

145
        m.webhookStatusCodeCounter, err = m.meter.Int64Counter("webhook.status_code",
×
146
                metric.WithDescription("Number of webhook requests by status code"),
×
147
                metric.WithUnit("requests"))
×
148
        if err != nil {
×
149
                return fmt.Errorf("failed to create webhook status code counter: %w", err)
×
150
        }
×
151

152
        m.webhookEventTypeCounter, err = m.meter.Int64Counter("webhook.event_type",
×
153
                metric.WithDescription("Number of webhook events by event type"),
×
154
                metric.WithUnit("events"))
×
155
        if err != nil {
×
156
                return fmt.Errorf("failed to create webhook event type counter: %w", err)
×
157
        }
×
158

159
        m.tokenOpCounter, err = m.meter.Int64Counter("token-checks",
×
160
                metric.WithDescription("Number of times token URLs are issued and consumed"),
×
161
                metric.WithUnit("ops"))
×
162
        if err != nil {
×
163
                return fmt.Errorf("failed to create token operations counter: %w", err)
×
164
        }
×
165

166
        return nil
×
167
}
168

169
// AddWebhookEventTypeCount adds a count to the webhook event type counter
170
func (m *metricsImpl) AddWebhookEventTypeCount(ctx context.Context, state *WebhookEventState) {
×
171
        if m.webhookEventTypeCounter == nil {
×
172
                return
×
173
        }
×
174

175
        labels := []attribute.KeyValue{
×
176
                attribute.String("webhook_event.type", state.Typ),
×
177
                attribute.Bool("webhook_event.accepted", state.Accepted),
×
178
                attribute.Bool("webhook_event.error", state.Error),
×
179
        }
×
180
        m.webhookEventTypeCounter.Add(ctx, 1, metric.WithAttributes(labels...))
×
181
}
182

183
func (m *metricsImpl) AddTokenOpCount(ctx context.Context, stage string, hasId bool) {
×
184
        if m.tokenOpCounter == nil {
×
185
                return
×
186
        }
×
187

188
        m.tokenOpCounter.Add(ctx, 1, metric.WithAttributes(
×
189
                attribute.String("stage", stage),
×
190
                attribute.Bool("has-id", hasId)))
×
191
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc