Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc4f5905

Browse files
authored
feat: expose template insights as Prometheus metrics (#10325)
1 parent997493d commitc4f5905

File tree

11 files changed

+555
-0
lines changed

11 files changed

+555
-0
lines changed

‎cli/server.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ import (
8080
"github.com/coder/coder/v2/coderd/httpmw"
8181
"github.com/coder/coder/v2/coderd/oauthpki"
8282
"github.com/coder/coder/v2/coderd/prometheusmetrics"
83+
"github.com/coder/coder/v2/coderd/prometheusmetrics/insights"
8384
"github.com/coder/coder/v2/coderd/schedule"
8485
"github.com/coder/coder/v2/coderd/telemetry"
8586
"github.com/coder/coder/v2/coderd/tracing"
@@ -200,6 +201,21 @@ func enablePrometheus(
200201
}
201202
afterCtx(ctx,closeWorkspacesFunc)
202203

204+
insightsMetricsCollector,err:=insights.NewMetricsCollector(options.Database,options.Logger,0,0)
205+
iferr!=nil {
206+
returnnil,xerrors.Errorf("unable to initialize insights metrics collector: %w",err)
207+
}
208+
err=options.PrometheusRegistry.Register(insightsMetricsCollector)
209+
iferr!=nil {
210+
returnnil,xerrors.Errorf("unable to register insights metrics collector: %w",err)
211+
}
212+
213+
closeInsightsMetricsCollector,err:=insightsMetricsCollector.Run(ctx)
214+
iferr!=nil {
215+
returnnil,xerrors.Errorf("unable to run insights metrics collector: %w",err)
216+
}
217+
afterCtx(ctx,closeInsightsMetricsCollector)
218+
203219
ifvals.Prometheus.CollectAgentStats {
204220
closeAgentStatsFunc,err:=prometheusmetrics.AgentStats(ctx,logger,options.PrometheusRegistry,options.Database,time.Now(),0)
205221
iferr!=nil {

‎coderd/database/dbauthz/dbauthz.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,6 +1327,13 @@ func (q *querier) GetTemplateInsightsByInterval(ctx context.Context, arg databas
13271327
returnq.db.GetTemplateInsightsByInterval(ctx,arg)
13281328
}
13291329

1330+
func (q*querier)GetTemplateInsightsByTemplate(ctx context.Context,arg database.GetTemplateInsightsByTemplateParams) ([]database.GetTemplateInsightsByTemplateRow,error) {
1331+
iferr:=q.authorizeContext(ctx,rbac.ActionUpdate,rbac.ResourceTemplate.All());err!=nil {
1332+
returnnil,err
1333+
}
1334+
returnq.db.GetTemplateInsightsByTemplate(ctx,arg)
1335+
}
1336+
13301337
func (q*querier)GetTemplateParameterInsights(ctx context.Context,arg database.GetTemplateParameterInsightsParams) ([]database.GetTemplateParameterInsightsRow,error) {
13311338
for_,templateID:=rangearg.TemplateIDs {
13321339
template,err:=q.db.GetTemplateByID(ctx,templateID)

‎coderd/database/dbfake/dbfake.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2500,6 +2500,10 @@ func (q *FakeQuerier) GetTemplateInsights(_ context.Context, arg database.GetTem
25002500

25012501
templateIDSet:=make(map[uuid.UUID]struct{})
25022502
appUsageIntervalsByUser:=make(map[uuid.UUID]map[time.Time]*database.GetTemplateInsightsRow)
2503+
2504+
q.mutex.RLock()
2505+
deferq.mutex.RUnlock()
2506+
25032507
for_,s:=rangeq.workspaceAgentStats {
25042508
ifs.CreatedAt.Before(arg.StartTime)||s.CreatedAt.Equal(arg.EndTime)||s.CreatedAt.After(arg.EndTime) {
25052509
continue
@@ -2648,6 +2652,101 @@ func (q *FakeQuerier) GetTemplateInsightsByInterval(ctx context.Context, arg dat
26482652
returnresult,nil
26492653
}
26502654

2655+
func (q*FakeQuerier)GetTemplateInsightsByTemplate(_ context.Context,arg database.GetTemplateInsightsByTemplateParams) ([]database.GetTemplateInsightsByTemplateRow,error) {
2656+
err:=validateDatabaseType(arg)
2657+
iferr!=nil {
2658+
returnnil,err
2659+
}
2660+
2661+
q.mutex.RLock()
2662+
deferq.mutex.RUnlock()
2663+
2664+
// map time.Time x TemplateID x UserID x <usage>
2665+
appUsageByTemplateAndUser:=map[time.Time]map[uuid.UUID]map[uuid.UUID]database.GetTemplateInsightsByTemplateRow{}
2666+
2667+
// Review agent stats in terms of usage
2668+
templateIDSet:=make(map[uuid.UUID]struct{})
2669+
2670+
for_,s:=rangeq.workspaceAgentStats {
2671+
ifs.CreatedAt.Before(arg.StartTime)||s.CreatedAt.Equal(arg.EndTime)||s.CreatedAt.After(arg.EndTime) {
2672+
continue
2673+
}
2674+
ifs.ConnectionCount==0 {
2675+
continue
2676+
}
2677+
2678+
t:=s.CreatedAt.Truncate(time.Minute)
2679+
templateIDSet[s.TemplateID]=struct{}{}
2680+
2681+
if_,ok:=appUsageByTemplateAndUser[t];!ok {
2682+
appUsageByTemplateAndUser[t]=make(map[uuid.UUID]map[uuid.UUID]database.GetTemplateInsightsByTemplateRow)
2683+
}
2684+
2685+
if_,ok:=appUsageByTemplateAndUser[t][s.TemplateID];!ok {
2686+
appUsageByTemplateAndUser[t][s.TemplateID]=make(map[uuid.UUID]database.GetTemplateInsightsByTemplateRow)
2687+
}
2688+
2689+
if_,ok:=appUsageByTemplateAndUser[t][s.TemplateID][s.UserID];!ok {
2690+
appUsageByTemplateAndUser[t][s.TemplateID][s.UserID]= database.GetTemplateInsightsByTemplateRow{}
2691+
}
2692+
2693+
u:=appUsageByTemplateAndUser[t][s.TemplateID][s.UserID]
2694+
ifs.SessionCountJetBrains>0 {
2695+
u.UsageJetbrainsSeconds=60
2696+
}
2697+
ifs.SessionCountVSCode>0 {
2698+
u.UsageVscodeSeconds=60
2699+
}
2700+
ifs.SessionCountReconnectingPTY>0 {
2701+
u.UsageReconnectingPtySeconds=60
2702+
}
2703+
ifs.SessionCountSSH>0 {
2704+
u.UsageSshSeconds=60
2705+
}
2706+
appUsageByTemplateAndUser[t][s.TemplateID][s.UserID]=u
2707+
}
2708+
2709+
// Sort used templates
2710+
templateIDs:=make([]uuid.UUID,0,len(templateIDSet))
2711+
fortemplateID:=rangetemplateIDSet {
2712+
templateIDs=append(templateIDs,templateID)
2713+
}
2714+
slices.SortFunc(templateIDs,func(a,b uuid.UUID)int {
2715+
returnslice.Ascending(a.String(),b.String())
2716+
})
2717+
2718+
// Build result
2719+
varresult []database.GetTemplateInsightsByTemplateRow
2720+
for_,templateID:=rangetemplateIDs {
2721+
r:= database.GetTemplateInsightsByTemplateRow{
2722+
TemplateID:templateID,
2723+
}
2724+
2725+
uniqueUsers:=map[uuid.UUID]struct{}{}
2726+
2727+
for_,mTemplateUserUsage:=rangeappUsageByTemplateAndUser {
2728+
mUserUsage,ok:=mTemplateUserUsage[templateID]
2729+
if!ok {
2730+
continue// template was not used in this time window
2731+
}
2732+
2733+
foruserID,usage:=rangemUserUsage {
2734+
uniqueUsers[userID]=struct{}{}
2735+
2736+
r.UsageJetbrainsSeconds+=usage.UsageJetbrainsSeconds
2737+
r.UsageVscodeSeconds+=usage.UsageVscodeSeconds
2738+
r.UsageReconnectingPtySeconds+=usage.UsageReconnectingPtySeconds
2739+
r.UsageSshSeconds+=usage.UsageSshSeconds
2740+
}
2741+
}
2742+
2743+
r.ActiveUsers=int64(len(uniqueUsers))
2744+
2745+
result=append(result,r)
2746+
}
2747+
returnresult,nil
2748+
}
2749+
26512750
func (q*FakeQuerier)GetTemplateParameterInsights(ctx context.Context,arg database.GetTemplateParameterInsightsParams) ([]database.GetTemplateParameterInsightsRow,error) {
26522751
err:=validateDatabaseType(arg)
26532752
iferr!=nil {

‎coderd/database/dbmetrics/dbmetrics.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/dbmock/dbmock.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries.sql.go

Lines changed: 73 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries/insights.sql

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,34 @@ SELECT
134134
COALESCE(SUM(usage_ssh_seconds),0)::bigintAS usage_ssh_seconds
135135
FROM agent_stats_by_interval_and_user;
136136

137+
-- name: GetTemplateInsightsByTemplate :many
138+
WITH agent_stats_by_interval_and_userAS (
139+
SELECT
140+
date_trunc('minute',was.created_at)AS created_at_trunc,
141+
was.template_id,
142+
was.user_id,
143+
CASE WHENSUM(was.session_count_vscode)>0 THEN60 ELSE0 ENDAS usage_vscode_seconds,
144+
CASE WHENSUM(was.session_count_jetbrains)>0 THEN60 ELSE0 ENDAS usage_jetbrains_seconds,
145+
CASE WHENSUM(was.session_count_reconnecting_pty)>0 THEN60 ELSE0 ENDAS usage_reconnecting_pty_seconds,
146+
CASE WHENSUM(was.session_count_ssh)>0 THEN60 ELSE0 ENDAS usage_ssh_seconds
147+
FROM workspace_agent_stats was
148+
WHERE
149+
was.created_at>= @start_time::timestamptz
150+
ANDwas.created_at< @end_time::timestamptz
151+
ANDwas.connection_count>0
152+
GROUP BY created_at_trunc,was.template_id,was.user_id
153+
)
154+
155+
SELECT
156+
template_id,
157+
COALESCE(COUNT(DISTINCT user_id))::bigintAS active_users,
158+
COALESCE(SUM(usage_vscode_seconds),0)::bigintAS usage_vscode_seconds,
159+
COALESCE(SUM(usage_jetbrains_seconds),0)::bigintAS usage_jetbrains_seconds,
160+
COALESCE(SUM(usage_reconnecting_pty_seconds),0)::bigintAS usage_reconnecting_pty_seconds,
161+
COALESCE(SUM(usage_ssh_seconds),0)::bigintAS usage_ssh_seconds
162+
FROM agent_stats_by_interval_and_user
163+
GROUP BY template_id;
164+
137165
-- name: GetTemplateAppInsights :many
138166
-- GetTemplateAppInsights returns the aggregate usage of each app in a given
139167
-- timeframe. The result can be filtered on template_ids, meaning only user data

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp