Skip to content

Commit

Permalink
backend: Add metrics endpoints
Browse files Browse the repository at this point in the history
Pull request #656 adds the necessary instance_stats database table as well as functions for querying instance counts (by channel, version, and architecture) from the groups, instance, and instance_application tables and storing the results in the new table.

To make this data accessible outside Nebraska, we create the following:

- Prometheus metrics endpoint: A new HTTP endpoint (instance-metrics/prometheus) that serves only the latest snapshot from the instance_stats table. As Prometheus is a time-series database, this serves instance counts with the latest timestamp only.
- JSON metrics data endpoint: A new HTTP endpoint that emits all instance_stats data in JSON format. The difference here is that we query for all data, and we emit one JSON document per row.
  • Loading branch information
skoeva committed Aug 11, 2023
1 parent b641c2b commit 14fd8f7
Show file tree
Hide file tree
Showing 10 changed files with 487 additions and 76 deletions.
59 changes: 59 additions & 0 deletions backend/api/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,41 @@ paths:
description: Activity not found response
"500":
description: List activity error response
/instance-metrics/prometheus:
get:
description: Get latest instance stats
operationId: getLatestInstanceStats
security:
- oidcBearerAuth: []
- oidcCookieAuth: []
- githubCookieAuth: []
responses:
"200":
description: Get latest instance stats success response
content:
text/plain:
schema:
type: string
"500":
description: Get latest instance stats error response
/instance-metrics/json:
get:
description: Get instance stats
operationId: getInstanceStats
security:
- oidcBearerAuth: []
- oidcCookieAuth: []
- githubCookieAuth: []
responses:
"200":
description: Get instance stats success response
content:
application/x-ndjson:
schema:
$ref: "#/components/schemas/instanceStats"
"500":
description: Get instance stats error response

components:
schemas:
## request Body
Expand Down Expand Up @@ -1339,6 +1374,30 @@ components:
package_id:
type: string

instanceStats:
type: object
required:
- type
- channel
- version
- arch
- timestamp
- instances
properties:
type:
type: string
enum: ["instance_count"]
channel:
type: string
version:
type: string
arch:
type: string
timestamp:
type: string
count:
type: integer


## response
config:
Expand Down
4 changes: 2 additions & 2 deletions backend/pkg/api/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const (

const (
validityInterval postgresDuration = "1 days"
defaultInterval time.Duration = time.Hour
defaultInterval time.Duration = 2 * time.Hour
)

// Instance represents an instance running one or more applications for which
Expand Down Expand Up @@ -651,7 +651,7 @@ func (api *API) GetDefaultInterval() time.Duration {
// that have been checked in during a given duration from a given time.
func (api *API) instanceStatsQuery(t *time.Time, duration *time.Duration) *goqu.SelectDataset {
if t == nil {
now := time.Now()
now := time.Now().UTC()
t = &now
}

Expand Down
35 changes: 35 additions & 0 deletions backend/pkg/api/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ WHERE a.id = e.application_id AND e.event_type_id = et.id AND et.result = 0 AND
GROUP BY app_name
ORDER BY app_name
`, ignoreFakeInstanceCondition("e.instance_id"))

latestInstanceStatsSQL string = `
SELECT channel_name, version, arch, timestamp, instances AS instances_count
FROM instance_stats
WHERE timestamp = (SELECT MAX(timestamp) FROM instance_stats)
`
)

type AppInstancesPerChannelMetric struct {
Expand Down Expand Up @@ -77,6 +83,35 @@ func (api *API) GetFailedUpdatesMetrics() ([]FailedUpdatesMetric, error) {
return metrics, nil
}

type LatestInstanceStatsMetric struct {
ChannelName string `db:"channel_name" json:"channel_name"`
Version string `db:"version" json:"version"`
Arch string `db:"arch" json:"arch"`
Timestamp string `db:"timestamp" json:"timestamp"`
InstancesCount int `db:"instances_count" json:"instances_count"`
}

func (api *API) GetLatestInstanceStatsMetrics() ([]LatestInstanceStatsMetric, error) {
var metrics []LatestInstanceStatsMetric
rows, err := api.db.Queryx(latestInstanceStatsSQL)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var metric LatestInstanceStatsMetric
err := rows.StructScan(&metric)
if err != nil {
return nil, err
}
metrics = append(metrics, metric)
}
if err := rows.Err(); err != nil {
return nil, err
}
return metrics, nil
}

func (api *API) DbStats() sql.DBStats {
return api.db.Stats()
}
182 changes: 182 additions & 0 deletions backend/pkg/codegen/client.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 14fd8f7

Please sign in to comment.