feat(coderd/telemetry): add telemetry for database Tasks (#20279)

Adds Tasks to telemetry snapshots

Co-authored-by: Mathias Fredriksson <mafredri@gmail.com>
This commit is contained in:
Cian Johnston
2025-10-17 10:48:56 +01:00
committed by GitHub
parent 14e80022c9
commit dc6e50d6b7
5 changed files with 102 additions and 7 deletions
+60
View File
@@ -730,6 +730,19 @@ func (r *remoteReporter) createSnapshot() (*Snapshot, error) {
}
return nil
})
eg.Go(func() error {
dbTasks, err := r.options.Database.ListTasks(ctx, database.ListTasksParams{
OwnerID: uuid.Nil,
OrganizationID: uuid.Nil,
})
if err != nil {
return err
}
for _, dbTask := range dbTasks {
snapshot.Tasks = append(snapshot.Tasks, ConvertTask(dbTask))
}
return nil
})
err := eg.Wait()
if err != nil {
@@ -1205,6 +1218,7 @@ type Snapshot struct {
Workspaces []Workspace `json:"workspaces"`
NetworkEvents []NetworkEvent `json:"network_events"`
Organizations []Organization `json:"organizations"`
Tasks []Task `json:"tasks"`
TelemetryItems []TelemetryItem `json:"telemetry_items"`
UserTailnetConnections []UserTailnetConnection `json:"user_tailnet_connections"`
PrebuiltWorkspaces []PrebuiltWorkspace `json:"prebuilt_workspaces"`
@@ -1753,6 +1767,52 @@ type Organization struct {
CreatedAt time.Time `json:"created_at"`
}
type Task struct {
ID string `json:"id"`
OrganizationID string `json:"organization_id"`
OwnerID string `json:"owner_id"`
Name string `json:"name"`
WorkspaceID *string `json:"workspace_id"`
WorkspaceBuildNumber *int64 `json:"workspace_build_number"`
WorkspaceAgentID *string `json:"workspace_agent_id"`
WorkspaceAppID *string `json:"workspace_app_id"`
TemplateVersionID string `json:"template_version_id"`
PromptHash string `json:"prompt_hash"` // Prompt is hashed for privacy.
CreatedAt time.Time `json:"created_at"`
Status string `json:"status"`
}
// ConvertTask anonymizes a Task.
func ConvertTask(task database.Task) Task {
t := &Task{
ID: task.ID.String(),
OrganizationID: task.OrganizationID.String(),
OwnerID: task.OwnerID.String(),
Name: task.Name,
WorkspaceID: nil,
WorkspaceBuildNumber: nil,
WorkspaceAgentID: nil,
WorkspaceAppID: nil,
TemplateVersionID: task.TemplateVersionID.String(),
PromptHash: fmt.Sprintf("%x", sha256.Sum256([]byte(task.Prompt))),
CreatedAt: task.CreatedAt,
Status: string(task.Status),
}
if task.WorkspaceID.Valid {
t.WorkspaceID = ptr.Ref(task.WorkspaceID.UUID.String())
}
if task.WorkspaceBuildNumber.Valid {
t.WorkspaceBuildNumber = ptr.Ref(int64(task.WorkspaceBuildNumber.Int32))
}
if task.WorkspaceAgentID.Valid {
t.WorkspaceAgentID = ptr.Ref(task.WorkspaceAgentID.UUID.String())
}
if task.WorkspaceAppID.Valid {
t.WorkspaceAppID = ptr.Ref(task.WorkspaceAppID.UUID.String())
}
return *t
}
type telemetryItemKey string
// The comment below gets rid of the warning that the name "TelemetryItemKey" has
+30
View File
@@ -151,6 +151,20 @@ func TestTelemetry(t *testing.T) {
HasAITask: sql.NullBool{Valid: true, Bool: true},
AITaskSidebarAppID: uuid.NullUUID{Valid: true, UUID: taskWsApp.ID},
})
task := dbgen.Task(t, db, database.TaskTable{
OwnerID: user.ID,
OrganizationID: org.ID,
WorkspaceID: uuid.NullUUID{Valid: true, UUID: taskWs.ID},
TemplateVersionID: taskTV.ID,
Prompt: "example prompt",
TemplateParameters: json.RawMessage(`{"foo": "bar"}`),
})
taskWA := dbgen.TaskWorkspaceApp(t, db, database.TaskWorkspaceApp{
TaskID: task.ID,
WorkspaceAgentID: uuid.NullUUID{Valid: true, UUID: taskWsAgent.ID},
WorkspaceAppID: uuid.NullUUID{Valid: true, UUID: taskWsApp.ID},
WorkspaceBuildNumber: taskWB.BuildNumber,
})
group := dbgen.Group(t, db, database.Group{
OrganizationID: org.ID,
@@ -220,6 +234,22 @@ func TestTelemetry(t *testing.T) {
require.Len(t, wsa.Subsystems, 2)
require.Equal(t, string(database.WorkspaceAgentSubsystemEnvbox), wsa.Subsystems[0])
require.Equal(t, string(database.WorkspaceAgentSubsystemExectrace), wsa.Subsystems[1])
require.Len(t, snapshot.Tasks, 1)
for _, snapTask := range snapshot.Tasks {
assert.Equal(t, task.ID.String(), snapTask.ID)
assert.Equal(t, task.OrganizationID.String(), snapTask.OrganizationID)
assert.Equal(t, task.OwnerID.String(), snapTask.OwnerID)
assert.Equal(t, task.Name, snapTask.Name)
if assert.True(t, task.WorkspaceID.Valid) {
assert.Equal(t, task.WorkspaceID.UUID.String(), *snapTask.WorkspaceID)
}
assert.EqualValues(t, taskWA.WorkspaceBuildNumber, *snapTask.WorkspaceBuildNumber)
assert.Equal(t, taskWA.WorkspaceAgentID.UUID.String(), *snapTask.WorkspaceAgentID)
assert.Equal(t, taskWA.WorkspaceAppID.UUID.String(), *snapTask.WorkspaceAppID)
assert.Equal(t, task.TemplateVersionID.String(), snapTask.TemplateVersionID)
assert.Equal(t, "e196fe22e61cfa32d8c38749e0ce348108bb4cae29e2c36cdcce7e77faa9eb5f", snapTask.PromptHash)
assert.Equal(t, task.CreatedAt.UTC(), snapTask.CreatedAt.UTC())
}
require.True(t, slices.ContainsFunc(snapshot.TemplateVersions, func(ttv telemetry.TemplateVersion) bool {
if ttv.ID != taskTV.ID {