Skip to content

Commit

Permalink
introspection: database metrics for notifier
Browse files Browse the repository at this point in the history
implements prometheus database metrics per our specification:
#1167

Signed-off-by: ldelossa <ldelossa@redhat.com>
  • Loading branch information
ldelossa authored and ldelossa committed Mar 31, 2021
1 parent 21dc720 commit 1ece08f
Show file tree
Hide file tree
Showing 11 changed files with 345 additions and 5 deletions.
35 changes: 34 additions & 1 deletion notifier/postgres/created.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,50 @@ package postgres

import (
"context"
"time"

"github.com/google/uuid"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
clairerror "github.com/quay/clair/v4/clair-error"
)

var (
createdCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Namespace: "clair",
Subsystem: "notifier",
Name: "created_total",
Help: "Total number of database queries issued in the created method.",
},
[]string{"query"},
)
createdDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: "clair",
Subsystem: "notifier",
Name: "created_duration_seconds",
Help: "The duration of all queries issued in the created method",
},
[]string{"query"},
)
)

// created will return all notification ids in "created" status
func created(ctx context.Context, pool *pgxpool.Pool) ([]uuid.UUID, error) {
const (
query = `SELECT notification_id FROM receipt WHERE status = 'created'`
)

ids := make([]uuid.UUID, 0, 0)
rows, _ := pool.Query(ctx, query)
start := time.Now()
rows, err := pool.Query(ctx, query)
if err != nil {
return nil, clairerror.ErrCreated{err}
}
createdCounter.WithLabelValues("query").Add(1)
createdDuration.WithLabelValues("query").Observe(time.Since(start).Seconds())
defer rows.Close()
for rows.Next() {
var id uuid.UUID
Expand All @@ -25,6 +55,9 @@ func created(ctx context.Context, pool *pgxpool.Pool) ([]uuid.UUID, error) {
}
ids = append(ids, id)
}
if err := rows.Err(); err != nil {
return nil, clairerror.ErrCreated{err}
}

return ids, nil
}
32 changes: 31 additions & 1 deletion notifier/postgres/deleted.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,50 @@ package postgres

import (
"context"
"time"

"github.com/google/uuid"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
clairerror "github.com/quay/clair/v4/clair-error"
)

var (
deletedCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Namespace: "clair",
Subsystem: "notifier",
Name: "deleted_total",
Help: "Total number of database queries issued in the deleted method.",
},
[]string{"query"},
)
deletedDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: "clair",
Subsystem: "notifier",
Name: "deleted_duration_seconds",
Help: "The duration of all queries issued in the deleted method",
},
[]string{"query"},
)
)

// deleted will return all notification ids in "deleted" status
func deleted(ctx context.Context, pool *pgxpool.Pool) ([]uuid.UUID, error) {
const (
query = `SELECT notification_id FROM receipt WHERE status = 'deleted'`
)

ids := make([]uuid.UUID, 0, 0)
rows, _ := pool.Query(ctx, query)
start := time.Now()
rows, err := pool.Query(ctx, query)
if err != nil {
return nil, clairerror.ErrCreated{err}
}
deletedCounter.WithLabelValues("query").Add(1)
deletedDuration.WithLabelValues("query").Observe(time.Since(start).Seconds())
defer rows.Close()
for rows.Next() {
var id uuid.UUID
Expand Down
33 changes: 33 additions & 0 deletions notifier/postgres/deletenotifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,40 @@ package postgres

import (
"context"
"time"

"github.com/google/uuid"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/quay/zlog"
"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/label"

clairerror "github.com/quay/clair/v4/clair-error"
)

var (
deleteNotificationsCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Namespace: "clair",
Subsystem: "notifier",
Name: "deletenotifications_total",
Help: "Total number of database queries issued in the deleteNotifications method.",
},
[]string{"query"},
)
deleteNotificationsDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: "clair",
Subsystem: "notifier",
Name: "deletenotifications_duration_seconds",
Help: "The duration of all queries issued in the deleteNotifications method",
},
[]string{"query"},
)
)

// deleteNotifications garbage collects notifications and their associated
// id and receipt rows
func deleteNotifications(ctx context.Context, pool *pgxpool.Pool, id uuid.UUID) error {
Expand All @@ -31,26 +55,35 @@ func deleteNotifications(ctx context.Context, pool *pgxpool.Pool, id uuid.UUID)
return clairerror.ErrDeleteNotification{id, err}
}

start := time.Now()
tag, err := tx.Exec(ctx, deleteNotifications, id.String())
if err != nil {
return clairerror.ErrDeleteNotification{id, err}
}
deleteNotificationsCounter.WithLabelValues("deleteNotifications").Add(1)
deleteNotificationsDuration.WithLabelValues("deleteNotifications").Observe(time.Since(start).Seconds())
if tag.RowsAffected() <= 0 {
zlog.Warn(ctx).Msg("no notification bodies deleted")
}

start = time.Now()
tag, err = tx.Exec(ctx, deleteReceipt, id.String())
if err != nil {
return clairerror.ErrDeleteNotification{id, err}
}
deleteNotificationsCounter.WithLabelValues("deleteReceipt").Add(1)
deleteNotificationsDuration.WithLabelValues("deleteReceipt").Observe(time.Since(start).Seconds())
if tag.RowsAffected() <= 0 {
zlog.Warn(ctx).Msg("no notification receipt deleted")
}

