mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
@@ -2046,6 +2046,13 @@ func (q *querier) InsertWorkspaceApp(ctx context.Context, arg database.InsertWor
|
||||
return q.db.InsertWorkspaceApp(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) InsertWorkspaceAppStats(ctx context.Context, arg database.InsertWorkspaceAppStatsParams) error {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceSystem); err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.InsertWorkspaceAppStats(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) InsertWorkspaceBuild(ctx context.Context, arg database.InsertWorkspaceBuildParams) error {
|
||||
w, err := q.db.GetWorkspaceByID(ctx, arg.WorkspaceID)
|
||||
if err != nil {
|
||||
|
||||
@@ -114,33 +114,35 @@ type data struct {
|
||||
userLinks []database.UserLink
|
||||
|
||||
// New tables
|
||||
workspaceAgentStats []database.WorkspaceAgentStat
|
||||
auditLogs []database.AuditLog
|
||||
files []database.File
|
||||
gitAuthLinks []database.GitAuthLink
|
||||
gitSSHKey []database.GitSSHKey
|
||||
groupMembers []database.GroupMember
|
||||
groups []database.Group
|
||||
licenses []database.License
|
||||
parameterSchemas []database.ParameterSchema
|
||||
provisionerDaemons []database.ProvisionerDaemon
|
||||
provisionerJobLogs []database.ProvisionerJobLog
|
||||
provisionerJobs []database.ProvisionerJob
|
||||
replicas []database.Replica
|
||||
templateVersions []database.TemplateVersionTable
|
||||
templateVersionParameters []database.TemplateVersionParameter
|
||||
templateVersionVariables []database.TemplateVersionVariable
|
||||
templates []database.TemplateTable
|
||||
workspaceAgents []database.WorkspaceAgent
|
||||
workspaceAgentMetadata []database.WorkspaceAgentMetadatum
|
||||
workspaceAgentLogs []database.WorkspaceAgentLog
|
||||
workspaceApps []database.WorkspaceApp
|
||||
workspaceBuilds []database.WorkspaceBuildTable
|
||||
workspaceBuildParameters []database.WorkspaceBuildParameter
|
||||
workspaceResourceMetadata []database.WorkspaceResourceMetadatum
|
||||
workspaceResources []database.WorkspaceResource
|
||||
workspaces []database.Workspace
|
||||
workspaceProxies []database.WorkspaceProxy
|
||||
workspaceAgentStats []database.WorkspaceAgentStat
|
||||
auditLogs []database.AuditLog
|
||||
files []database.File
|
||||
gitAuthLinks []database.GitAuthLink
|
||||
gitSSHKey []database.GitSSHKey
|
||||
groupMembers []database.GroupMember
|
||||
groups []database.Group
|
||||
licenses []database.License
|
||||
parameterSchemas []database.ParameterSchema
|
||||
provisionerDaemons []database.ProvisionerDaemon
|
||||
provisionerJobLogs []database.ProvisionerJobLog
|
||||
provisionerJobs []database.ProvisionerJob
|
||||
replicas []database.Replica
|
||||
templateVersions []database.TemplateVersionTable
|
||||
templateVersionParameters []database.TemplateVersionParameter
|
||||
templateVersionVariables []database.TemplateVersionVariable
|
||||
templates []database.TemplateTable
|
||||
workspaceAgents []database.WorkspaceAgent
|
||||
workspaceAgentMetadata []database.WorkspaceAgentMetadatum
|
||||
workspaceAgentLogs []database.WorkspaceAgentLog
|
||||
workspaceApps []database.WorkspaceApp
|
||||
workspaceAppStatsLastInsertID int64
|
||||
workspaceAppStats []database.WorkspaceAppStat
|
||||
workspaceBuilds []database.WorkspaceBuildTable
|
||||
workspaceBuildParameters []database.WorkspaceBuildParameter
|
||||
workspaceResourceMetadata []database.WorkspaceResourceMetadatum
|
||||
workspaceResources []database.WorkspaceResource
|
||||
workspaces []database.Workspace
|
||||
workspaceProxies []database.WorkspaceProxy
|
||||
// Locks is a map of lock names. Any keys within the map are currently
|
||||
// locked.
|
||||
locks map[int64]struct{}
|
||||
@@ -4336,6 +4338,44 @@ func (q *FakeQuerier) InsertWorkspaceApp(_ context.Context, arg database.InsertW
|
||||
return workspaceApp, nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) InsertWorkspaceAppStats(_ context.Context, arg database.InsertWorkspaceAppStatsParams) error {
|
||||
err := validateDatabaseType(arg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
InsertWorkspaceAppStatsLoop:
|
||||
for i := 0; i < len(arg.UserID); i++ {
|
||||
stat := database.WorkspaceAppStat{
|
||||
ID: q.workspaceAppStatsLastInsertID + 1,
|
||||
UserID: arg.UserID[i],
|
||||
WorkspaceID: arg.WorkspaceID[i],
|
||||
AgentID: arg.AgentID[i],
|
||||
AccessMethod: arg.AccessMethod[i],
|
||||
SlugOrPort: arg.SlugOrPort[i],
|
||||
SessionID: arg.SessionID[i],
|
||||
SessionStartedAt: arg.SessionStartedAt[i],
|
||||
SessionEndedAt: arg.SessionEndedAt[i],
|
||||
Requests: arg.Requests[i],
|
||||
}
|
||||
for j, s := range q.workspaceAppStats {
|
||||
// Check unique constraint for upsert.
|
||||
if s.UserID == stat.UserID && s.AgentID == stat.AgentID && s.SessionID == stat.SessionID {
|
||||
q.workspaceAppStats[j].SessionEndedAt = stat.SessionEndedAt
|
||||
q.workspaceAppStats[j].Requests = stat.Requests
|
||||
continue InsertWorkspaceAppStatsLoop
|
||||
}
|
||||
}
|
||||
q.workspaceAppStats = append(q.workspaceAppStats, stat)
|
||||
q.workspaceAppStatsLastInsertID++
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) InsertWorkspaceBuild(_ context.Context, arg database.InsertWorkspaceBuildParams) error {
|
||||
if err := validateDatabaseType(arg); err != nil {
|
||||
return err
|
||||
|
||||
@@ -1264,6 +1264,13 @@ func (m metricsStore) InsertWorkspaceApp(ctx context.Context, arg database.Inser
|
||||
return app, err
|
||||
}
|
||||
|
||||
func (m metricsStore) InsertWorkspaceAppStats(ctx context.Context, arg database.InsertWorkspaceAppStatsParams) error {
|
||||
start := time.Now()
|
||||
r0 := m.s.InsertWorkspaceAppStats(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("InsertWorkspaceAppStats").Observe(time.Since(start).Seconds())
|
||||
return r0
|
||||
}
|
||||
|
||||
func (m metricsStore) InsertWorkspaceBuild(ctx context.Context, arg database.InsertWorkspaceBuildParams) error {
|
||||
start := time.Now()
|
||||
err := m.s.InsertWorkspaceBuild(ctx, arg)
|
||||
|
||||
@@ -2657,6 +2657,20 @@ func (mr *MockStoreMockRecorder) InsertWorkspaceApp(arg0, arg1 interface{}) *gom
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceApp", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceApp), arg0, arg1)
|
||||
}
|
||||
|
||||
// InsertWorkspaceAppStats mocks base method.
|
||||
func (m *MockStore) InsertWorkspaceAppStats(arg0 context.Context, arg1 database.InsertWorkspaceAppStatsParams) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InsertWorkspaceAppStats", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// InsertWorkspaceAppStats indicates an expected call of InsertWorkspaceAppStats.
|
||||
func (mr *MockStoreMockRecorder) InsertWorkspaceAppStats(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceAppStats", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceAppStats), arg0, arg1)
|
||||
}
|
||||
|
||||
// InsertWorkspaceBuild mocks base method.
|
||||
func (m *MockStore) InsertWorkspaceBuild(arg0 context.Context, arg1 database.InsertWorkspaceBuildParams) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
Generated
+63
@@ -812,6 +812,50 @@ COMMENT ON COLUMN workspace_agents.started_at IS 'The time the agent entered the
|
||||
|
||||
COMMENT ON COLUMN workspace_agents.ready_at IS 'The time the agent entered the ready or start_error lifecycle state';
|
||||
|
||||
CREATE TABLE workspace_app_stats (
|
||||
id bigint NOT NULL,
|
||||
user_id uuid NOT NULL,
|
||||
workspace_id uuid NOT NULL,
|
||||
agent_id uuid NOT NULL,
|
||||
access_method text NOT NULL,
|
||||
slug_or_port text NOT NULL,
|
||||
session_id uuid NOT NULL,
|
||||
session_started_at timestamp with time zone NOT NULL,
|
||||
session_ended_at timestamp with time zone NOT NULL,
|
||||
requests integer NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON TABLE workspace_app_stats IS 'A record of workspace app usage statistics';
|
||||
|
||||
COMMENT ON COLUMN workspace_app_stats.id IS 'The ID of the record';
|
||||
|
||||
COMMENT ON COLUMN workspace_app_stats.user_id IS 'The user who used the workspace app';
|
||||
|
||||
COMMENT ON COLUMN workspace_app_stats.workspace_id IS 'The workspace that the workspace app was used in';
|
||||
|
||||
COMMENT ON COLUMN workspace_app_stats.agent_id IS 'The workspace agent that was used';
|
||||
|
||||
COMMENT ON COLUMN workspace_app_stats.access_method IS 'The method used to access the workspace app';
|
||||
|
||||
COMMENT ON COLUMN workspace_app_stats.slug_or_port IS 'The slug or port used to to identify the app';
|
||||
|
||||
COMMENT ON COLUMN workspace_app_stats.session_id IS 'The unique identifier for the session';
|
||||
|
||||
COMMENT ON COLUMN workspace_app_stats.session_started_at IS 'The time the session started';
|
||||
|
||||
COMMENT ON COLUMN workspace_app_stats.session_ended_at IS 'The time the session ended';
|
||||
|
||||
COMMENT ON COLUMN workspace_app_stats.requests IS 'The number of requests made during the session, a number larger than 1 indicates that multiple sessions were rolled up into one';
|
||||
|
||||
CREATE SEQUENCE workspace_app_stats_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE workspace_app_stats_id_seq OWNED BY workspace_app_stats.id;
|
||||
|
||||
CREATE TABLE workspace_apps (
|
||||
id uuid NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
@@ -969,6 +1013,8 @@ ALTER TABLE ONLY provisioner_job_logs ALTER COLUMN id SET DEFAULT nextval('provi
|
||||
|
||||
ALTER TABLE ONLY workspace_agent_logs ALTER COLUMN id SET DEFAULT nextval('workspace_agent_startup_logs_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY workspace_app_stats ALTER COLUMN id SET DEFAULT nextval('workspace_app_stats_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY workspace_proxies ALTER COLUMN region_id SET DEFAULT nextval('workspace_proxies_region_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY workspace_resource_metadata ALTER COLUMN id SET DEFAULT nextval('workspace_resource_metadata_id_seq'::regclass);
|
||||
@@ -1081,6 +1127,12 @@ ALTER TABLE ONLY workspace_agent_logs
|
||||
ALTER TABLE ONLY workspace_agents
|
||||
ADD CONSTRAINT workspace_agents_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY workspace_app_stats
|
||||
ADD CONSTRAINT workspace_app_stats_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY workspace_app_stats
|
||||
ADD CONSTRAINT workspace_app_stats_user_id_agent_id_session_id_key UNIQUE (user_id, agent_id, session_id);
|
||||
|
||||
ALTER TABLE ONLY workspace_apps
|
||||
ADD CONSTRAINT workspace_apps_agent_id_slug_idx UNIQUE (agent_id, slug);
|
||||
|
||||
@@ -1167,6 +1219,8 @@ CREATE INDEX workspace_agents_auth_token_idx ON workspace_agents USING btree (au
|
||||
|
||||
CREATE INDEX workspace_agents_resource_id_idx ON workspace_agents USING btree (resource_id);
|
||||
|
||||
CREATE INDEX workspace_app_stats_workspace_id_idx ON workspace_app_stats USING btree (workspace_id);
|
||||
|
||||
CREATE UNIQUE INDEX workspace_proxies_lower_name_idx ON workspace_proxies USING btree (lower(name)) WHERE (deleted = false);
|
||||
|
||||
CREATE INDEX workspace_resources_job_id_idx ON workspace_resources USING btree (job_id);
|
||||
@@ -1252,6 +1306,15 @@ ALTER TABLE ONLY workspace_agent_logs
|
||||
ALTER TABLE ONLY workspace_agents
|
||||
ADD CONSTRAINT workspace_agents_resource_id_fkey FOREIGN KEY (resource_id) REFERENCES workspace_resources(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY workspace_app_stats
|
||||
ADD CONSTRAINT workspace_app_stats_agent_id_fkey FOREIGN KEY (agent_id) REFERENCES workspace_agents(id);
|
||||
|
||||
ALTER TABLE ONLY workspace_app_stats
|
||||
ADD CONSTRAINT workspace_app_stats_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id);
|
||||
|
||||
ALTER TABLE ONLY workspace_app_stats
|
||||
ADD CONSTRAINT workspace_app_stats_workspace_id_fkey FOREIGN KEY (workspace_id) REFERENCES workspaces(id);
|
||||
|
||||
ALTER TABLE ONLY workspace_apps
|
||||
ADD CONSTRAINT workspace_apps_agent_id_fkey FOREIGN KEY (agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE workspace_app_stats;
|
||||
@@ -0,0 +1,32 @@
|
||||
CREATE TABLE workspace_app_stats (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id uuid NOT NULL REFERENCES users (id),
|
||||
workspace_id uuid NOT NULL REFERENCES workspaces (id),
|
||||
agent_id uuid NOT NULL REFERENCES workspace_agents (id),
|
||||
access_method text NOT NULL,
|
||||
slug_or_port text NOT NULL,
|
||||
session_id uuid NOT NULL,
|
||||
session_started_at timestamptz NOT NULL,
|
||||
session_ended_at timestamptz NOT NULL,
|
||||
requests integer NOT NULL,
|
||||
|
||||
-- Set a unique constraint to allow upserting the session_ended_at
|
||||
-- and requests fields without risk of collisions.
|
||||
UNIQUE(user_id, agent_id, session_id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE workspace_app_stats IS 'A record of workspace app usage statistics';
|
||||
|
||||
COMMENT ON COLUMN workspace_app_stats.id IS 'The ID of the record';
|
||||
COMMENT ON COLUMN workspace_app_stats.user_id IS 'The user who used the workspace app';
|
||||
COMMENT ON COLUMN workspace_app_stats.workspace_id IS 'The workspace that the workspace app was used in';
|
||||
COMMENT ON COLUMN workspace_app_stats.agent_id IS 'The workspace agent that was used';
|
||||
COMMENT ON COLUMN workspace_app_stats.access_method IS 'The method used to access the workspace app';
|
||||
COMMENT ON COLUMN workspace_app_stats.slug_or_port IS 'The slug or port used to to identify the app';
|
||||
COMMENT ON COLUMN workspace_app_stats.session_id IS 'The unique identifier for the session';
|
||||
COMMENT ON COLUMN workspace_app_stats.session_started_at IS 'The time the session started';
|
||||
COMMENT ON COLUMN workspace_app_stats.session_ended_at IS 'The time the session ended';
|
||||
COMMENT ON COLUMN workspace_app_stats.requests IS 'The number of requests made during the session, a number larger than 1 indicates that multiple sessions were rolled up into one';
|
||||
|
||||
-- Create index on workspace_id for joining/filtering by templates.
|
||||
CREATE INDEX workspace_app_stats_workspace_id_idx ON workspace_app_stats (workspace_id);
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
INSERT INTO public.workspace_app_stats (
|
||||
id,
|
||||
user_id,
|
||||
workspace_id,
|
||||
agent_id,
|
||||
access_method,
|
||||
slug_or_port,
|
||||
session_id,
|
||||
session_started_at,
|
||||
session_ended_at,
|
||||
requests
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
1498,
|
||||
'30095c71-380b-457a-8995-97b8ee6e5307',
|
||||
'3a9a1feb-e89d-457c-9d53-ac751b198ebe',
|
||||
'7a1ce5f8-8d00-431c-ad1b-97a846512804',
|
||||
'path',
|
||||
'code-server',
|
||||
'562cbfb8-3d9a-4018-9c04-e8159d5aa43e',
|
||||
'2023-08-14 20:15:00+00',
|
||||
'2023-08-14 20:16:00+00',
|
||||
1
|
||||
),
|
||||
(
|
||||
59,
|
||||
'30095c71-380b-457a-8995-97b8ee6e5307',
|
||||
'3a9a1feb-e89d-457c-9d53-ac751b198ebe',
|
||||
'7a1ce5f8-8d00-431c-ad1b-97a846512804',
|
||||
'terminal',
|
||||
'',
|
||||
'281919d0-5d99-48fb-8a93-2c3019010387',
|
||||
'2023-08-14 14:15:40.085827+00',
|
||||
'2023-08-14 14:17:41.295989+00',
|
||||
1
|
||||
),
|
||||
(
|
||||
58,
|
||||
'30095c71-380b-457a-8995-97b8ee6e5307',
|
||||
'3a9a1feb-e89d-457c-9d53-ac751b198ebe',
|
||||
'7a1ce5f8-8d00-431c-ad1b-97a846512804',
|
||||
'path',
|
||||
'code-server',
|
||||
'5b7c9d43-19e6-4401-997b-c26de2c86c55',
|
||||
'2023-08-14 14:15:34.620496+00',
|
||||
'2023-08-14 23:58:37.158964+00',
|
||||
1
|
||||
),
|
||||
(
|
||||
57,
|
||||
'30095c71-380b-457a-8995-97b8ee6e5307',
|
||||
'3a9a1feb-e89d-457c-9d53-ac751b198ebe',
|
||||
'7a1ce5f8-8d00-431c-ad1b-97a846512804',
|
||||
'path',
|
||||
'code-server',
|
||||
'fe546a68-0921-4a2b-bced-5dc5c5635576',
|
||||
'2023-08-14 14:15:34.129002+00',
|
||||
'2023-08-14 23:58:37.158901+00',
|
||||
1
|
||||
),
|
||||
(
|
||||
56,
|
||||
'30095c71-380b-457a-8995-97b8ee6e5307',
|
||||
'3a9a1feb-e89d-457c-9d53-ac751b198ebe',
|
||||
'7a1ce5f8-8d00-431c-ad1b-97a846512804',
|
||||
'path',
|
||||
'code-server',
|
||||
'96e4e857-598c-4881-bc40-e13008b48bb0',
|
||||
'2023-08-14 14:15:00+00',
|
||||
'2023-08-14 14:16:00+00',
|
||||
36
|
||||
),
|
||||
(
|
||||
7,
|
||||
'30095c71-380b-457a-8995-97b8ee6e5307',
|
||||
'3a9a1feb-e89d-457c-9d53-ac751b198ebe',
|
||||
'7a1ce5f8-8d00-431c-ad1b-97a846512804',
|
||||
'terminal',
|
||||
'',
|
||||
'95d22d41-0fde-447b-9743-0b8583edb60a',
|
||||
'2023-08-14 13:00:28.732837+00',
|
||||
'2023-08-14 13:09:23.990797+00',
|
||||
1
|
||||
),
|
||||
(
|
||||
4,
|
||||
'30095c71-380b-457a-8995-97b8ee6e5307',
|
||||
'3a9a1feb-e89d-457c-9d53-ac751b198ebe',
|
||||
'7a1ce5f8-8d00-431c-ad1b-97a846512804',
|
||||
'path',
|
||||
'code-server',
|
||||
'442688ce-f9e7-46df-ba3d-623ef9a1d30d',
|
||||
'2023-08-14 13:00:12.843977+00',
|
||||
'2023-08-14 13:09:26.276696+00',
|
||||
1
|
||||
),
|
||||
(
|
||||
3,
|
||||
'30095c71-380b-457a-8995-97b8ee6e5307',
|
||||
'3a9a1feb-e89d-457c-9d53-ac751b198ebe',
|
||||
'7a1ce5f8-8d00-431c-ad1b-97a846512804',
|
||||
'path',
|
||||
'code-server',
|
||||
'f963c4f0-55b7-4813-8b61-ea58536754db',
|
||||
'2023-08-14 13:00:12.323196+00',
|
||||
'2023-08-14 13:09:26.277073+00',
|
||||
1
|
||||
),
|
||||
(
|
||||
2,
|
||||
'30095c71-380b-457a-8995-97b8ee6e5307',
|
||||
'3a9a1feb-e89d-457c-9d53-ac751b198ebe',
|
||||
'7a1ce5f8-8d00-431c-ad1b-97a846512804',
|
||||
'terminal',
|
||||
'',
|
||||
'5a034459-73e4-4642-91b8-80b0f718f29e',
|
||||
'2023-08-14 13:00:00+00',
|
||||
'2023-08-14 13:01:00+00',
|
||||
4
|
||||
),
|
||||
(
|
||||
1,
|
||||
'30095c71-380b-457a-8995-97b8ee6e5307',
|
||||
'3a9a1feb-e89d-457c-9d53-ac751b198ebe',
|
||||
'7a1ce5f8-8d00-431c-ad1b-97a846512804',
|
||||
'path',
|
||||
'code-server',
|
||||
'd7a0d8e1-069e-421d-b876-b5d0ddbcaf6d',
|
||||
'2023-08-14 13:00:00+00',
|
||||
'2023-08-14 13:01:00+00',
|
||||
36
|
||||
);
|
||||
@@ -2016,6 +2016,30 @@ type WorkspaceApp struct {
|
||||
External bool `db:"external" json:"external"`
|
||||
}
|
||||
|
||||
// A record of workspace app usage statistics
|
||||
type WorkspaceAppStat struct {
|
||||
// The ID of the record
|
||||
ID int64 `db:"id" json:"id"`
|
||||
// The user who used the workspace app
|
||||
UserID uuid.UUID `db:"user_id" json:"user_id"`
|
||||
// The workspace that the workspace app was used in
|
||||
WorkspaceID uuid.UUID `db:"workspace_id" json:"workspace_id"`
|
||||
// The workspace agent that was used
|
||||
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
|
||||
// The method used to access the workspace app
|
||||
AccessMethod string `db:"access_method" json:"access_method"`
|
||||
// The slug or port used to to identify the app
|
||||
SlugOrPort string `db:"slug_or_port" json:"slug_or_port"`
|
||||
// The unique identifier for the session
|
||||
SessionID uuid.UUID `db:"session_id" json:"session_id"`
|
||||
// The time the session started
|
||||
SessionStartedAt time.Time `db:"session_started_at" json:"session_started_at"`
|
||||
// The time the session ended
|
||||
SessionEndedAt time.Time `db:"session_ended_at" json:"session_ended_at"`
|
||||
// The number of requests made during the session, a number larger than 1 indicates that multiple sessions were rolled up into one
|
||||
Requests int32 `db:"requests" json:"requests"`
|
||||
}
|
||||
|
||||
// Joins in the username + avatar url of the initiated by user.
|
||||
type WorkspaceBuild struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
|
||||
@@ -233,6 +233,7 @@ type sqlcQuerier interface {
|
||||
InsertWorkspaceAgentStat(ctx context.Context, arg InsertWorkspaceAgentStatParams) (WorkspaceAgentStat, error)
|
||||
InsertWorkspaceAgentStats(ctx context.Context, arg InsertWorkspaceAgentStatsParams) error
|
||||
InsertWorkspaceApp(ctx context.Context, arg InsertWorkspaceAppParams) (WorkspaceApp, error)
|
||||
InsertWorkspaceAppStats(ctx context.Context, arg InsertWorkspaceAppStatsParams) error
|
||||
InsertWorkspaceBuild(ctx context.Context, arg InsertWorkspaceBuildParams) error
|
||||
InsertWorkspaceBuildParameters(ctx context.Context, arg InsertWorkspaceBuildParametersParams) error
|
||||
InsertWorkspaceProxy(ctx context.Context, arg InsertWorkspaceProxyParams) (WorkspaceProxy, error)
|
||||
|
||||
@@ -7831,6 +7831,72 @@ func (q *sqlQuerier) UpdateWorkspaceAppHealthByID(ctx context.Context, arg Updat
|
||||
return err
|
||||
}
|
||||
|
||||
const insertWorkspaceAppStats = `-- name: InsertWorkspaceAppStats :exec
|
||||
INSERT INTO
|
||||
workspace_app_stats (
|
||||
user_id,
|
||||
workspace_id,
|
||||
agent_id,
|
||||
access_method,
|
||||
slug_or_port,
|
||||
session_id,
|
||||
session_started_at,
|
||||
session_ended_at,
|
||||
requests
|
||||
)
|
||||
SELECT
|
||||
unnest($1::uuid[]) AS user_id,
|
||||
unnest($2::uuid[]) AS workspace_id,
|
||||
unnest($3::uuid[]) AS agent_id,
|
||||
unnest($4::text[]) AS access_method,
|
||||
unnest($5::text[]) AS slug_or_port,
|
||||
unnest($6::uuid[]) AS session_id,
|
||||
unnest($7::timestamptz[]) AS session_started_at,
|
||||
unnest($8::timestamptz[]) AS session_ended_at,
|
||||
unnest($9::int[]) AS requests
|
||||
ON CONFLICT
|
||||
(user_id, agent_id, session_id)
|
||||
DO
|
||||
UPDATE SET
|
||||
session_ended_at = EXCLUDED.session_ended_at,
|
||||
requests = EXCLUDED.requests
|
||||
WHERE
|
||||
workspace_app_stats.user_id = EXCLUDED.user_id
|
||||
AND workspace_app_stats.agent_id = EXCLUDED.agent_id
|
||||
AND workspace_app_stats.session_id = EXCLUDED.session_id
|
||||
-- Since stats are updated in place as time progresses, we only
|
||||
-- want to update this row if it's fresh.
|
||||
AND workspace_app_stats.session_ended_at <= EXCLUDED.session_ended_at
|
||||
AND workspace_app_stats.requests <= EXCLUDED.requests
|
||||
`
|
||||
|
||||
type InsertWorkspaceAppStatsParams struct {
|
||||
UserID []uuid.UUID `db:"user_id" json:"user_id"`
|
||||
WorkspaceID []uuid.UUID `db:"workspace_id" json:"workspace_id"`
|
||||
AgentID []uuid.UUID `db:"agent_id" json:"agent_id"`
|
||||
AccessMethod []string `db:"access_method" json:"access_method"`
|
||||
SlugOrPort []string `db:"slug_or_port" json:"slug_or_port"`
|
||||
SessionID []uuid.UUID `db:"session_id" json:"session_id"`
|
||||
SessionStartedAt []time.Time `db:"session_started_at" json:"session_started_at"`
|
||||
SessionEndedAt []time.Time `db:"session_ended_at" json:"session_ended_at"`
|
||||
Requests []int32 `db:"requests" json:"requests"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertWorkspaceAppStats(ctx context.Context, arg InsertWorkspaceAppStatsParams) error {
|
||||
_, err := q.db.ExecContext(ctx, insertWorkspaceAppStats,
|
||||
pq.Array(arg.UserID),
|
||||
pq.Array(arg.WorkspaceID),
|
||||
pq.Array(arg.AgentID),
|
||||
pq.Array(arg.AccessMethod),
|
||||
pq.Array(arg.SlugOrPort),
|
||||
pq.Array(arg.SessionID),
|
||||
pq.Array(arg.SessionStartedAt),
|
||||
pq.Array(arg.SessionEndedAt),
|
||||
pq.Array(arg.Requests),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const getWorkspaceBuildParameters = `-- name: GetWorkspaceBuildParameters :many
|
||||
SELECT
|
||||
workspace_build_id, name, value
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
-- name: InsertWorkspaceAppStats :exec
|
||||
INSERT INTO
|
||||
workspace_app_stats (
|
||||
user_id,
|
||||
workspace_id,
|
||||
agent_id,
|
||||
access_method,
|
||||
slug_or_port,
|
||||
session_id,
|
||||
session_started_at,
|
||||
session_ended_at,
|
||||
requests
|
||||
)
|
||||
SELECT
|
||||
unnest(@user_id::uuid[]) AS user_id,
|
||||
unnest(@workspace_id::uuid[]) AS workspace_id,
|
||||
unnest(@agent_id::uuid[]) AS agent_id,
|
||||
unnest(@access_method::text[]) AS access_method,
|
||||
unnest(@slug_or_port::text[]) AS slug_or_port,
|
||||
unnest(@session_id::uuid[]) AS session_id,
|
||||
unnest(@session_started_at::timestamptz[]) AS session_started_at,
|
||||
unnest(@session_ended_at::timestamptz[]) AS session_ended_at,
|
||||
unnest(@requests::int[]) AS requests
|
||||
ON CONFLICT
|
||||
(user_id, agent_id, session_id)
|
||||
DO
|
||||
UPDATE SET
|
||||
session_ended_at = EXCLUDED.session_ended_at,
|
||||
requests = EXCLUDED.requests
|
||||
WHERE
|
||||
workspace_app_stats.user_id = EXCLUDED.user_id
|
||||
AND workspace_app_stats.agent_id = EXCLUDED.agent_id
|
||||
AND workspace_app_stats.session_id = EXCLUDED.session_id
|
||||
-- Since stats are updated in place as time progresses, we only
|
||||
-- want to update this row if it's fresh.
|
||||
AND workspace_app_stats.session_ended_at <= EXCLUDED.session_ended_at
|
||||
AND workspace_app_stats.requests <= EXCLUDED.requests;
|
||||
@@ -18,6 +18,7 @@ const (
|
||||
UniqueTemplateVersionParametersTemplateVersionIDNameKey UniqueConstraint = "template_version_parameters_template_version_id_name_key" // ALTER TABLE ONLY template_version_parameters ADD CONSTRAINT template_version_parameters_template_version_id_name_key UNIQUE (template_version_id, name);
|
||||
UniqueTemplateVersionVariablesTemplateVersionIDNameKey UniqueConstraint = "template_version_variables_template_version_id_name_key" // ALTER TABLE ONLY template_version_variables ADD CONSTRAINT template_version_variables_template_version_id_name_key UNIQUE (template_version_id, name);
|
||||
UniqueTemplateVersionsTemplateIDNameKey UniqueConstraint = "template_versions_template_id_name_key" // ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_template_id_name_key UNIQUE (template_id, name);
|
||||
UniqueWorkspaceAppStatsUserIDAgentIDSessionIDKey UniqueConstraint = "workspace_app_stats_user_id_agent_id_session_id_key" // ALTER TABLE ONLY workspace_app_stats ADD CONSTRAINT workspace_app_stats_user_id_agent_id_session_id_key UNIQUE (user_id, agent_id, session_id);
|
||||
UniqueWorkspaceAppsAgentIDSlugIndex UniqueConstraint = "workspace_apps_agent_id_slug_idx" // ALTER TABLE ONLY workspace_apps ADD CONSTRAINT workspace_apps_agent_id_slug_idx UNIQUE (agent_id, slug);
|
||||
UniqueWorkspaceBuildParametersWorkspaceBuildIDNameKey UniqueConstraint = "workspace_build_parameters_workspace_build_id_name_key" // ALTER TABLE ONLY workspace_build_parameters ADD CONSTRAINT workspace_build_parameters_workspace_build_id_name_key UNIQUE (workspace_build_id, name);
|
||||
UniqueWorkspaceBuildsJobIDKey UniqueConstraint = "workspace_builds_job_id_key" // ALTER TABLE ONLY workspace_builds ADD CONSTRAINT workspace_builds_job_id_key UNIQUE (job_id);
|
||||
|
||||
Reference in New Issue
Block a user