Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9ad124d

Browse files
authored
feat(coderd/telemetry): track AI task usage (#19418)
Relates to coder/internal#868
1 parent 5b1e809 commit 9ad124d

File tree

2 files changed

+79
-10
lines changed

2 files changed

+79
-10
lines changed

coderd/telemetry/telemetry.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ func ConvertWorkspace(workspace database.Workspace) Workspace {
768768

769769
// ConvertWorkspaceBuild anonymizes a workspace build.
770770
func ConvertWorkspaceBuild(build database.WorkspaceBuild) WorkspaceBuild {
771-
return WorkspaceBuild{
771+
wb := WorkspaceBuild{
772772
ID: build.ID,
773773
CreatedAt: build.CreatedAt,
774774
WorkspaceID: build.WorkspaceID,
@@ -777,6 +777,10 @@ func ConvertWorkspaceBuild(build database.WorkspaceBuild) WorkspaceBuild {
777777
// #nosec G115 - Safe conversion as build numbers are expected to be positive and within uint32 range
778778
BuildNumber: uint32(build.BuildNumber),
779779
}
780+
if build.HasAITask.Valid {
781+
wb.HasAITask = ptr.Ref(build.HasAITask.Bool)
782+
}
783+
return wb
780784
}
781785

782786
// ConvertProvisionerJob anonymizes a provisioner job.
@@ -1105,6 +1109,9 @@ func ConvertTemplateVersion(version database.TemplateVersion) TemplateVersion {
11051109
if version.SourceExampleID.Valid {
11061110
snapVersion.SourceExampleID = &version.SourceExampleID.String
11071111
}
1112+
if version.HasAITask.Valid {
1113+
snapVersion.HasAITask = ptr.Ref(version.HasAITask.Bool)
1114+
}
11081115
return snapVersion
11091116
}
11101117

@@ -1357,6 +1364,7 @@ type WorkspaceBuild struct {
13571364
TemplateVersionID uuid.UUID `json:"template_version_id"`
13581365
JobID uuid.UUID `json:"job_id"`
13591366
BuildNumber uint32 `json:"build_number"`
1367+
HasAITask *bool `json:"has_ai_task"`
13601368
}
13611369

13621370
type Workspace struct {
@@ -1404,6 +1412,7 @@ type TemplateVersion struct {
14041412
OrganizationID uuid.UUID `json:"organization_id"`
14051413
JobID uuid.UUID `json:"job_id"`
14061414
SourceExampleID *string `json:"source_example_id,omitempty"`
1415+
HasAITask *bool `json:"has_ai_task"`
14071416
}
14081417

14091418
type ProvisionerJob struct {

coderd/telemetry/telemetry_test.go

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"net/http"
88
"net/http/httptest"
99
"net/url"
10+
"slices"
1011
"sort"
1112
"testing"
1213
"time"
@@ -105,6 +106,52 @@ func TestTelemetry(t *testing.T) {
105106
OpenIn: database.WorkspaceAppOpenInSlimWindow,
106107
AgentID: wsagent.ID,
107108
})
109+
110+
taskJob := dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{
111+
Provisioner: database.ProvisionerTypeTerraform,
112+
StorageMethod: database.ProvisionerStorageMethodFile,
113+
Type: database.ProvisionerJobTypeTemplateVersionDryRun,
114+
OrganizationID: org.ID,
115+
})
116+
taskTpl := dbgen.Template(t, db, database.Template{
117+
Provisioner: database.ProvisionerTypeTerraform,
118+
OrganizationID: org.ID,
119+
CreatedBy: user.ID,
120+
})
121+
taskTV := dbgen.TemplateVersion(t, db, database.TemplateVersion{
122+
OrganizationID: org.ID,
123+
TemplateID: uuid.NullUUID{UUID: taskTpl.ID, Valid: true},
124+
CreatedBy: user.ID,
125+
JobID: taskJob.ID,
126+
HasAITask: sql.NullBool{Bool: true, Valid: true},
127+
})
128+
taskWs := dbgen.Workspace(t, db, database.WorkspaceTable{
129+
OwnerID: user.ID,
130+
OrganizationID: org.ID,
131+
TemplateID: taskTpl.ID,
132+
})
133+
taskWsResource := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{
134+
JobID: taskJob.ID,
135+
})
136+
taskWsAgent := dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{
137+
ResourceID: taskWsResource.ID,
138+
})
139+
taskWsApp := dbgen.WorkspaceApp(t, db, database.WorkspaceApp{
140+
SharingLevel: database.AppSharingLevelOwner,
141+
Health: database.WorkspaceAppHealthDisabled,
142+
OpenIn: database.WorkspaceAppOpenInSlimWindow,
143+
AgentID: taskWsAgent.ID,
144+
})
145+
taskWB := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{
146+
Transition: database.WorkspaceTransitionStart,
147+
Reason: database.BuildReasonAutostart,
148+
WorkspaceID: taskWs.ID,
149+
TemplateVersionID: tv.ID,
150+
JobID: taskJob.ID,
151+
HasAITask: sql.NullBool{Valid: true, Bool: true},
152+
AITaskSidebarAppID: uuid.NullUUID{Valid: true, UUID: taskWsApp.ID},
153+
})
154+
108155
group := dbgen.Group(t, db, database.Group{
109156
OrganizationID: org.ID,
110157
})
@@ -148,19 +195,19 @@ func TestTelemetry(t *testing.T) {
148195
})
149196

