From 6c73f9d66a598fa0e6c30e27453a4aa07d56b545 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Tue, 30 May 2023 12:31:30 +0100 Subject: [PATCH 01/10] feat: add prometheus metrics to database.Store --- cli/server.go | 6 +- coderd/database/dbmetrics/dbmetrics.go | 1550 ++++++++++++++++++++++++ 2 files changed, 1554 insertions(+), 2 deletions(-) create mode 100644 coderd/database/dbmetrics/dbmetrics.go diff --git a/cli/server.go b/cli/server.go index b070c5819d172..84fd8cdb0ebab 100644 --- a/cli/server.go +++ b/cli/server.go @@ -65,6 +65,7 @@ import ( "github.com/coder/coder/coderd/autobuild/executor" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/database/dbfake" + "github.com/coder/coder/coderd/database/dbmetrics" "github.com/coder/coder/coderd/database/dbpurge" "github.com/coder/coder/coderd/database/migrations" "github.com/coder/coder/coderd/devtunnel" @@ -586,7 +587,8 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. } if cfg.InMemoryDatabase { - options.Database = dbfake.New() + // This is only used for testing. + options.Database = dbmetrics.New(dbfake.New(), options.PrometheusRegistry) options.Pubsub = database.NewPubsubInMemory() } else { sqlDB, err := connectToPostgres(ctx, logger, sqlDriver, cfg.PostgresURL.String()) @@ -597,7 +599,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. _ = sqlDB.Close() }() - options.Database = database.New(sqlDB) + options.Database = dbmetrics.New(database.New(sqlDB), options.PrometheusRegistry) options.Pubsub, err = database.NewPubsub(ctx, sqlDB, cfg.PostgresURL.String()) if err != nil { return xerrors.Errorf("create pubsub: %w", err) diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go new file mode 100644 index 0000000000000..0c588c21b2317 --- /dev/null +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -0,0 +1,1550 @@ +package dbmetrics + +import ( + "context" + "database/sql" + "time" + + "github.com/google/uuid" + "github.com/prometheus/client_golang/prometheus" + + "github.com/coder/coder/coderd/database" + "github.com/coder/coder/coderd/rbac" +) + +// New returns a database.Store that registers metrics for all queries to reg. +func New(s database.Store, reg prometheus.Registerer) database.Store { + // Don't double-wrap. + if _, ok := s.(*metricsStore); ok { + return s + } + queryLatencies := prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "coderd", + Subsystem: "db", + Name: "query_latencies_seconds", + Help: "Latency distribution of queries in seconds.", + Buckets: prometheus.DefBuckets, + }, []string{"query"}) + reg.MustRegister(queryLatencies) + return &metricsStore{ + s: s, + queryLatencies: queryLatencies, + } +} + +var _ database.Store = (*metricsStore)(nil) + +type metricsStore struct { + s database.Store + queryLatencies *prometheus.HistogramVec +} + +func (m metricsStore) Ping(ctx context.Context) (time.Duration, error) { + start := time.Now() + duration, err := m.s.Ping(ctx) + m.queryLatencies.WithLabelValues("Ping").Observe(time.Since(start).Seconds()) + return duration, err +} + +func (m metricsStore) InTx(f func(database.Store) error, options *sql.TxOptions) error { + // No point in measuring this, as it's just a wrapper around the underlying store's InTx method. + return m.s.InTx(f, options) +} + +func (m metricsStore) AcquireLock(ctx context.Context, pgAdvisoryXactLock int64) error { + start := time.Now() + err := m.s.AcquireLock(ctx, pgAdvisoryXactLock) + m.queryLatencies.WithLabelValues("AcquireLock").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) AcquireProvisionerJob(ctx context.Context, arg database.AcquireProvisionerJobParams) (database.ProvisionerJob, error) { + start := time.Now() + provisionerJob, err := m.s.AcquireProvisionerJob(ctx, arg) + m.queryLatencies.WithLabelValues("AcquireProvisionerJob").Observe(time.Since(start).Seconds()) + return provisionerJob, err +} + +func (m metricsStore) DeleteAPIKeyByID(ctx context.Context, id string) error { + start := time.Now() + err := m.s.DeleteAPIKeyByID(ctx, id) + m.queryLatencies.WithLabelValues("DeleteAPIKeyByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) DeleteAPIKeysByUserID(ctx context.Context, userID uuid.UUID) error { + start := time.Now() + err := m.s.DeleteAPIKeysByUserID(ctx, userID) + m.queryLatencies.WithLabelValues("DeleteAPIKeysByUserID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) DeleteApplicationConnectAPIKeysByUserID(ctx context.Context, userID uuid.UUID) error { + start := time.Now() + err := m.s.DeleteApplicationConnectAPIKeysByUserID(ctx, userID) + m.queryLatencies.WithLabelValues("DeleteApplicationConnectAPIKeysByUserID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) DeleteGitSSHKey(ctx context.Context, userID uuid.UUID) error { + start := time.Now() + err := m.s.DeleteGitSSHKey(ctx, userID) + m.queryLatencies.WithLabelValues("DeleteGitSSHKey").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) DeleteGroupByID(ctx context.Context, id uuid.UUID) error { + start := time.Now() + err := m.s.DeleteGroupByID(ctx, id) + m.queryLatencies.WithLabelValues("DeleteGroupByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) DeleteGroupMemberFromGroup(ctx context.Context, arg database.DeleteGroupMemberFromGroupParams) error { + start := time.Now() + err := m.s.DeleteGroupMemberFromGroup(ctx, arg) + m.queryLatencies.WithLabelValues("DeleteGroupMemberFromGroup").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) DeleteGroupMembersByOrgAndUser(ctx context.Context, arg database.DeleteGroupMembersByOrgAndUserParams) error { + start := time.Now() + err := m.s.DeleteGroupMembersByOrgAndUser(ctx, arg) + m.queryLatencies.WithLabelValues("DeleteGroupMembersByOrgAndUser").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) DeleteLicense(ctx context.Context, id int32) (int32, error) { + start := time.Now() + licenseID, err := m.s.DeleteLicense(ctx, id) + m.queryLatencies.WithLabelValues("DeleteLicense").Observe(time.Since(start).Seconds()) + return licenseID, err +} + +func (m metricsStore) DeleteOldWorkspaceAgentStartupLogs(ctx context.Context) error { + start := time.Now() + err := m.s.DeleteOldWorkspaceAgentStartupLogs(ctx) + m.queryLatencies.WithLabelValues("DeleteOldWorkspaceAgentStartupLogs").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) DeleteOldWorkspaceAgentStats(ctx context.Context) error { + start := time.Now() + err := m.s.DeleteOldWorkspaceAgentStats(ctx) + m.queryLatencies.WithLabelValues("DeleteOldWorkspaceAgentStats").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) DeleteParameterValueByID(ctx context.Context, id uuid.UUID) error { + start := time.Now() + err := m.s.DeleteParameterValueByID(ctx, id) + m.queryLatencies.WithLabelValues("DeleteParameterValueByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) DeleteReplicasUpdatedBefore(ctx context.Context, updatedAt time.Time) error { + start := time.Now() + err := m.s.DeleteReplicasUpdatedBefore(ctx, updatedAt) + m.queryLatencies.WithLabelValues("DeleteReplicasUpdatedBefore").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) GetAPIKeyByID(ctx context.Context, id string) (database.APIKey, error) { + start := time.Now() + apiKey, err := m.s.GetAPIKeyByID(ctx, id) + m.queryLatencies.WithLabelValues("GetAPIKeyByID").Observe(time.Since(start).Seconds()) + return apiKey, err +} + +func (m metricsStore) GetAPIKeyByName(ctx context.Context, arg database.GetAPIKeyByNameParams) (database.APIKey, error) { + start := time.Now() + apiKey, err := m.s.GetAPIKeyByName(ctx, arg) + m.queryLatencies.WithLabelValues("GetAPIKeyByName").Observe(time.Since(start).Seconds()) + return apiKey, err +} + +func (m metricsStore) GetAPIKeysByLoginType(ctx context.Context, loginType database.LoginType) ([]database.APIKey, error) { + start := time.Now() + apiKeys, err := m.s.GetAPIKeysByLoginType(ctx, loginType) + m.queryLatencies.WithLabelValues("GetAPIKeysByLoginType").Observe(time.Since(start).Seconds()) + return apiKeys, err +} + +func (m metricsStore) GetAPIKeysByUserID(ctx context.Context, arg database.GetAPIKeysByUserIDParams) ([]database.APIKey, error) { + start := time.Now() + apiKeys, err := m.s.GetAPIKeysByUserID(ctx, arg) + m.queryLatencies.WithLabelValues("GetAPIKeysByUserID").Observe(time.Since(start).Seconds()) + return apiKeys, err +} + +func (m metricsStore) GetAPIKeysLastUsedAfter(ctx context.Context, lastUsed time.Time) ([]database.APIKey, error) { + start := time.Now() + apiKeys, err := m.s.GetAPIKeysLastUsedAfter(ctx, lastUsed) + m.queryLatencies.WithLabelValues("GetAPIKeysLastUsedAfter").Observe(time.Since(start).Seconds()) + return apiKeys, err +} + +func (m metricsStore) GetActiveUserCount(ctx context.Context) (int64, error) { + start := time.Now() + count, err := m.s.GetActiveUserCount(ctx) + m.queryLatencies.WithLabelValues("GetActiveUserCount").Observe(time.Since(start).Seconds()) + return count, err +} + +func (m metricsStore) GetAppSecurityKey(ctx context.Context) (string, error) { + start := time.Now() + key, err := m.s.GetAppSecurityKey(ctx) + m.queryLatencies.WithLabelValues("GetAppSecurityKey").Observe(time.Since(start).Seconds()) + return key, err +} + +func (m metricsStore) GetAuditLogsOffset(ctx context.Context, arg database.GetAuditLogsOffsetParams) ([]database.GetAuditLogsOffsetRow, error) { + start := time.Now() + rows, err := m.s.GetAuditLogsOffset(ctx, arg) + m.queryLatencies.WithLabelValues("GetAuditLogsOffset").Observe(time.Since(start).Seconds()) + return rows, err +} + +func (m metricsStore) GetAuthorizationUserRoles(ctx context.Context, userID uuid.UUID) (database.GetAuthorizationUserRolesRow, error) { + start := time.Now() + row, err := m.s.GetAuthorizationUserRoles(ctx, userID) + m.queryLatencies.WithLabelValues("GetAuthorizationUserRoles").Observe(time.Since(start).Seconds()) + return row, err +} + +func (m metricsStore) GetDERPMeshKey(ctx context.Context) (string, error) { + start := time.Now() + key, err := m.s.GetDERPMeshKey(ctx) + m.queryLatencies.WithLabelValues("GetDERPMeshKey").Observe(time.Since(start).Seconds()) + return key, err +} + +func (m metricsStore) GetDeploymentDAUs(ctx context.Context) ([]database.GetDeploymentDAUsRow, error) { + start := time.Now() + rows, err := m.s.GetDeploymentDAUs(ctx) + m.queryLatencies.WithLabelValues("GetDeploymentDAUs").Observe(time.Since(start).Seconds()) + return rows, err +} + +func (m metricsStore) GetDeploymentID(ctx context.Context) (string, error) { + start := time.Now() + id, err := m.s.GetDeploymentID(ctx) + m.queryLatencies.WithLabelValues("GetDeploymentID").Observe(time.Since(start).Seconds()) + return id, err +} + +func (m metricsStore) GetDeploymentWorkspaceAgentStats(ctx context.Context, createdAt time.Time) (database.GetDeploymentWorkspaceAgentStatsRow, error) { + start := time.Now() + row, err := m.s.GetDeploymentWorkspaceAgentStats(ctx, createdAt) + m.queryLatencies.WithLabelValues("GetDeploymentWorkspaceAgentStats").Observe(time.Since(start).Seconds()) + return row, err +} + +func (m metricsStore) GetDeploymentWorkspaceStats(ctx context.Context) (database.GetDeploymentWorkspaceStatsRow, error) { + start := time.Now() + row, err := m.s.GetDeploymentWorkspaceStats(ctx) + m.queryLatencies.WithLabelValues("GetDeploymentWorkspaceStats").Observe(time.Since(start).Seconds()) + return row, err +} + +func (m metricsStore) GetFileByHashAndCreator(ctx context.Context, arg database.GetFileByHashAndCreatorParams) (database.File, error) { + start := time.Now() + file, err := m.s.GetFileByHashAndCreator(ctx, arg) + m.queryLatencies.WithLabelValues("GetFileByHashAndCreator").Observe(time.Since(start).Seconds()) + return file, err +} + +func (m metricsStore) GetFileByID(ctx context.Context, id uuid.UUID) (database.File, error) { + start := time.Now() + file, err := m.s.GetFileByID(ctx, id) + m.queryLatencies.WithLabelValues("GetFileByID").Observe(time.Since(start).Seconds()) + return file, err +} + +func (m metricsStore) GetFileTemplates(ctx context.Context, fileID uuid.UUID) ([]database.GetFileTemplatesRow, error) { + start := time.Now() + rows, err := m.s.GetFileTemplates(ctx, fileID) + m.queryLatencies.WithLabelValues("GetFileTemplates").Observe(time.Since(start).Seconds()) + return rows, err +} + +func (m metricsStore) GetFilteredUserCount(ctx context.Context, arg database.GetFilteredUserCountParams) (int64, error) { + start := time.Now() + count, err := m.s.GetFilteredUserCount(ctx, arg) + m.queryLatencies.WithLabelValues("GetFilteredUserCount").Observe(time.Since(start).Seconds()) + return count, err +} + +func (m metricsStore) GetGitAuthLink(ctx context.Context, arg database.GetGitAuthLinkParams) (database.GitAuthLink, error) { + start := time.Now() + link, err := m.s.GetGitAuthLink(ctx, arg) + m.queryLatencies.WithLabelValues("GetGitAuthLink").Observe(time.Since(start).Seconds()) + return link, err +} + +func (m metricsStore) GetGitSSHKey(ctx context.Context, userID uuid.UUID) (database.GitSSHKey, error) { + start := time.Now() + key, err := m.s.GetGitSSHKey(ctx, userID) + m.queryLatencies.WithLabelValues("GetGitSSHKey").Observe(time.Since(start).Seconds()) + return key, err +} + +func (m metricsStore) GetGroupByID(ctx context.Context, id uuid.UUID) (database.Group, error) { + start := time.Now() + group, err := m.s.GetGroupByID(ctx, id) + m.queryLatencies.WithLabelValues("GetGroupByID").Observe(time.Since(start).Seconds()) + return group, err +} + +func (m metricsStore) GetGroupByOrgAndName(ctx context.Context, arg database.GetGroupByOrgAndNameParams) (database.Group, error) { + start := time.Now() + group, err := m.s.GetGroupByOrgAndName(ctx, arg) + m.queryLatencies.WithLabelValues("GetGroupByOrgAndName").Observe(time.Since(start).Seconds()) + return group, err +} + +func (m metricsStore) GetGroupMembers(ctx context.Context, groupID uuid.UUID) ([]database.User, error) { + start := time.Now() + users, err := m.s.GetGroupMembers(ctx, groupID) + m.queryLatencies.WithLabelValues("GetGroupMembers").Observe(time.Since(start).Seconds()) + return users, err +} + +func (m metricsStore) GetGroupsByOrganizationID(ctx context.Context, organizationID uuid.UUID) ([]database.Group, error) { + start := time.Now() + groups, err := m.s.GetGroupsByOrganizationID(ctx, organizationID) + m.queryLatencies.WithLabelValues("GetGroupsByOrganizationID").Observe(time.Since(start).Seconds()) + return groups, err +} + +func (m metricsStore) GetLastUpdateCheck(ctx context.Context) (string, error) { + start := time.Now() + version, err := m.s.GetLastUpdateCheck(ctx) + m.queryLatencies.WithLabelValues("GetLastUpdateCheck").Observe(time.Since(start).Seconds()) + return version, err +} + +func (m metricsStore) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (database.WorkspaceBuild, error) { + start := time.Now() + build, err := m.s.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspaceID) + m.queryLatencies.WithLabelValues("GetLatestWorkspaceBuildByWorkspaceID").Observe(time.Since(start).Seconds()) + return build, err +} + +func (m metricsStore) GetLatestWorkspaceBuilds(ctx context.Context) ([]database.WorkspaceBuild, error) { + start := time.Now() + builds, err := m.s.GetLatestWorkspaceBuilds(ctx) + m.queryLatencies.WithLabelValues("GetLatestWorkspaceBuilds").Observe(time.Since(start).Seconds()) + return builds, err +} + +func (m metricsStore) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, ids []uuid.UUID) ([]database.WorkspaceBuild, error) { + start := time.Now() + builds, err := m.s.GetLatestWorkspaceBuildsByWorkspaceIDs(ctx, ids) + m.queryLatencies.WithLabelValues("GetLatestWorkspaceBuildsByWorkspaceIDs").Observe(time.Since(start).Seconds()) + return builds, err +} + +func (m metricsStore) GetLicenseByID(ctx context.Context, id int32) (database.License, error) { + start := time.Now() + license, err := m.s.GetLicenseByID(ctx, id) + m.queryLatencies.WithLabelValues("GetLicenseByID").Observe(time.Since(start).Seconds()) + return license, err +} + +func (m metricsStore) GetLicenses(ctx context.Context) ([]database.License, error) { + start := time.Now() + licenses, err := m.s.GetLicenses(ctx) + m.queryLatencies.WithLabelValues("GetLicenses").Observe(time.Since(start).Seconds()) + return licenses, err +} + +func (m metricsStore) GetLogoURL(ctx context.Context) (string, error) { + start := time.Now() + url, err := m.s.GetLogoURL(ctx) + m.queryLatencies.WithLabelValues("GetLogoURL").Observe(time.Since(start).Seconds()) + return url, err +} + +func (m metricsStore) GetOrganizationByID(ctx context.Context, id uuid.UUID) (database.Organization, error) { + start := time.Now() + organization, err := m.s.GetOrganizationByID(ctx, id) + m.queryLatencies.WithLabelValues("GetOrganizationByID").Observe(time.Since(start).Seconds()) + return organization, err +} + +func (m metricsStore) GetOrganizationByName(ctx context.Context, name string) (database.Organization, error) { + start := time.Now() + organization, err := m.s.GetOrganizationByName(ctx, name) + m.queryLatencies.WithLabelValues("GetOrganizationByName").Observe(time.Since(start).Seconds()) + return organization, err +} + +func (m metricsStore) GetOrganizationIDsByMemberIDs(ctx context.Context, ids []uuid.UUID) ([]database.GetOrganizationIDsByMemberIDsRow, error) { + start := time.Now() + organizations, err := m.s.GetOrganizationIDsByMemberIDs(ctx, ids) + m.queryLatencies.WithLabelValues("GetOrganizationIDsByMemberIDs").Observe(time.Since(start).Seconds()) + return organizations, err +} + +func (m metricsStore) GetOrganizationMemberByUserID(ctx context.Context, arg database.GetOrganizationMemberByUserIDParams) (database.OrganizationMember, error) { + start := time.Now() + member, err := m.s.GetOrganizationMemberByUserID(ctx, arg) + m.queryLatencies.WithLabelValues("GetOrganizationMemberByUserID").Observe(time.Since(start).Seconds()) + return member, err +} + +func (m metricsStore) GetOrganizationMembershipsByUserID(ctx context.Context, userID uuid.UUID) ([]database.OrganizationMember, error) { + start := time.Now() + memberships, err := m.s.GetOrganizationMembershipsByUserID(ctx, userID) + m.queryLatencies.WithLabelValues("GetOrganizationMembershipsByUserID").Observe(time.Since(start).Seconds()) + return memberships, err +} + +func (m metricsStore) GetOrganizations(ctx context.Context) ([]database.Organization, error) { + start := time.Now() + organizations, err := m.s.GetOrganizations(ctx) + m.queryLatencies.WithLabelValues("GetOrganizations").Observe(time.Since(start).Seconds()) + return organizations, err +} + +func (m metricsStore) GetOrganizationsByUserID(ctx context.Context, userID uuid.UUID) ([]database.Organization, error) { + start := time.Now() + organizations, err := m.s.GetOrganizationsByUserID(ctx, userID) + m.queryLatencies.WithLabelValues("GetOrganizationsByUserID").Observe(time.Since(start).Seconds()) + return organizations, err +} + +func (m metricsStore) GetParameterSchemasByJobID(ctx context.Context, jobID uuid.UUID) ([]database.ParameterSchema, error) { + start := time.Now() + schemas, err := m.s.GetParameterSchemasByJobID(ctx, jobID) + m.queryLatencies.WithLabelValues("GetParameterSchemasByJobID").Observe(time.Since(start).Seconds()) + return schemas, err +} + +func (m metricsStore) GetParameterSchemasCreatedAfter(ctx context.Context, createdAt time.Time) ([]database.ParameterSchema, error) { + start := time.Now() + schemas, err := m.s.GetParameterSchemasCreatedAfter(ctx, createdAt) + m.queryLatencies.WithLabelValues("GetParameterSchemasCreatedAfter").Observe(time.Since(start).Seconds()) + return schemas, err +} + +func (m metricsStore) GetParameterValueByScopeAndName(ctx context.Context, arg database.GetParameterValueByScopeAndNameParams) (database.ParameterValue, error) { + start := time.Now() + value, err := m.s.GetParameterValueByScopeAndName(ctx, arg) + m.queryLatencies.WithLabelValues("GetParameterValueByScopeAndName").Observe(time.Since(start).Seconds()) + return value, err +} + +func (m metricsStore) GetPreviousTemplateVersion(ctx context.Context, arg database.GetPreviousTemplateVersionParams) (database.TemplateVersion, error) { + start := time.Now() + version, err := m.s.GetPreviousTemplateVersion(ctx, arg) + m.queryLatencies.WithLabelValues("GetPreviousTemplateVersion").Observe(time.Since(start).Seconds()) + return version, err +} + +func (m metricsStore) GetProvisionerDaemons(ctx context.Context) ([]database.ProvisionerDaemon, error) { + start := time.Now() + daemons, err := m.s.GetProvisionerDaemons(ctx) + m.queryLatencies.WithLabelValues("GetProvisionerDaemons").Observe(time.Since(start).Seconds()) + return daemons, err +} + +func (m metricsStore) GetProvisionerJobByID(ctx context.Context, id uuid.UUID) (database.ProvisionerJob, error) { + start := time.Now() + job, err := m.s.GetProvisionerJobByID(ctx, id) + m.queryLatencies.WithLabelValues("GetProvisionerJobByID").Observe(time.Since(start).Seconds()) + return job, err +} + +func (m metricsStore) GetProvisionerJobsByIDs(ctx context.Context, ids []uuid.UUID) ([]database.ProvisionerJob, error) { + start := time.Now() + jobs, err := m.s.GetProvisionerJobsByIDs(ctx, ids) + m.queryLatencies.WithLabelValues("GetProvisionerJobsByIDs").Observe(time.Since(start).Seconds()) + return jobs, err +} + +func (m metricsStore) GetProvisionerJobsCreatedAfter(ctx context.Context, createdAt time.Time) ([]database.ProvisionerJob, error) { + start := time.Now() + jobs, err := m.s.GetProvisionerJobsCreatedAfter(ctx, createdAt) + m.queryLatencies.WithLabelValues("GetProvisionerJobsCreatedAfter").Observe(time.Since(start).Seconds()) + return jobs, err +} + +func (m metricsStore) GetProvisionerLogsAfterID(ctx context.Context, arg database.GetProvisionerLogsAfterIDParams) ([]database.ProvisionerJobLog, error) { + start := time.Now() + logs, err := m.s.GetProvisionerLogsAfterID(ctx, arg) + m.queryLatencies.WithLabelValues("GetProvisionerLogsAfterID").Observe(time.Since(start).Seconds()) + return logs, err +} + +func (m metricsStore) GetQuotaAllowanceForUser(ctx context.Context, userID uuid.UUID) (int64, error) { + start := time.Now() + allowance, err := m.s.GetQuotaAllowanceForUser(ctx, userID) + m.queryLatencies.WithLabelValues("GetQuotaAllowanceForUser").Observe(time.Since(start).Seconds()) + return allowance, err +} + +func (m metricsStore) GetQuotaConsumedForUser(ctx context.Context, ownerID uuid.UUID) (int64, error) { + start := time.Now() + consumed, err := m.s.GetQuotaConsumedForUser(ctx, ownerID) + m.queryLatencies.WithLabelValues("GetQuotaConsumedForUser").Observe(time.Since(start).Seconds()) + return consumed, err +} + +func (m metricsStore) GetReplicasUpdatedAfter(ctx context.Context, updatedAt time.Time) ([]database.Replica, error) { + start := time.Now() + replicas, err := m.s.GetReplicasUpdatedAfter(ctx, updatedAt) + m.queryLatencies.WithLabelValues("GetReplicasUpdatedAfter").Observe(time.Since(start).Seconds()) + return replicas, err +} + +func (m metricsStore) GetServiceBanner(ctx context.Context) (string, error) { + start := time.Now() + banner, err := m.s.GetServiceBanner(ctx) + m.queryLatencies.WithLabelValues("GetServiceBanner").Observe(time.Since(start).Seconds()) + return banner, err +} + +func (m metricsStore) GetTemplateAverageBuildTime(ctx context.Context, arg database.GetTemplateAverageBuildTimeParams) (database.GetTemplateAverageBuildTimeRow, error) { + start := time.Now() + buildTime, err := m.s.GetTemplateAverageBuildTime(ctx, arg) + m.queryLatencies.WithLabelValues("GetTemplateAverageBuildTime").Observe(time.Since(start).Seconds()) + return buildTime, err +} + +func (m metricsStore) GetTemplateByID(ctx context.Context, id uuid.UUID) (database.Template, error) { + start := time.Now() + template, err := m.s.GetTemplateByID(ctx, id) + m.queryLatencies.WithLabelValues("GetTemplateByID").Observe(time.Since(start).Seconds()) + return template, err +} + +func (m metricsStore) GetTemplateByOrganizationAndName(ctx context.Context, arg database.GetTemplateByOrganizationAndNameParams) (database.Template, error) { + start := time.Now() + template, err := m.s.GetTemplateByOrganizationAndName(ctx, arg) + m.queryLatencies.WithLabelValues("GetTemplateByOrganizationAndName").Observe(time.Since(start).Seconds()) + return template, err +} + +func (m metricsStore) GetTemplateDAUs(ctx context.Context, templateID uuid.UUID) ([]database.GetTemplateDAUsRow, error) { + start := time.Now() + daus, err := m.s.GetTemplateDAUs(ctx, templateID) + m.queryLatencies.WithLabelValues("GetTemplateDAUs").Observe(time.Since(start).Seconds()) + return daus, err +} + +func (m metricsStore) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) (database.TemplateVersion, error) { + start := time.Now() + version, err := m.s.GetTemplateVersionByID(ctx, id) + m.queryLatencies.WithLabelValues("GetTemplateVersionByID").Observe(time.Since(start).Seconds()) + return version, err +} + +func (m metricsStore) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.UUID) (database.TemplateVersion, error) { + start := time.Now() + version, err := m.s.GetTemplateVersionByJobID(ctx, jobID) + m.queryLatencies.WithLabelValues("GetTemplateVersionByJobID").Observe(time.Since(start).Seconds()) + return version, err +} + +func (m metricsStore) GetTemplateVersionByTemplateIDAndName(ctx context.Context, arg database.GetTemplateVersionByTemplateIDAndNameParams) (database.TemplateVersion, error) { + start := time.Now() + version, err := m.s.GetTemplateVersionByTemplateIDAndName(ctx, arg) + m.queryLatencies.WithLabelValues("GetTemplateVersionByTemplateIDAndName").Observe(time.Since(start).Seconds()) + return version, err +} + +func (m metricsStore) GetTemplateVersionParameters(ctx context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionParameter, error) { + start := time.Now() + parameters, err := m.s.GetTemplateVersionParameters(ctx, templateVersionID) + m.queryLatencies.WithLabelValues("GetTemplateVersionParameters").Observe(time.Since(start).Seconds()) + return parameters, err +} + +func (m metricsStore) GetTemplateVersionVariables(ctx context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionVariable, error) { + start := time.Now() + variables, err := m.s.GetTemplateVersionVariables(ctx, templateVersionID) + m.queryLatencies.WithLabelValues("GetTemplateVersionVariables").Observe(time.Since(start).Seconds()) + return variables, err +} + +func (m metricsStore) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UUID) ([]database.TemplateVersion, error) { + start := time.Now() + versions, err := m.s.GetTemplateVersionsByIDs(ctx, ids) + m.queryLatencies.WithLabelValues("GetTemplateVersionsByIDs").Observe(time.Since(start).Seconds()) + return versions, err +} + +func (m metricsStore) GetTemplateVersionsByTemplateID(ctx context.Context, arg database.GetTemplateVersionsByTemplateIDParams) ([]database.TemplateVersion, error) { + start := time.Now() + versions, err := m.s.GetTemplateVersionsByTemplateID(ctx, arg) + m.queryLatencies.WithLabelValues("GetTemplateVersionsByTemplateID").Observe(time.Since(start).Seconds()) + return versions, err +} + +func (m metricsStore) GetTemplateVersionsCreatedAfter(ctx context.Context, createdAt time.Time) ([]database.TemplateVersion, error) { + start := time.Now() + versions, err := m.s.GetTemplateVersionsCreatedAfter(ctx, createdAt) + m.queryLatencies.WithLabelValues("GetTemplateVersionsCreatedAfter").Observe(time.Since(start).Seconds()) + return versions, err +} + +func (m metricsStore) GetTemplates(ctx context.Context) ([]database.Template, error) { + start := time.Now() + templates, err := m.s.GetTemplates(ctx) + m.queryLatencies.WithLabelValues("GetTemplates").Observe(time.Since(start).Seconds()) + return templates, err +} + +func (m metricsStore) GetTemplatesWithFilter(ctx context.Context, arg database.GetTemplatesWithFilterParams) ([]database.Template, error) { + start := time.Now() + templates, err := m.s.GetTemplatesWithFilter(ctx, arg) + m.queryLatencies.WithLabelValues("GetTemplatesWithFilter").Observe(time.Since(start).Seconds()) + return templates, err +} + +func (m metricsStore) GetUnexpiredLicenses(ctx context.Context) ([]database.License, error) { + start := time.Now() + licenses, err := m.s.GetUnexpiredLicenses(ctx) + m.queryLatencies.WithLabelValues("GetUnexpiredLicenses").Observe(time.Since(start).Seconds()) + return licenses, err +} + +func (m metricsStore) GetUserByEmailOrUsername(ctx context.Context, arg database.GetUserByEmailOrUsernameParams) (database.User, error) { + start := time.Now() + user, err := m.s.GetUserByEmailOrUsername(ctx, arg) + m.queryLatencies.WithLabelValues("GetUserByEmailOrUsername").Observe(time.Since(start).Seconds()) + return user, err +} + +func (m metricsStore) GetUserByID(ctx context.Context, id uuid.UUID) (database.User, error) { + start := time.Now() + user, err := m.s.GetUserByID(ctx, id) + m.queryLatencies.WithLabelValues("GetUserByID").Observe(time.Since(start).Seconds()) + return user, err +} + +func (m metricsStore) GetUserCount(ctx context.Context) (int64, error) { + start := time.Now() + count, err := m.s.GetUserCount(ctx) + m.queryLatencies.WithLabelValues("GetUserCount").Observe(time.Since(start).Seconds()) + return count, err +} + +func (m metricsStore) GetUserLinkByLinkedID(ctx context.Context, linkedID string) (database.UserLink, error) { + start := time.Now() + link, err := m.s.GetUserLinkByLinkedID(ctx, linkedID) + m.queryLatencies.WithLabelValues("GetUserLinkByLinkedID").Observe(time.Since(start).Seconds()) + return link, err +} + +func (m metricsStore) GetUserLinkByUserIDLoginType(ctx context.Context, arg database.GetUserLinkByUserIDLoginTypeParams) (database.UserLink, error) { + start := time.Now() + link, err := m.s.GetUserLinkByUserIDLoginType(ctx, arg) + m.queryLatencies.WithLabelValues("GetUserLinkByUserIDLoginType").Observe(time.Since(start).Seconds()) + return link, err +} + +func (m metricsStore) GetUsers(ctx context.Context, arg database.GetUsersParams) ([]database.GetUsersRow, error) { + start := time.Now() + users, err := m.s.GetUsers(ctx, arg) + m.queryLatencies.WithLabelValues("GetUsers").Observe(time.Since(start).Seconds()) + return users, err +} + +func (m metricsStore) GetUsersByIDs(ctx context.Context, ids []uuid.UUID) ([]database.User, error) { + start := time.Now() + users, err := m.s.GetUsersByIDs(ctx, ids) + m.queryLatencies.WithLabelValues("GetUsersByIDs").Observe(time.Since(start).Seconds()) + return users, err +} + +func (m metricsStore) GetWorkspaceAgentByAuthToken(ctx context.Context, authToken uuid.UUID) (database.WorkspaceAgent, error) { + start := time.Now() + agent, err := m.s.GetWorkspaceAgentByAuthToken(ctx, authToken) + m.queryLatencies.WithLabelValues("GetWorkspaceAgentByAuthToken").Observe(time.Since(start).Seconds()) + return agent, err +} + +func (m metricsStore) GetWorkspaceAgentByID(ctx context.Context, id uuid.UUID) (database.WorkspaceAgent, error) { + start := time.Now() + agent, err := m.s.GetWorkspaceAgentByID(ctx, id) + m.queryLatencies.WithLabelValues("GetWorkspaceAgentByID").Observe(time.Since(start).Seconds()) + return agent, err +} + +func (m metricsStore) GetWorkspaceAgentByInstanceID(ctx context.Context, authInstanceID string) (database.WorkspaceAgent, error) { + start := time.Now() + agent, err := m.s.GetWorkspaceAgentByInstanceID(ctx, authInstanceID) + m.queryLatencies.WithLabelValues("GetWorkspaceAgentByInstanceID").Observe(time.Since(start).Seconds()) + return agent, err +} + +func (m metricsStore) GetWorkspaceAgentMetadata(ctx context.Context, workspaceAgentID uuid.UUID) ([]database.WorkspaceAgentMetadatum, error) { + start := time.Now() + metadata, err := m.s.GetWorkspaceAgentMetadata(ctx, workspaceAgentID) + m.queryLatencies.WithLabelValues("GetWorkspaceAgentMetadata").Observe(time.Since(start).Seconds()) + return metadata, err +} + +func (m metricsStore) GetWorkspaceAgentStartupLogsAfter(ctx context.Context, arg database.GetWorkspaceAgentStartupLogsAfterParams) ([]database.WorkspaceAgentStartupLog, error) { + start := time.Now() + logs, err := m.s.GetWorkspaceAgentStartupLogsAfter(ctx, arg) + m.queryLatencies.WithLabelValues("GetWorkspaceAgentStartupLogsAfter").Observe(time.Since(start).Seconds()) + return logs, err +} + +func (m metricsStore) GetWorkspaceAgentStats(ctx context.Context, createdAt time.Time) ([]database.GetWorkspaceAgentStatsRow, error) { + start := time.Now() + stats, err := m.s.GetWorkspaceAgentStats(ctx, createdAt) + m.queryLatencies.WithLabelValues("GetWorkspaceAgentStats").Observe(time.Since(start).Seconds()) + return stats, err +} + +func (m metricsStore) GetWorkspaceAgentStatsAndLabels(ctx context.Context, createdAt time.Time) ([]database.GetWorkspaceAgentStatsAndLabelsRow, error) { + start := time.Now() + stats, err := m.s.GetWorkspaceAgentStatsAndLabels(ctx, createdAt) + m.queryLatencies.WithLabelValues("GetWorkspaceAgentStatsAndLabels").Observe(time.Since(start).Seconds()) + return stats, err +} + +func (m metricsStore) GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids []uuid.UUID) ([]database.WorkspaceAgent, error) { + start := time.Now() + agents, err := m.s.GetWorkspaceAgentsByResourceIDs(ctx, ids) + m.queryLatencies.WithLabelValues("GetWorkspaceAgentsByResourceIDs").Observe(time.Since(start).Seconds()) + return agents, err +} + +func (m metricsStore) GetWorkspaceAgentsCreatedAfter(ctx context.Context, createdAt time.Time) ([]database.WorkspaceAgent, error) { + start := time.Now() + agents, err := m.s.GetWorkspaceAgentsCreatedAfter(ctx, createdAt) + m.queryLatencies.WithLabelValues("GetWorkspaceAgentsCreatedAfter").Observe(time.Since(start).Seconds()) + return agents, err +} + +func (m metricsStore) GetWorkspaceAgentsInLatestBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) ([]database.WorkspaceAgent, error) { + start := time.Now() + agents, err := m.s.GetWorkspaceAgentsInLatestBuildByWorkspaceID(ctx, workspaceID) + m.queryLatencies.WithLabelValues("GetWorkspaceAgentsInLatestBuildByWorkspaceID").Observe(time.Since(start).Seconds()) + return agents, err +} + +func (m metricsStore) GetWorkspaceAppByAgentIDAndSlug(ctx context.Context, arg database.GetWorkspaceAppByAgentIDAndSlugParams) (database.WorkspaceApp, error) { + start := time.Now() + app, err := m.s.GetWorkspaceAppByAgentIDAndSlug(ctx, arg) + m.queryLatencies.WithLabelValues("GetWorkspaceAppByAgentIDAndSlug").Observe(time.Since(start).Seconds()) + return app, err +} + +func (m metricsStore) GetWorkspaceAppsByAgentID(ctx context.Context, agentID uuid.UUID) ([]database.WorkspaceApp, error) { + start := time.Now() + apps, err := m.s.GetWorkspaceAppsByAgentID(ctx, agentID) + m.queryLatencies.WithLabelValues("GetWorkspaceAppsByAgentID").Observe(time.Since(start).Seconds()) + return apps, err +} + +func (m metricsStore) GetWorkspaceAppsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]database.WorkspaceApp, error) { + start := time.Now() + apps, err := m.s.GetWorkspaceAppsByAgentIDs(ctx, ids) + m.queryLatencies.WithLabelValues("GetWorkspaceAppsByAgentIDs").Observe(time.Since(start).Seconds()) + return apps, err +} + +func (m metricsStore) GetWorkspaceAppsCreatedAfter(ctx context.Context, createdAt time.Time) ([]database.WorkspaceApp, error) { + start := time.Now() + apps, err := m.s.GetWorkspaceAppsCreatedAfter(ctx, createdAt) + m.queryLatencies.WithLabelValues("GetWorkspaceAppsCreatedAfter").Observe(time.Since(start).Seconds()) + return apps, err +} + +func (m metricsStore) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (database.WorkspaceBuild, error) { + start := time.Now() + build, err := m.s.GetWorkspaceBuildByID(ctx, id) + m.queryLatencies.WithLabelValues("GetWorkspaceBuildByID").Observe(time.Since(start).Seconds()) + return build, err +} + +func (m metricsStore) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (database.WorkspaceBuild, error) { + start := time.Now() + build, err := m.s.GetWorkspaceBuildByJobID(ctx, jobID) + m.queryLatencies.WithLabelValues("GetWorkspaceBuildByJobID").Observe(time.Since(start).Seconds()) + return build, err +} + +func (m metricsStore) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(ctx context.Context, arg database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams) (database.WorkspaceBuild, error) { + start := time.Now() + build, err := m.s.GetWorkspaceBuildByWorkspaceIDAndBuildNumber(ctx, arg) + m.queryLatencies.WithLabelValues("GetWorkspaceBuildByWorkspaceIDAndBuildNumber").Observe(time.Since(start).Seconds()) + return build, err +} + +func (m metricsStore) GetWorkspaceBuildParameters(ctx context.Context, workspaceBuildID uuid.UUID) ([]database.WorkspaceBuildParameter, error) { + start := time.Now() + params, err := m.s.GetWorkspaceBuildParameters(ctx, workspaceBuildID) + m.queryLatencies.WithLabelValues("GetWorkspaceBuildParameters").Observe(time.Since(start).Seconds()) + return params, err +} + +func (m metricsStore) GetWorkspaceBuildsByWorkspaceID(ctx context.Context, arg database.GetWorkspaceBuildsByWorkspaceIDParams) ([]database.WorkspaceBuild, error) { + start := time.Now() + builds, err := m.s.GetWorkspaceBuildsByWorkspaceID(ctx, arg) + m.queryLatencies.WithLabelValues("GetWorkspaceBuildsByWorkspaceID").Observe(time.Since(start).Seconds()) + return builds, err +} + +func (m metricsStore) GetWorkspaceBuildsCreatedAfter(ctx context.Context, createdAt time.Time) ([]database.WorkspaceBuild, error) { + start := time.Now() + builds, err := m.s.GetWorkspaceBuildsCreatedAfter(ctx, createdAt) + m.queryLatencies.WithLabelValues("GetWorkspaceBuildsCreatedAfter").Observe(time.Since(start).Seconds()) + return builds, err +} + +func (m metricsStore) GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (database.Workspace, error) { + start := time.Now() + workspace, err := m.s.GetWorkspaceByAgentID(ctx, agentID) + m.queryLatencies.WithLabelValues("GetWorkspaceByAgentID").Observe(time.Since(start).Seconds()) + return workspace, err +} + +func (m metricsStore) GetWorkspaceByID(ctx context.Context, id uuid.UUID) (database.Workspace, error) { + start := time.Now() + workspace, err := m.s.GetWorkspaceByID(ctx, id) + m.queryLatencies.WithLabelValues("GetWorkspaceByID").Observe(time.Since(start).Seconds()) + return workspace, err +} + +func (m metricsStore) GetWorkspaceByOwnerIDAndName(ctx context.Context, arg database.GetWorkspaceByOwnerIDAndNameParams) (database.Workspace, error) { + start := time.Now() + workspace, err := m.s.GetWorkspaceByOwnerIDAndName(ctx, arg) + m.queryLatencies.WithLabelValues("GetWorkspaceByOwnerIDAndName").Observe(time.Since(start).Seconds()) + return workspace, err +} + +func (m metricsStore) GetWorkspaceByWorkspaceAppID(ctx context.Context, workspaceAppID uuid.UUID) (database.Workspace, error) { + start := time.Now() + workspace, err := m.s.GetWorkspaceByWorkspaceAppID(ctx, workspaceAppID) + m.queryLatencies.WithLabelValues("GetWorkspaceByWorkspaceAppID").Observe(time.Since(start).Seconds()) + return workspace, err +} + +func (m metricsStore) GetWorkspaceProxies(ctx context.Context) ([]database.WorkspaceProxy, error) { + start := time.Now() + proxies, err := m.s.GetWorkspaceProxies(ctx) + m.queryLatencies.WithLabelValues("GetWorkspaceProxies").Observe(time.Since(start).Seconds()) + return proxies, err +} + +func (m metricsStore) GetWorkspaceProxyByHostname(ctx context.Context, arg database.GetWorkspaceProxyByHostnameParams) (database.WorkspaceProxy, error) { + start := time.Now() + proxy, err := m.s.GetWorkspaceProxyByHostname(ctx, arg) + m.queryLatencies.WithLabelValues("GetWorkspaceProxyByHostname").Observe(time.Since(start).Seconds()) + return proxy, err +} + +func (m metricsStore) GetWorkspaceProxyByID(ctx context.Context, id uuid.UUID) (database.WorkspaceProxy, error) { + start := time.Now() + proxy, err := m.s.GetWorkspaceProxyByID(ctx, id) + m.queryLatencies.WithLabelValues("GetWorkspaceProxyByID").Observe(time.Since(start).Seconds()) + return proxy, err +} + +func (m metricsStore) GetWorkspaceProxyByName(ctx context.Context, name string) (database.WorkspaceProxy, error) { + start := time.Now() + proxy, err := m.s.GetWorkspaceProxyByName(ctx, name) + m.queryLatencies.WithLabelValues("GetWorkspaceProxyByName").Observe(time.Since(start).Seconds()) + return proxy, err +} + +func (m metricsStore) GetWorkspaceResourceByID(ctx context.Context, id uuid.UUID) (database.WorkspaceResource, error) { + start := time.Now() + resource, err := m.s.GetWorkspaceResourceByID(ctx, id) + m.queryLatencies.WithLabelValues("GetWorkspaceResourceByID").Observe(time.Since(start).Seconds()) + return resource, err +} + +func (m metricsStore) GetWorkspaceResourceMetadataByResourceIDs(ctx context.Context, ids []uuid.UUID) ([]database.WorkspaceResourceMetadatum, error) { + start := time.Now() + metadata, err := m.s.GetWorkspaceResourceMetadataByResourceIDs(ctx, ids) + m.queryLatencies.WithLabelValues("GetWorkspaceResourceMetadataByResourceIDs").Observe(time.Since(start).Seconds()) + return metadata, err +} + +func (m metricsStore) GetWorkspaceResourceMetadataCreatedAfter(ctx context.Context, createdAt time.Time) ([]database.WorkspaceResourceMetadatum, error) { + start := time.Now() + metadata, err := m.s.GetWorkspaceResourceMetadataCreatedAfter(ctx, createdAt) + m.queryLatencies.WithLabelValues("GetWorkspaceResourceMetadataCreatedAfter").Observe(time.Since(start).Seconds()) + return metadata, err +} + +func (m metricsStore) GetWorkspaceResourcesByJobID(ctx context.Context, jobID uuid.UUID) ([]database.WorkspaceResource, error) { + start := time.Now() + resources, err := m.s.GetWorkspaceResourcesByJobID(ctx, jobID) + m.queryLatencies.WithLabelValues("GetWorkspaceResourcesByJobID").Observe(time.Since(start).Seconds()) + return resources, err +} + +func (m metricsStore) GetWorkspaceResourcesByJobIDs(ctx context.Context, ids []uuid.UUID) ([]database.WorkspaceResource, error) { + start := time.Now() + resources, err := m.s.GetWorkspaceResourcesByJobIDs(ctx, ids) + m.queryLatencies.WithLabelValues("GetWorkspaceResourcesByJobIDs").Observe(time.Since(start).Seconds()) + return resources, err +} + +func (m metricsStore) GetWorkspaceResourcesCreatedAfter(ctx context.Context, createdAt time.Time) ([]database.WorkspaceResource, error) { + start := time.Now() + resources, err := m.s.GetWorkspaceResourcesCreatedAfter(ctx, createdAt) + m.queryLatencies.WithLabelValues("GetWorkspaceResourcesCreatedAfter").Observe(time.Since(start).Seconds()) + return resources, err +} + +func (m metricsStore) GetWorkspaces(ctx context.Context, arg database.GetWorkspacesParams) ([]database.GetWorkspacesRow, error) { + start := time.Now() + workspaces, err := m.s.GetWorkspaces(ctx, arg) + m.queryLatencies.WithLabelValues("GetWorkspaces").Observe(time.Since(start).Seconds()) + return workspaces, err +} + +func (m metricsStore) GetWorkspacesEligibleForAutoStartStop(ctx context.Context, now time.Time) ([]database.Workspace, error) { + start := time.Now() + workspaces, err := m.s.GetWorkspacesEligibleForAutoStartStop(ctx, now) + m.queryLatencies.WithLabelValues("GetWorkspacesEligibleForAutoStartStop").Observe(time.Since(start).Seconds()) + return workspaces, err +} + +func (m metricsStore) InsertAPIKey(ctx context.Context, arg database.InsertAPIKeyParams) (database.APIKey, error) { + start := time.Now() + key, err := m.s.InsertAPIKey(ctx, arg) + m.queryLatencies.WithLabelValues("InsertAPIKey").Observe(time.Since(start).Seconds()) + return key, err +} + +func (m metricsStore) InsertAllUsersGroup(ctx context.Context, organizationID uuid.UUID) (database.Group, error) { + start := time.Now() + group, err := m.s.InsertAllUsersGroup(ctx, organizationID) + m.queryLatencies.WithLabelValues("InsertAllUsersGroup").Observe(time.Since(start).Seconds()) + return group, err +} + +func (m metricsStore) InsertAuditLog(ctx context.Context, arg database.InsertAuditLogParams) (database.AuditLog, error) { + start := time.Now() + log, err := m.s.InsertAuditLog(ctx, arg) + m.queryLatencies.WithLabelValues("InsertAuditLog").Observe(time.Since(start).Seconds()) + return log, err +} + +func (m metricsStore) InsertDERPMeshKey(ctx context.Context, value string) error { + start := time.Now() + err := m.s.InsertDERPMeshKey(ctx, value) + m.queryLatencies.WithLabelValues("InsertDERPMeshKey").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) InsertDeploymentID(ctx context.Context, value string) error { + start := time.Now() + err := m.s.InsertDeploymentID(ctx, value) + m.queryLatencies.WithLabelValues("InsertDeploymentID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) InsertFile(ctx context.Context, arg database.InsertFileParams) (database.File, error) { + start := time.Now() + file, err := m.s.InsertFile(ctx, arg) + m.queryLatencies.WithLabelValues("InsertFile").Observe(time.Since(start).Seconds()) + return file, err +} + +func (m metricsStore) InsertGitAuthLink(ctx context.Context, arg database.InsertGitAuthLinkParams) (database.GitAuthLink, error) { + start := time.Now() + link, err := m.s.InsertGitAuthLink(ctx, arg) + m.queryLatencies.WithLabelValues("InsertGitAuthLink").Observe(time.Since(start).Seconds()) + return link, err +} + +func (m metricsStore) InsertGitSSHKey(ctx context.Context, arg database.InsertGitSSHKeyParams) (database.GitSSHKey, error) { + start := time.Now() + key, err := m.s.InsertGitSSHKey(ctx, arg) + m.queryLatencies.WithLabelValues("InsertGitSSHKey").Observe(time.Since(start).Seconds()) + return key, err +} + +func (m metricsStore) InsertGroup(ctx context.Context, arg database.InsertGroupParams) (database.Group, error) { + start := time.Now() + group, err := m.s.InsertGroup(ctx, arg) + m.queryLatencies.WithLabelValues("InsertGroup").Observe(time.Since(start).Seconds()) + return group, err +} + +func (m metricsStore) InsertGroupMember(ctx context.Context, arg database.InsertGroupMemberParams) error { + start := time.Now() + err := m.s.InsertGroupMember(ctx, arg) + m.queryLatencies.WithLabelValues("InsertGroupMember").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) InsertLicense(ctx context.Context, arg database.InsertLicenseParams) (database.License, error) { + start := time.Now() + license, err := m.s.InsertLicense(ctx, arg) + m.queryLatencies.WithLabelValues("InsertLicense").Observe(time.Since(start).Seconds()) + return license, err +} + +func (m metricsStore) InsertOrganization(ctx context.Context, arg database.InsertOrganizationParams) (database.Organization, error) { + start := time.Now() + organization, err := m.s.InsertOrganization(ctx, arg) + m.queryLatencies.WithLabelValues("InsertOrganization").Observe(time.Since(start).Seconds()) + return organization, err +} + +func (m metricsStore) InsertOrganizationMember(ctx context.Context, arg database.InsertOrganizationMemberParams) (database.OrganizationMember, error) { + start := time.Now() + member, err := m.s.InsertOrganizationMember(ctx, arg) + m.queryLatencies.WithLabelValues("InsertOrganizationMember").Observe(time.Since(start).Seconds()) + return member, err +} + +func (m metricsStore) InsertParameterSchema(ctx context.Context, arg database.InsertParameterSchemaParams) (database.ParameterSchema, error) { + start := time.Now() + schema, err := m.s.InsertParameterSchema(ctx, arg) + m.queryLatencies.WithLabelValues("InsertParameterSchema").Observe(time.Since(start).Seconds()) + return schema, err +} + +func (m metricsStore) InsertParameterValue(ctx context.Context, arg database.InsertParameterValueParams) (database.ParameterValue, error) { + start := time.Now() + value, err := m.s.InsertParameterValue(ctx, arg) + m.queryLatencies.WithLabelValues("InsertParameterValue").Observe(time.Since(start).Seconds()) + return value, err +} + +func (m metricsStore) InsertProvisionerDaemon(ctx context.Context, arg database.InsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) { + start := time.Now() + daemon, err := m.s.InsertProvisionerDaemon(ctx, arg) + m.queryLatencies.WithLabelValues("InsertProvisionerDaemon").Observe(time.Since(start).Seconds()) + return daemon, err +} + +func (m metricsStore) InsertProvisionerJob(ctx context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) { + start := time.Now() + job, err := m.s.InsertProvisionerJob(ctx, arg) + m.queryLatencies.WithLabelValues("InsertProvisionerJob").Observe(time.Since(start).Seconds()) + return job, err +} + +func (m metricsStore) InsertProvisionerJobLogs(ctx context.Context, arg database.InsertProvisionerJobLogsParams) ([]database.ProvisionerJobLog, error) { + start := time.Now() + logs, err := m.s.InsertProvisionerJobLogs(ctx, arg) + m.queryLatencies.WithLabelValues("InsertProvisionerJobLogs").Observe(time.Since(start).Seconds()) + return logs, err +} + +func (m metricsStore) InsertReplica(ctx context.Context, arg database.InsertReplicaParams) (database.Replica, error) { + start := time.Now() + replica, err := m.s.InsertReplica(ctx, arg) + m.queryLatencies.WithLabelValues("InsertReplica").Observe(time.Since(start).Seconds()) + return replica, err +} + +func (m metricsStore) InsertTemplate(ctx context.Context, arg database.InsertTemplateParams) (database.Template, error) { + start := time.Now() + template, err := m.s.InsertTemplate(ctx, arg) + m.queryLatencies.WithLabelValues("InsertTemplate").Observe(time.Since(start).Seconds()) + return template, err +} + +func (m metricsStore) InsertTemplateVersion(ctx context.Context, arg database.InsertTemplateVersionParams) (database.TemplateVersion, error) { + start := time.Now() + version, err := m.s.InsertTemplateVersion(ctx, arg) + m.queryLatencies.WithLabelValues("InsertTemplateVersion").Observe(time.Since(start).Seconds()) + return version, err +} + +func (m metricsStore) InsertTemplateVersionParameter(ctx context.Context, arg database.InsertTemplateVersionParameterParams) (database.TemplateVersionParameter, error) { + start := time.Now() + parameter, err := m.s.InsertTemplateVersionParameter(ctx, arg) + m.queryLatencies.WithLabelValues("InsertTemplateVersionParameter").Observe(time.Since(start).Seconds()) + return parameter, err +} + +func (m metricsStore) InsertTemplateVersionVariable(ctx context.Context, arg database.InsertTemplateVersionVariableParams) (database.TemplateVersionVariable, error) { + start := time.Now() + variable, err := m.s.InsertTemplateVersionVariable(ctx, arg) + m.queryLatencies.WithLabelValues("InsertTemplateVersionVariable").Observe(time.Since(start).Seconds()) + return variable, err +} + +func (m metricsStore) InsertUser(ctx context.Context, arg database.InsertUserParams) (database.User, error) { + start := time.Now() + user, err := m.s.InsertUser(ctx, arg) + m.queryLatencies.WithLabelValues("InsertUser").Observe(time.Since(start).Seconds()) + return user, err +} + +func (m metricsStore) InsertUserGroupsByName(ctx context.Context, arg database.InsertUserGroupsByNameParams) error { + start := time.Now() + err := m.s.InsertUserGroupsByName(ctx, arg) + m.queryLatencies.WithLabelValues("InsertUserGroupsByName").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) InsertUserLink(ctx context.Context, arg database.InsertUserLinkParams) (database.UserLink, error) { + start := time.Now() + link, err := m.s.InsertUserLink(ctx, arg) + m.queryLatencies.WithLabelValues("InsertUserLink").Observe(time.Since(start).Seconds()) + return link, err +} + +func (m metricsStore) InsertWorkspace(ctx context.Context, arg database.InsertWorkspaceParams) (database.Workspace, error) { + start := time.Now() + workspace, err := m.s.InsertWorkspace(ctx, arg) + m.queryLatencies.WithLabelValues("InsertWorkspace").Observe(time.Since(start).Seconds()) + return workspace, err +} + +func (m metricsStore) InsertWorkspaceAgent(ctx context.Context, arg database.InsertWorkspaceAgentParams) (database.WorkspaceAgent, error) { + start := time.Now() + agent, err := m.s.InsertWorkspaceAgent(ctx, arg) + m.queryLatencies.WithLabelValues("InsertWorkspaceAgent").Observe(time.Since(start).Seconds()) + return agent, err +} + +func (m metricsStore) InsertWorkspaceAgentMetadata(ctx context.Context, arg database.InsertWorkspaceAgentMetadataParams) error { + start := time.Now() + err := m.s.InsertWorkspaceAgentMetadata(ctx, arg) + m.queryLatencies.WithLabelValues("InsertWorkspaceAgentMetadata").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) InsertWorkspaceAgentStartupLogs(ctx context.Context, arg database.InsertWorkspaceAgentStartupLogsParams) ([]database.WorkspaceAgentStartupLog, error) { + start := time.Now() + logs, err := m.s.InsertWorkspaceAgentStartupLogs(ctx, arg) + m.queryLatencies.WithLabelValues("InsertWorkspaceAgentStartupLogs").Observe(time.Since(start).Seconds()) + return logs, err +} + +func (m metricsStore) InsertWorkspaceAgentStat(ctx context.Context, arg database.InsertWorkspaceAgentStatParams) (database.WorkspaceAgentStat, error) { + start := time.Now() + stat, err := m.s.InsertWorkspaceAgentStat(ctx, arg) + m.queryLatencies.WithLabelValues("InsertWorkspaceAgentStat").Observe(time.Since(start).Seconds()) + return stat, err +} + +func (m metricsStore) InsertWorkspaceApp(ctx context.Context, arg database.InsertWorkspaceAppParams) (database.WorkspaceApp, error) { + start := time.Now() + app, err := m.s.InsertWorkspaceApp(ctx, arg) + m.queryLatencies.WithLabelValues("InsertWorkspaceApp").Observe(time.Since(start).Seconds()) + return app, err +} + +func (m metricsStore) InsertWorkspaceBuild(ctx context.Context, arg database.InsertWorkspaceBuildParams) (database.WorkspaceBuild, error) { + start := time.Now() + build, err := m.s.InsertWorkspaceBuild(ctx, arg) + m.queryLatencies.WithLabelValues("InsertWorkspaceBuild").Observe(time.Since(start).Seconds()) + return build, err +} + +func (m metricsStore) InsertWorkspaceBuildParameters(ctx context.Context, arg database.InsertWorkspaceBuildParametersParams) error { + start := time.Now() + err := m.s.InsertWorkspaceBuildParameters(ctx, arg) + m.queryLatencies.WithLabelValues("InsertWorkspaceBuildParameters").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) InsertWorkspaceProxy(ctx context.Context, arg database.InsertWorkspaceProxyParams) (database.WorkspaceProxy, error) { + start := time.Now() + proxy, err := m.s.InsertWorkspaceProxy(ctx, arg) + m.queryLatencies.WithLabelValues("InsertWorkspaceProxy").Observe(time.Since(start).Seconds()) + return proxy, err +} + +func (m metricsStore) InsertWorkspaceResource(ctx context.Context, arg database.InsertWorkspaceResourceParams) (database.WorkspaceResource, error) { + start := time.Now() + resource, err := m.s.InsertWorkspaceResource(ctx, arg) + m.queryLatencies.WithLabelValues("InsertWorkspaceResource").Observe(time.Since(start).Seconds()) + return resource, err +} + +func (m metricsStore) InsertWorkspaceResourceMetadata(ctx context.Context, arg database.InsertWorkspaceResourceMetadataParams) ([]database.WorkspaceResourceMetadatum, error) { + start := time.Now() + metadata, err := m.s.InsertWorkspaceResourceMetadata(ctx, arg) + m.queryLatencies.WithLabelValues("InsertWorkspaceResourceMetadata").Observe(time.Since(start).Seconds()) + return metadata, err +} + +func (m metricsStore) ParameterValue(ctx context.Context, id uuid.UUID) (database.ParameterValue, error) { + start := time.Now() + value, err := m.s.ParameterValue(ctx, id) + m.queryLatencies.WithLabelValues("ParameterValue").Observe(time.Since(start).Seconds()) + return value, err +} + +func (m metricsStore) ParameterValues(ctx context.Context, arg database.ParameterValuesParams) ([]database.ParameterValue, error) { + start := time.Now() + values, err := m.s.ParameterValues(ctx, arg) + m.queryLatencies.WithLabelValues("ParameterValues").Observe(time.Since(start).Seconds()) + return values, err +} + +func (m metricsStore) RegisterWorkspaceProxy(ctx context.Context, arg database.RegisterWorkspaceProxyParams) (database.WorkspaceProxy, error) { + start := time.Now() + proxy, err := m.s.RegisterWorkspaceProxy(ctx, arg) + m.queryLatencies.WithLabelValues("RegisterWorkspaceProxy").Observe(time.Since(start).Seconds()) + return proxy, err +} + +func (m metricsStore) TryAcquireLock(ctx context.Context, pgTryAdvisoryXactLock int64) (bool, error) { + start := time.Now() + ok, err := m.s.TryAcquireLock(ctx, pgTryAdvisoryXactLock) + m.queryLatencies.WithLabelValues("TryAcquireLock").Observe(time.Since(start).Seconds()) + return ok, err +} + +func (m metricsStore) UpdateAPIKeyByID(ctx context.Context, arg database.UpdateAPIKeyByIDParams) error { + start := time.Now() + err := m.s.UpdateAPIKeyByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateAPIKeyByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateGitAuthLink(ctx context.Context, arg database.UpdateGitAuthLinkParams) (database.GitAuthLink, error) { + start := time.Now() + link, err := m.s.UpdateGitAuthLink(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateGitAuthLink").Observe(time.Since(start).Seconds()) + return link, err +} + +func (m metricsStore) UpdateGitSSHKey(ctx context.Context, arg database.UpdateGitSSHKeyParams) (database.GitSSHKey, error) { + start := time.Now() + key, err := m.s.UpdateGitSSHKey(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateGitSSHKey").Observe(time.Since(start).Seconds()) + return key, err +} + +func (m metricsStore) UpdateGroupByID(ctx context.Context, arg database.UpdateGroupByIDParams) (database.Group, error) { + start := time.Now() + group, err := m.s.UpdateGroupByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateGroupByID").Observe(time.Since(start).Seconds()) + return group, err +} + +func (m metricsStore) UpdateMemberRoles(ctx context.Context, arg database.UpdateMemberRolesParams) (database.OrganizationMember, error) { + start := time.Now() + member, err := m.s.UpdateMemberRoles(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateMemberRoles").Observe(time.Since(start).Seconds()) + return member, err +} + +func (m metricsStore) UpdateProvisionerJobByID(ctx context.Context, arg database.UpdateProvisionerJobByIDParams) error { + start := time.Now() + err := m.s.UpdateProvisionerJobByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateProvisionerJobByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateProvisionerJobWithCancelByID(ctx context.Context, arg database.UpdateProvisionerJobWithCancelByIDParams) error { + start := time.Now() + err := m.s.UpdateProvisionerJobWithCancelByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateProvisionerJobWithCancelByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateProvisionerJobWithCompleteByID(ctx context.Context, arg database.UpdateProvisionerJobWithCompleteByIDParams) error { + start := time.Now() + err := m.s.UpdateProvisionerJobWithCompleteByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateProvisionerJobWithCompleteByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateReplica(ctx context.Context, arg database.UpdateReplicaParams) (database.Replica, error) { + start := time.Now() + replica, err := m.s.UpdateReplica(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateReplica").Observe(time.Since(start).Seconds()) + return replica, err +} + +func (m metricsStore) UpdateTemplateACLByID(ctx context.Context, arg database.UpdateTemplateACLByIDParams) (database.Template, error) { + start := time.Now() + template, err := m.s.UpdateTemplateACLByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateTemplateACLByID").Observe(time.Since(start).Seconds()) + return template, err +} + +func (m metricsStore) UpdateTemplateActiveVersionByID(ctx context.Context, arg database.UpdateTemplateActiveVersionByIDParams) error { + start := time.Now() + err := m.s.UpdateTemplateActiveVersionByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateTemplateActiveVersionByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateTemplateDeletedByID(ctx context.Context, arg database.UpdateTemplateDeletedByIDParams) error { + start := time.Now() + err := m.s.UpdateTemplateDeletedByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateTemplateDeletedByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateTemplateMetaByID(ctx context.Context, arg database.UpdateTemplateMetaByIDParams) (database.Template, error) { + start := time.Now() + template, err := m.s.UpdateTemplateMetaByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateTemplateMetaByID").Observe(time.Since(start).Seconds()) + return template, err +} + +func (m metricsStore) UpdateTemplateScheduleByID(ctx context.Context, arg database.UpdateTemplateScheduleByIDParams) (database.Template, error) { + start := time.Now() + template, err := m.s.UpdateTemplateScheduleByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateTemplateScheduleByID").Observe(time.Since(start).Seconds()) + return template, err +} + +func (m metricsStore) UpdateTemplateVersionByID(ctx context.Context, arg database.UpdateTemplateVersionByIDParams) (database.TemplateVersion, error) { + start := time.Now() + version, err := m.s.UpdateTemplateVersionByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateTemplateVersionByID").Observe(time.Since(start).Seconds()) + return version, err +} + +func (m metricsStore) UpdateTemplateVersionDescriptionByJobID(ctx context.Context, arg database.UpdateTemplateVersionDescriptionByJobIDParams) error { + start := time.Now() + err := m.s.UpdateTemplateVersionDescriptionByJobID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateTemplateVersionDescriptionByJobID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateTemplateVersionGitAuthProvidersByJobID(ctx context.Context, arg database.UpdateTemplateVersionGitAuthProvidersByJobIDParams) error { + start := time.Now() + err := m.s.UpdateTemplateVersionGitAuthProvidersByJobID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateTemplateVersionGitAuthProvidersByJobID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateUserDeletedByID(ctx context.Context, arg database.UpdateUserDeletedByIDParams) error { + start := time.Now() + err := m.s.UpdateUserDeletedByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserDeletedByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateUserHashedPassword(ctx context.Context, arg database.UpdateUserHashedPasswordParams) error { + start := time.Now() + err := m.s.UpdateUserHashedPassword(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserHashedPassword").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateUserLastSeenAt(ctx context.Context, arg database.UpdateUserLastSeenAtParams) (database.User, error) { + start := time.Now() + user, err := m.s.UpdateUserLastSeenAt(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserLastSeenAt").Observe(time.Since(start).Seconds()) + return user, err +} + +func (m metricsStore) UpdateUserLink(ctx context.Context, arg database.UpdateUserLinkParams) (database.UserLink, error) { + start := time.Now() + link, err := m.s.UpdateUserLink(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserLink").Observe(time.Since(start).Seconds()) + return link, err +} + +func (m metricsStore) UpdateUserLinkedID(ctx context.Context, arg database.UpdateUserLinkedIDParams) (database.UserLink, error) { + start := time.Now() + link, err := m.s.UpdateUserLinkedID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserLinkedID").Observe(time.Since(start).Seconds()) + return link, err +} + +func (m metricsStore) UpdateUserProfile(ctx context.Context, arg database.UpdateUserProfileParams) (database.User, error) { + start := time.Now() + user, err := m.s.UpdateUserProfile(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserProfile").Observe(time.Since(start).Seconds()) + return user, err +} + +func (m metricsStore) UpdateUserRoles(ctx context.Context, arg database.UpdateUserRolesParams) (database.User, error) { + start := time.Now() + user, err := m.s.UpdateUserRoles(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserRoles").Observe(time.Since(start).Seconds()) + return user, err +} + +func (m metricsStore) UpdateUserStatus(ctx context.Context, arg database.UpdateUserStatusParams) (database.User, error) { + start := time.Now() + user, err := m.s.UpdateUserStatus(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserStatus").Observe(time.Since(start).Seconds()) + return user, err +} + +func (m metricsStore) UpdateWorkspace(ctx context.Context, arg database.UpdateWorkspaceParams) (database.Workspace, error) { + start := time.Now() + workspace, err := m.s.UpdateWorkspace(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspace").Observe(time.Since(start).Seconds()) + return workspace, err +} + +func (m metricsStore) UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg database.UpdateWorkspaceAgentConnectionByIDParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceAgentConnectionByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceAgentConnectionByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateWorkspaceAgentLifecycleStateByID(ctx context.Context, arg database.UpdateWorkspaceAgentLifecycleStateByIDParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceAgentLifecycleStateByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceAgentLifecycleStateByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateWorkspaceAgentMetadata(ctx context.Context, arg database.UpdateWorkspaceAgentMetadataParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceAgentMetadata(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceAgentMetadata").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateWorkspaceAgentStartupByID(ctx context.Context, arg database.UpdateWorkspaceAgentStartupByIDParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceAgentStartupByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceAgentStartupByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateWorkspaceAgentStartupLogOverflowByID(ctx context.Context, arg database.UpdateWorkspaceAgentStartupLogOverflowByIDParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceAgentStartupLogOverflowByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceAgentStartupLogOverflowByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateWorkspaceAppHealthByID(ctx context.Context, arg database.UpdateWorkspaceAppHealthByIDParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceAppHealthByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceAppHealthByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateWorkspaceAutostart(ctx context.Context, arg database.UpdateWorkspaceAutostartParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceAutostart(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceAutostart").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateWorkspaceBuildByID(ctx context.Context, arg database.UpdateWorkspaceBuildByIDParams) (database.WorkspaceBuild, error) { + start := time.Now() + build, err := m.s.UpdateWorkspaceBuildByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceBuildByID").Observe(time.Since(start).Seconds()) + return build, err +} + +func (m metricsStore) UpdateWorkspaceBuildCostByID(ctx context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) (database.WorkspaceBuild, error) { + start := time.Now() + build, err := m.s.UpdateWorkspaceBuildCostByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceBuildCostByID").Observe(time.Since(start).Seconds()) + return build, err +} + +func (m metricsStore) UpdateWorkspaceDeletedByID(ctx context.Context, arg database.UpdateWorkspaceDeletedByIDParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceDeletedByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceDeletedByID").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateWorkspaceLastUsedAt(ctx context.Context, arg database.UpdateWorkspaceLastUsedAtParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceLastUsedAt(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceLastUsedAt").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateWorkspaceProxy(ctx context.Context, arg database.UpdateWorkspaceProxyParams) (database.WorkspaceProxy, error) { + start := time.Now() + proxy, err := m.s.UpdateWorkspaceProxy(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceProxy").Observe(time.Since(start).Seconds()) + return proxy, err +} + +func (m metricsStore) UpdateWorkspaceProxyDeleted(ctx context.Context, arg database.UpdateWorkspaceProxyDeletedParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceProxyDeleted(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceProxyDeleted").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateWorkspaceTTL(ctx context.Context, arg database.UpdateWorkspaceTTLParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceTTL(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceTTL").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpdateWorkspaceTTLToBeWithinTemplateMax(ctx context.Context, arg database.UpdateWorkspaceTTLToBeWithinTemplateMaxParams) error { + start := time.Now() + err := m.s.UpdateWorkspaceTTLToBeWithinTemplateMax(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceTTLToBeWithinTemplateMax").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpsertAppSecurityKey(ctx context.Context, value string) error { + start := time.Now() + err := m.s.UpsertAppSecurityKey(ctx, value) + m.queryLatencies.WithLabelValues("UpsertAppSecurityKey").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpsertLastUpdateCheck(ctx context.Context, value string) error { + start := time.Now() + err := m.s.UpsertLastUpdateCheck(ctx, value) + m.queryLatencies.WithLabelValues("UpsertLastUpdateCheck").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpsertLogoURL(ctx context.Context, value string) error { + start := time.Now() + err := m.s.UpsertLogoURL(ctx, value) + m.queryLatencies.WithLabelValues("UpsertLogoURL").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) UpsertServiceBanner(ctx context.Context, value string) error { + start := time.Now() + err := m.s.UpsertServiceBanner(ctx, value) + m.queryLatencies.WithLabelValues("UpsertServiceBanner").Observe(time.Since(start).Seconds()) + return err +} + +func (m metricsStore) GetAuthorizedTemplates(ctx context.Context, arg database.GetTemplatesWithFilterParams, prepared rbac.PreparedAuthorized) ([]database.Template, error) { + start := time.Now() + templates, err := m.s.GetAuthorizedTemplates(ctx, arg, prepared) + m.queryLatencies.WithLabelValues("GetAuthorizedTemplates").Observe(time.Since(start).Seconds()) + return templates, err +} + +func (m metricsStore) GetTemplateGroupRoles(ctx context.Context, id uuid.UUID) ([]database.TemplateGroup, error) { + start := time.Now() + roles, err := m.s.GetTemplateGroupRoles(ctx, id) + m.queryLatencies.WithLabelValues("GetTemplateGroupRoles").Observe(time.Since(start).Seconds()) + return roles, err +} + +func (m metricsStore) GetTemplateUserRoles(ctx context.Context, id uuid.UUID) ([]database.TemplateUser, error) { + start := time.Now() + roles, err := m.s.GetTemplateUserRoles(ctx, id) + m.queryLatencies.WithLabelValues("GetTemplateUserRoles").Observe(time.Since(start).Seconds()) + return roles, err +} + +func (m metricsStore) GetAuthorizedWorkspaces(ctx context.Context, arg database.GetWorkspacesParams, prepared rbac.PreparedAuthorized) ([]database.GetWorkspacesRow, error) { + start := time.Now() + workspaces, err := m.s.GetAuthorizedWorkspaces(ctx, arg, prepared) + m.queryLatencies.WithLabelValues("GetAuthorizedWorkspaces").Observe(time.Since(start).Seconds()) + return workspaces, err +} + +func (m metricsStore) GetAuthorizedUserCount(ctx context.Context, arg database.GetFilteredUserCountParams, prepared rbac.PreparedAuthorized) (int64, error) { + start := time.Now() + count, err := m.s.GetAuthorizedUserCount(ctx, arg, prepared) + m.queryLatencies.WithLabelValues("GetAuthorizedUserCount").Observe(time.Since(start).Seconds()) + return count, err +} From c0ea9efc66c115b814f1b5af4e60108357647b50 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Tue, 30 May 2023 14:24:24 +0100 Subject: [PATCH 02/10] ensure wrapping --- coderd/coderd.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/coderd/coderd.go b/coderd/coderd.go index 712e52460fbfe..a3f039d1176ad 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -47,6 +47,7 @@ import ( "github.com/coder/coder/coderd/awsidentity" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/database/dbauthz" + "github.com/coder/coder/coderd/database/dbmetrics" "github.com/coder/coder/coderd/database/dbtype" "github.com/coder/coder/coderd/gitauth" "github.com/coder/coder/coderd/gitsshkey" @@ -185,6 +186,8 @@ func New(options *Options) *API { if options.Authorizer == nil { options.Authorizer = rbac.NewCachingAuthorizer(options.PrometheusRegistry) } + // The below are no-ops if already wrapped. + options.Database = dbmetrics.New(options.Database, options.PrometheusRegistry) options.Database = dbauthz.New( options.Database, options.Authorizer, From b153939670fb99f34db9285a5bda152d329db958 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 31 May 2023 10:28:57 +0100 Subject: [PATCH 03/10] only wrap if we have a prometheus registry; add safety check for non-dev --- coderd/coderd.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/coderd/coderd.go b/coderd/coderd.go index a3f039d1176ad..dc0111f18d33c 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -177,6 +177,11 @@ func New(options *Options) *API { options = &Options{} } + // Safety check: if we're not running a unit test, we *must* have a Prometheus registry. + if options.PrometheusRegistry == nil && flag.Lookup("test.v") == nil { + panic("developer error: options.PrometheusRegistry is nil and not running a unit test") + } + if options.DeploymentValues.DisableOwnerWorkspaceExec { rbac.ReloadBuiltinRoles(&rbac.RoleOptions{ NoOwnerWorkspaceExec: true, @@ -187,7 +192,9 @@ func New(options *Options) *API { options.Authorizer = rbac.NewCachingAuthorizer(options.PrometheusRegistry) } // The below are no-ops if already wrapped. - options.Database = dbmetrics.New(options.Database, options.PrometheusRegistry) + if options.PrometheusRegistry != nil { + options.Database = dbmetrics.New(options.Database, options.PrometheusRegistry) + } options.Database = dbauthz.New( options.Database, options.Authorizer, From 6b867c642c96268f9e1fc71b95ba849a9a31dbdf Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 31 May 2023 10:33:24 +0100 Subject: [PATCH 04/10] measure tx duration --- coderd/database/dbmetrics/dbmetrics.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index 0c588c21b2317..93901fa53631d 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -25,10 +25,19 @@ func New(s database.Store, reg prometheus.Registerer) database.Store { Help: "Latency distribution of queries in seconds.", Buckets: prometheus.DefBuckets, }, []string{"query"}) + txDuration := prometheus.NewHistogram(prometheus.HistogramOpts{ + Namespace: "coderd", + Subsystem: "db", + Name: "tx_duration_seconds", + Help: "Duration of transactions in seconds.", + Buckets: prometheus.DefBuckets, + }) reg.MustRegister(queryLatencies) + reg.MustRegister(txDuration) return &metricsStore{ s: s, queryLatencies: queryLatencies, + txDuration: txDuration, } } @@ -37,6 +46,7 @@ var _ database.Store = (*metricsStore)(nil) type metricsStore struct { s database.Store queryLatencies *prometheus.HistogramVec + txDuration prometheus.Histogram } func (m metricsStore) Ping(ctx context.Context) (time.Duration, error) { @@ -47,8 +57,10 @@ func (m metricsStore) Ping(ctx context.Context) (time.Duration, error) { } func (m metricsStore) InTx(f func(database.Store) error, options *sql.TxOptions) error { - // No point in measuring this, as it's just a wrapper around the underlying store's InTx method. - return m.s.InTx(f, options) + start := time.Now() + err := m.s.InTx(f, options) + m.txDuration.Observe(time.Since(start).Seconds()) + return err } func (m metricsStore) AcquireLock(ctx context.Context, pgAdvisoryXactLock int64) error { From d3cf018366d5e12d454b0d6b4af903ce630ae11a Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 31 May 2023 10:38:18 +0100 Subject: [PATCH 05/10] fixup! Merge remote-tracking branch 'origin/main' into cj/db-prom --- coderd/database/dbmetrics/dbmetrics.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index 93901fa53631d..3ecf60d6e5d44 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -231,9 +231,9 @@ func (m metricsStore) GetDERPMeshKey(ctx context.Context) (string, error) { return key, err } -func (m metricsStore) GetDeploymentDAUs(ctx context.Context) ([]database.GetDeploymentDAUsRow, error) { +func (m metricsStore) GetDeploymentDAUs(ctx context.Context, tzOffset int32) ([]database.GetDeploymentDAUsRow, error) { start := time.Now() - rows, err := m.s.GetDeploymentDAUs(ctx) + rows, err := m.s.GetDeploymentDAUs(ctx, tzOffset) m.queryLatencies.WithLabelValues("GetDeploymentDAUs").Observe(time.Since(start).Seconds()) return rows, err } @@ -539,9 +539,9 @@ func (m metricsStore) GetTemplateByOrganizationAndName(ctx context.Context, arg return template, err } -func (m metricsStore) GetTemplateDAUs(ctx context.Context, templateID uuid.UUID) ([]database.GetTemplateDAUsRow, error) { +func (m metricsStore) GetTemplateDAUs(ctx context.Context, arg database.GetTemplateDAUsParams) ([]database.GetTemplateDAUsRow, error) { start := time.Now() - daus, err := m.s.GetTemplateDAUs(ctx, templateID) + daus, err := m.s.GetTemplateDAUs(ctx, arg) m.queryLatencies.WithLabelValues("GetTemplateDAUs").Observe(time.Since(start).Seconds()) return daus, err } From 0ecd6aa095daef546f675458fed19979cbecfdb8 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 31 May 2023 10:42:43 +0100 Subject: [PATCH 06/10] chore: fix flaky TestLicensesListFake/Mainline --- enterprise/cli/licenses_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/enterprise/cli/licenses_test.go b/enterprise/cli/licenses_test.go index 77d6dd15abd87..c80f5d7bd9963 100644 --- a/enterprise/cli/licenses_test.go +++ b/enterprise/cli/licenses_test.go @@ -140,6 +140,7 @@ func TestLicensesListFake(t *testing.T) { // so instead we have to fake the HTTP interaction. t.Run("Mainline", func(t *testing.T) { t.Parallel() + var expectedLicenseExpires = time.Date(2024, 4, 6, 16, 53, 35, 0, time.UTC) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() inv := setupFakeLicenseServerTest(t, "licenses", "list") @@ -158,7 +159,13 @@ func TestLicensesListFake(t *testing.T) { assert.Equal(t, "claim1", licenses[0].Claims["h1"]) assert.Equal(t, int32(5), licenses[1].ID) assert.Equal(t, "claim2", licenses[1].Claims["h2"]) - assert.Equal(t, "2024-04-06T16:53:35Z", licenses[0].Claims["license_expires"]) + expiresClaim := licenses[0].Claims["license_expires"] + expiresString, ok := expiresClaim.(string) + require.True(t, ok, "license_expires claim is not a string") + assert.NotEmpty(t, expiresClaim) + expiresTime, err := time.Parse(time.RFC3339, expiresString) + require.NoError(t, err) + require.Equal(t, expectedLicenseExpires, expiresTime.UTC()) }) } From b846d0bc6392a4409e3b74b2f362cc54b6caca92 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 31 May 2023 10:45:02 +0100 Subject: [PATCH 07/10] fixup! chore: fix flaky TestLicensesListFake/Mainline --- enterprise/cli/licenses_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise/cli/licenses_test.go b/enterprise/cli/licenses_test.go index c80f5d7bd9963..fc4fb2bdc04ab 100644 --- a/enterprise/cli/licenses_test.go +++ b/enterprise/cli/licenses_test.go @@ -140,7 +140,7 @@ func TestLicensesListFake(t *testing.T) { // so instead we have to fake the HTTP interaction. t.Run("Mainline", func(t *testing.T) { t.Parallel() - var expectedLicenseExpires = time.Date(2024, 4, 6, 16, 53, 35, 0, time.UTC) + expectedLicenseExpires := time.Date(2024, 4, 6, 16, 53, 35, 0, time.UTC) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() inv := setupFakeLicenseServerTest(t, "licenses", "list") From 0b9e836116d694bfbf9b3f9ef9bfc01b0e5fd493 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 31 May 2023 12:16:18 +0100 Subject: [PATCH 08/10] fix double-wrapping for good --- coderd/database/db.go | 13 +++++++++++++ coderd/database/dbauthz/dbauthz.go | 12 ++++++++++-- coderd/database/dbauthz/dbauthz_test.go | 2 +- coderd/database/dbauthz/setup_test.go | 13 ++++++++++--- coderd/database/dbfake/databasefake.go | 4 ++++ coderd/database/dbmetrics/dbmetrics.go | 12 ++++++++++-- coderd/database/dbmock/store.go | 14 ++++++++++++++ 7 files changed, 62 insertions(+), 8 deletions(-) diff --git a/coderd/database/db.go b/coderd/database/db.go index 72b9ab3e7f174..591452905f918 100644 --- a/coderd/database/db.go +++ b/coderd/database/db.go @@ -24,11 +24,20 @@ type Store interface { querier // customQuerier contains custom queries that are not generated. customQuerier + // wrapper allows us to detect if the interface has been wrapped. + wrapper Ping(ctx context.Context) (time.Duration, error) InTx(func(Store) error, *sql.TxOptions) error } +type wrapper interface { + // Wrappers returns a list of wrappers that have been applied to the store. + // This is used to detect if the store has already wrapped, and avoid + // double-wrapping. + Wrappers() []string +} + // DBTX represents a database connection or transaction. type DBTX interface { ExecContext(context.Context, string, ...interface{}) (sql.Result, error) @@ -60,6 +69,10 @@ type sqlQuerier struct { db DBTX } +func (q *sqlQuerier) Wrappers() []string { + return []string{} +} + // Ping returns the time it takes to ping the database. func (q *sqlQuerier) Ping(ctx context.Context) (time.Duration, error) { start := time.Now() diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index b823f7bd7067f..135664f70420c 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -17,6 +17,8 @@ import ( var _ database.Store = (*querier)(nil) +const wrapname = "dbauthz.querier" + // NoActorError wraps ErrNoRows for the api to return a 404. This is the correct // response when the user is not authorized. var NoActorError = xerrors.Errorf("no authorization actor in context: %w", sql.ErrNoRows) @@ -89,8 +91,10 @@ type querier struct { func New(db database.Store, authorizer rbac.Authorizer, logger slog.Logger) database.Store { // If the underlying db store is already a querier, return it. // Do not double wrap. - if _, ok := db.(*querier); ok { - return db + for _, w := range db.Wrappers() { + if w == wrapname { + return db + } } return &querier{ db: db, @@ -99,6 +103,10 @@ func New(db database.Store, authorizer rbac.Authorizer, logger slog.Logger) data } } +func (q *querier) Wrappers() []string { + return append(q.db.Wrappers(), wrapname) +} + // authorizeContext is a helper function to authorize an action on an object. func (q *querier) authorizeContext(ctx context.Context, action rbac.Action, object rbac.Objecter) error { act, ok := ActorFromContext(ctx) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 3fa5d3cdf1c5b..c89829b34542a 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -138,7 +138,7 @@ func TestDBAuthzRecursive(t *testing.T) { for i := 2; i < method.Type.NumIn(); i++ { ins = append(ins, reflect.New(method.Type.In(i)).Elem()) } - if method.Name == "InTx" || method.Name == "Ping" { + if method.Name == "InTx" || method.Name == "Ping" || method.Name == "Wrappers" { continue } // Log the name of the last method, so if there is a panic, it is diff --git a/coderd/database/dbauthz/setup_test.go b/coderd/database/dbauthz/setup_test.go index 10870bd01a6e9..d333c87362cd0 100644 --- a/coderd/database/dbauthz/setup_test.go +++ b/coderd/database/dbauthz/setup_test.go @@ -8,6 +8,7 @@ import ( "strings" "testing" + "github.com/golang/mock/gomock" "github.com/google/uuid" "github.com/open-policy-agent/opa/topdown" "github.com/stretchr/testify/require" @@ -19,14 +20,16 @@ import ( "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/database/dbauthz" "github.com/coder/coder/coderd/database/dbfake" + "github.com/coder/coder/coderd/database/dbmock" "github.com/coder/coder/coderd/rbac" "github.com/coder/coder/coderd/rbac/regosql" "github.com/coder/coder/coderd/util/slice" ) var skipMethods = map[string]string{ - "InTx": "Not relevant", - "Ping": "Not relevant", + "InTx": "Not relevant", + "Ping": "Not relevant", + "Wrappers": "Not relevant", } // TestMethodTestSuite runs MethodTestSuite. @@ -52,7 +55,11 @@ type MethodTestSuite struct { // SetupSuite sets up the suite by creating a map of all methods on querier // and setting their count to 0. func (s *MethodTestSuite) SetupSuite() { - az := dbauthz.New(nil, nil, slog.Make()) + ctrl := gomock.NewController(s.T()) + mockStore := dbmock.NewMockStore(ctrl) + // We intentionally set no expectations apart from this. + mockStore.EXPECT().Wrappers().Return([]string{}).AnyTimes() + az := dbauthz.New(mockStore, nil, slog.Make()) // Take the underlying type of the interface. azt := reflect.TypeOf(az).Elem() s.methodAccounting = make(map[string]int) diff --git a/coderd/database/dbfake/databasefake.go b/coderd/database/dbfake/databasefake.go index bbb327c1b1f6e..b77e5617060ec 100644 --- a/coderd/database/dbfake/databasefake.go +++ b/coderd/database/dbfake/databasefake.go @@ -97,6 +97,10 @@ type fakeQuerier struct { *data } +func (q *fakeQuerier) Wrappers() []string { + return []string{} +} + type fakeTx struct { *fakeQuerier locks map[int64]struct{} diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index 3ecf60d6e5d44..3b38ba40fe26b 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -12,11 +12,15 @@ import ( "github.com/coder/coder/coderd/rbac" ) +const wrapname = "dbmetrics.metricsStore" + // New returns a database.Store that registers metrics for all queries to reg. func New(s database.Store, reg prometheus.Registerer) database.Store { // Don't double-wrap. - if _, ok := s.(*metricsStore); ok { - return s + for _, w := range s.Wrappers() { + if w == wrapname { + return s + } } queryLatencies := prometheus.NewHistogramVec(prometheus.HistogramOpts{ Namespace: "coderd", @@ -49,6 +53,10 @@ type metricsStore struct { txDuration prometheus.Histogram } +func (m metricsStore) Wrappers() []string { + return append(m.s.Wrappers(), wrapname) +} + func (m metricsStore) Ping(ctx context.Context) (time.Duration, error) { start := time.Now() duration, err := m.s.Ping(ctx) diff --git a/coderd/database/dbmock/store.go b/coderd/database/dbmock/store.go index a145f24802c07..bfb7955281c02 100644 --- a/coderd/database/dbmock/store.go +++ b/coderd/database/dbmock/store.go @@ -3233,3 +3233,17 @@ func (mr *MockStoreMockRecorder) UpsertServiceBanner(arg0, arg1 interface{}) *go mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertServiceBanner", reflect.TypeOf((*MockStore)(nil).UpsertServiceBanner), arg0, arg1) } + +// Wrappers mocks base method. +func (m *MockStore) Wrappers() []string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Wrappers") + ret0, _ := ret[0].([]string) + return ret0 +} + +// Wrappers indicates an expected call of Wrappers. +func (mr *MockStoreMockRecorder) Wrappers() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Wrappers", reflect.TypeOf((*MockStore)(nil).Wrappers)) +} From 9aee24369ed1ee074a36f0014b116950e46aef78 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 31 May 2023 12:51:40 +0100 Subject: [PATCH 09/10] fixup! fix double-wrapping for good --- coderd/database/db.go | 2 +- coderd/database/dbfake/databasefake.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/database/db.go b/coderd/database/db.go index 591452905f918..9ad12340705ba 100644 --- a/coderd/database/db.go +++ b/coderd/database/db.go @@ -69,7 +69,7 @@ type sqlQuerier struct { db DBTX } -func (q *sqlQuerier) Wrappers() []string { +func (*sqlQuerier) Wrappers() []string { return []string{} } diff --git a/coderd/database/dbfake/databasefake.go b/coderd/database/dbfake/databasefake.go index b77e5617060ec..31754186eb076 100644 --- a/coderd/database/dbfake/databasefake.go +++ b/coderd/database/dbfake/databasefake.go @@ -97,7 +97,7 @@ type fakeQuerier struct { *data } -func (q *fakeQuerier) Wrappers() []string { +func (*fakeQuerier) Wrappers() []string { return []string{} } From 9367f6a63cdff6511786d82879fed7061f85c8f1 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 31 May 2023 14:19:59 +0100 Subject: [PATCH 10/10] slices.Contains --- coderd/database/dbauthz/dbauthz.go | 7 +++---- coderd/database/dbmetrics/dbmetrics.go | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 135664f70420c..f2e141dc74d27 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/google/uuid" + "golang.org/x/exp/slices" "golang.org/x/xerrors" "github.com/open-policy-agent/opa/topdown" @@ -91,10 +92,8 @@ type querier struct { func New(db database.Store, authorizer rbac.Authorizer, logger slog.Logger) database.Store { // If the underlying db store is already a querier, return it. // Do not double wrap. - for _, w := range db.Wrappers() { - if w == wrapname { - return db - } + if slices.Contains(db.Wrappers(), wrapname) { + return db } return &querier{ db: db, diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index 3b38ba40fe26b..eb454b3bcfde6 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -7,6 +7,7 @@ import ( "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" + "golang.org/x/exp/slices" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/rbac" @@ -17,10 +18,8 @@ const wrapname = "dbmetrics.metricsStore" // New returns a database.Store that registers metrics for all queries to reg. func New(s database.Store, reg prometheus.Registerer) database.Store { // Don't double-wrap. - for _, w := range s.Wrappers() { - if w == wrapname { - return s - } + if slices.Contains(s.Wrappers(), wrapname) { + return s } queryLatencies := prometheus.NewHistogramVec(prometheus.HistogramOpts{ Namespace: "coderd",