feat: add connection statistics for workspace agents (#6469)

* fix: don't make session counts cumulative

This made for some weird tracking... we want the point-in-time
number of counts!

* Add databasefake query for getting agent stats

* Add deployment stats endpoint

* The query... works?!?

* Fix aggregation query

* Select from multiple tables instead

* Fix continuous stats

* Increase period of stat refreshes

* Add workspace counts to deployment stats

* fmt

* Add a slight bit of responsiveness

* Fix template version editor overflow

* Add refresh button

* Fix font family on button

* Fix latest stat being reported

* Revert agent conn stats

* Fix linting error

* Fix tests

* Fix gen

* Fix migrations

* Block on sending stat updates

* Add test fixtures

* Fix response structure

* make gen
This commit is contained in:
Kyle Carberry
2023-03-08 21:05:45 -06:00
committed by GitHub
parent 9d40d2ffdc
commit 5304b4e483
43 changed files with 1790 additions and 174 deletions

View File

@ -1158,7 +1158,7 @@ when required by your organization's security policy.`,
Flag: "agent-stats-refresh-interval",
Env: "AGENT_STATS_REFRESH_INTERVAL",
Hidden: true,
Default: (10 * time.Minute).String(),
Default: (30 * time.Second).String(),
Value: &c.AgentStatRefreshInterval,
},
{
@ -1322,7 +1322,7 @@ func (c *DeploymentValues) WithoutSecrets() (*DeploymentValues, error) {
// DeploymentValues returns the deployment config for the coder server.
func (c *Client) DeploymentValues(ctx context.Context) (*DeploymentConfig, error) {
res, err := c.Request(ctx, http.MethodGet, "/api/v2/config/deployment", nil)
res, err := c.Request(ctx, http.MethodGet, "/api/v2/deployment/config", nil)
if err != nil {
return nil, xerrors.Errorf("execute request: %w", err)
}
@ -1340,6 +1340,21 @@ func (c *Client) DeploymentValues(ctx context.Context) (*DeploymentConfig, error
return resp, json.NewDecoder(res.Body).Decode(resp)
}
func (c *Client) DeploymentStats(ctx context.Context) (DeploymentStats, error) {
res, err := c.Request(ctx, http.MethodGet, "/api/v2/deployment/stats", nil)
if err != nil {
return DeploymentStats{}, xerrors.Errorf("execute request: %w", err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return DeploymentStats{}, ReadBodyAsError(res)
}
var df DeploymentStats
return df, json.NewDecoder(res.Body).Decode(&df)
}
type AppearanceConfig struct {
LogoURL string `json:"logo_url"`
ServiceBanner ServiceBannerConfig `json:"service_banner"`
@ -1511,3 +1526,41 @@ func (c *Client) AppHost(ctx context.Context) (AppHostResponse, error) {
var host AppHostResponse
return host, json.NewDecoder(res.Body).Decode(&host)
}
type WorkspaceConnectionLatencyMS struct {
P50 float64
P95 float64
}
type WorkspaceDeploymentStats struct {
Pending int64 `json:"pending"`
Building int64 `json:"building"`
Running int64 `json:"running"`
Failed int64 `json:"failed"`
Stopped int64 `json:"stopped"`
ConnectionLatencyMS WorkspaceConnectionLatencyMS `json:"connection_latency_ms"`
RxBytes int64 `json:"rx_bytes"`
TxBytes int64 `json:"tx_bytes"`
}
type SessionCountDeploymentStats struct {
VSCode int64 `json:"vscode"`
SSH int64 `json:"ssh"`
JetBrains int64 `json:"jetbrains"`
ReconnectingPTY int64 `json:"reconnecting_pty"`
}
type DeploymentStats struct {
// AggregatedFrom is the time in which stats are aggregated from.
// This might be back in time a specific duration or interval.
AggregatedFrom time.Time `json:"aggregated_from" format:"date-time"`
// CollectedAt is the time in which stats are collected at.
CollectedAt time.Time `json:"collected_at" format:"date-time"`
// NextUpdateAt is the time when the next batch of stats will
// be updated.
NextUpdateAt time.Time `json:"next_update_at" format:"date-time"`
Workspaces WorkspaceDeploymentStats `json:"workspaces"`
SessionCount SessionCountDeploymentStats `json:"session_count"`
}