150197
_, snapshot := collectSnapshot(ctx, t, db, nil)
151-
require.Len(t, snapshot.ProvisionerJobs, 1)
198+
require.Len(t, snapshot.ProvisionerJobs, 2)
152199
require.Len(t, snapshot.Licenses, 1)
153-
require.Len(t, snapshot.Templates, 1)
154-
require.Len(t, snapshot.TemplateVersions, 2)
200+
require.Len(t, snapshot.Templates, 2)
201+
require.Len(t, snapshot.TemplateVersions, 3)
155202
require.Len(t, snapshot.Users, 1)
156203
require.Len(t, snapshot.Groups, 2)
157204
// 1 member in the everyone group + 1 member in the custom group
158205
require.Len(t, snapshot.GroupMembers, 2)
159-
require.Len(t, snapshot.Workspaces, 1)
160-
require.Len(t, snapshot.WorkspaceApps, 1)
161-
require.Len(t, snapshot.WorkspaceAgents, 1)
162-
require.Len(t, snapshot.WorkspaceBuilds, 1)
163-
require.Len(t, snapshot.WorkspaceResources, 1)
206+
require.Len(t, snapshot.Workspaces, 2)
207+
require.Len(t, snapshot.WorkspaceApps, 2)
208+
require.Len(t, snapshot.WorkspaceAgents, 2)
209+
require.Len(t, snapshot.WorkspaceBuilds, 2)
210+
require.Len(t, snapshot.WorkspaceResources, 2)
164211
require.Len(t, snapshot.WorkspaceAgentStats, 1)
165212
require.Len(t, snapshot.WorkspaceProxies, 1)
166213
require.Len(t, snapshot.WorkspaceModules, 1)
@@ -169,11 +216,24 @@ func TestTelemetry(t *testing.T) {
169216
require.Len(t, snapshot.TelemetryItems, 2)
170217
require.Len(t, snapshot.WorkspaceAgentMemoryResourceMonitors, 1)
171218
require.Len(t, snapshot.WorkspaceAgentVolumeResourceMonitors, 1)
172-
wsa := snapshot.WorkspaceAgents[0]
219+
wsa := snapshot.WorkspaceAgents[1]
173220
require.Len(t, wsa.Subsystems, 2)
174221
require.Equal(t, string(database.WorkspaceAgentSubsystemEnvbox), wsa.Subsystems[0])
175222
require.Equal(t, string(database.WorkspaceAgentSubsystemExectrace), wsa.Subsystems[1])
176223

224+
require.True(t, slices.ContainsFunc(snapshot.TemplateVersions, func(ttv telemetry.TemplateVersion) bool {
225+
if ttv.ID != taskTV.ID {
226+
return false
227+
}
228+
return assert.NotNil(t, ttv.HasAITask) && assert.True(t, *ttv.HasAITask)
229+
}))
230+
require.True(t, slices.ContainsFunc(snapshot.WorkspaceBuilds, func(twb telemetry.WorkspaceBuild) bool {
231+
if twb.ID != taskWB.ID {
232+
return false
233+
}
234+
return assert.NotNil(t, twb.HasAITask) && assert.True(t, *twb.HasAITask)
235+
}))
236+
177237
tvs := snapshot.TemplateVersions
178238
sort.Slice(tvs, func(i, j int) bool {
179239
// Sort by SourceExampleID presence (non-nil comes before nil)

0 commit comments

Comments
 (0)