start = time.Now()
tag, err = tx.Exec(ctx, deleteNotificationID, id.String())
if err != nil {
return clairerror.ErrDeleteNotification{id, err}
}
deleteNotificationsCounter.WithLabelValues("deleteNotificationID").Add(1)
deleteNotificationsDuration.WithLabelValues("deleteNotificationID").Observe(time.Since(start).Seconds())
if tag.RowsAffected() <= 0 {
zlog.Warn(ctx).Msg("no notification id deleted")
}
Expand Down
35 changes: 34 additions & 1 deletion notifier/postgres/failed.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,50 @@ package postgres

import (
"context"
"time"

"github.com/google/uuid"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
clairerror "github.com/quay/clair/v4/clair-error"
)

var (
failedCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Namespace: "clair",
Subsystem: "notifier",
Name: "failed_total",
Help: "Total number of database queries issued in the failed method.",
},
[]string{"query"},
)
failedDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: "clair",
Subsystem: "notifier",
Name: "failed_duration_seconds",
Help: "The duration of all queries issued in the failed method",
},
[]string{"query"},
)
)

// created will return all notification ids in "failed" status
func failed(ctx context.Context, pool *pgxpool.Pool) ([]uuid.UUID, error) {
const (
query = `SELECT notification_id FROM receipt WHERE status = 'delivery_failed'`
)

ids := make([]uuid.UUID, 0, 0)
rows, _ := pool.Query(ctx, query)
start := time.Now()
rows, err := pool.Query(ctx, query)
if err != nil {
return nil, clairerror.ErrFailed{err}
}
failedCounter.WithLabelValues("query").Add(1)
failedDuration.WithLabelValues("query").Observe(time.Since(start).Seconds())
defer rows.Close()
for rows.Next() {
var id uuid.UUID
Expand All @@ -25,6 +55,9 @@ func failed(ctx context.Context, pool *pgxpool.Pool) ([]uuid.UUID, error) {
}
ids = append(ids, id)
}
if err := rows.Err(); err != nil {
return nil, clairerror.ErrFailed{err}
}

return ids, nil
}
47 changes: 45 additions & 2 deletions notifier/postgres/notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,38 @@ package postgres

import (
"context"
"time"

"github.com/google/uuid"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"

clairerror "github.com/quay/clair/v4/clair-error"
"github.com/quay/clair/v4/notifier"
)

var (
notificationsCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Namespace: "clair",
Subsystem: "notifier",
Name: "notifications_total",
Help: "Total number of database queries issued in the notifications method.",
},
[]string{"query"},
)
notificationsDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: "clair",
Subsystem: "notifier",
Name: "notifications_duration_seconds",
Help: "The duration of all queries issued in the notifications method",
},
[]string{"query"},
)
)

func notifications(ctx context.Context, pool *pgxpool.Pool, id uuid.UUID, page *notifier.Page) ([]notifier.Notification, notifier.Page, error) {
const (
query = "SELECT id, body FROM notification_body WHERE notification_id = $1"
Expand All @@ -20,7 +44,13 @@ func notifications(ctx context.Context, pool *pgxpool.Pool, id uuid.UUID, page *
if page == nil {
p := notifier.Page{}
notifications := make([]notifier.Notification, 0, 0)
rows, _ := pool.Query(ctx, query, id.String())
start := time.Now()
rows, err := pool.Query(ctx, query, id.String())
if err != nil {
return nil, notifier.Page{}, clairerror.ErrBadNotification{id, err}
}
notificationsCounter.WithLabelValues("query").Add(1)
notificationsDuration.WithLabelValues("query").Observe(time.Since(start).Seconds())
defer rows.Close()
for rows.Next() {
var n notifier.Notification
Expand All @@ -30,6 +60,9 @@ func notifications(ctx context.Context, pool *pgxpool.Pool, id uuid.UUID, page *
}
notifications = append(notifications, n)
}
if err := rows.Err(); err != nil {
return nil, notifier.Page{}, clairerror.ErrBadNotification{id, err}
}
return notifications, p, nil
}

Expand All @@ -48,8 +81,15 @@ func notifications(ctx context.Context, pool *pgxpool.Pool, id uuid.UUID, page *
// another page to fetch
limit := page.Size + 1

start := time.Now()
notifications := make([]notifier.Notification, 0, limit)
rows, _ := pool.Query(ctx, pagedQuery, id, page.Next, limit)
rows, err := pool.Query(ctx, pagedQuery, id, page.Next, limit)
if err != nil {
return nil, notifier.Page{}, clairerror.ErrBadNotification{id, err}
}
notificationsCounter.WithLabelValues("pagedQuery").Add(1)
notificationsDuration.WithLabelValues("pagedQuery").Observe(time.Since(start).Seconds())

defer rows.Close()
for rows.Next() {
var n notifier.Notification
Expand All @@ -59,6 +99,9 @@ func notifications(ctx context.Context, pool *pgxpool.Pool, id uuid.UUID, page *
}
notifications = append(notifications, n)
}
if err := rows.Err(); err != nil {
return nil, notifier.Page{}, clairerror.ErrBadNotification{id, err}
}

morePages := uint64(len(notifications)) == limit
if morePages {
Expand Down

0 comments on commit 1ece08f

Please sign in to comment.