Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions agent/agents/postgres/pgstatmonitor/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ type pgStatMonitorSettingsTextValue struct {
Value string `reform:"value"`
}

// pgStatMonitorErrors represents a row in pg_stat_monitor_errors view.
//
//reform:pg_stat_monitor_errors
type pgStatMonitorErrors struct {
Severity string `reform:"severity"`
Message string `reform:"message"`
MessageTime string `reform:"msgtime"`
Calls int64 `reform:"calls"`
}

// pgStatMonitorExtended contains pgStatMonitor data and extends it with database, username and tables data.
// It's made for performance reason.
type pgStatMonitorExtended struct {
Expand Down
91 changes: 91 additions & 0 deletions agent/agents/postgres/pgstatmonitor/models_reform.go

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

60 changes: 60 additions & 0 deletions agent/agents/postgres/pgstatmonitor/pgstatmonitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type PGStatMonitorQAN struct {
changes chan agents.Change
monitorCache *statMonitorCache
disableQueryExamples bool
waitTime time.Duration
}

// Params represent Agent parameters.
Expand Down Expand Up @@ -254,6 +255,8 @@ func (m *PGStatMonitorQAN) Run(ctx context.Context) {
}
running = m.checkDefaultWaitTime(waitTime)

m.waitTime = waitTime

// query pg_stat_monitor every waitTime seconds
start := time.Now()
m.l.Debugf("Scheduling next collection in %s at %s.", waitTime, start.Add(waitTime).Format("15:04:05"))
Expand Down Expand Up @@ -299,6 +302,8 @@ func (m *PGStatMonitorQAN) Run(ctx context.Context) {
continue
}

m.waitTime = waitTime

lengthS := uint32(waitTime.Seconds())
buckets, err := m.getNewBuckets(ctx, lengthS, normalizedQuery)

Expand Down Expand Up @@ -407,6 +412,11 @@ func (m *PGStatMonitorQAN) getNewBuckets(ctx context.Context, periodLengthSecs u
return nil, err
}

err = m.checkErrorsView(ctx)
if err != nil {
return nil, err
}

buckets := m.makeBuckets(current, prev)
m.l.Debugf("Made %d buckets out of %d stat monitor in %d interval.",
len(buckets), len(current), periodLengthSecs)
Expand All @@ -426,6 +436,56 @@ func (m *PGStatMonitorQAN) getNewBuckets(ctx context.Context, periodLengthSecs u
return buckets, nil
}

func (m *PGStatMonitorQAN) checkErrorsView(ctx context.Context) error {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci-lint] reported by reviewdog 🐶
calculated cyclomatic complexity for function checkErrorsView is 12, max is 10 (cyclop)

vPGSM, _, err := getPGMonitorVersion(m.q)
if err != nil {
return errors.Wrap(err, "failed to get row and view for pg_stat_monitor version")
}

// Errors view is supported in PGSM 2.0 and higher.
if vPGSM < pgStatMonitorVersion20PG12 {
return nil
}

row := &pgStatMonitorErrors{}
rows, err := m.q.SelectRows(pgStatMonitorErrorsView, "")
if err != nil {
return errors.Wrap(err, "failed to query pg_stat_monitor_errors view")
}

now := time.Now()
for ctx.Err() == nil {
if err = m.q.NextRow(row, rows); err != nil {
if errors.Is(err, reform.ErrNoRows) {
break
}

return errors.Wrap(err, "cannot read row from errors view")
}

messageTime, err := time.Parse("2006-01-02 15:04:05", row.MessageTime)
if err != nil {
return errors.Wrap(err, "cannot parse messageTime")
}

if now.After(messageTime.Add(m.waitTime)) {
continue
}

template := "Message: %s, Calls: %d"
switch row.Severity {
case "INFO":
m.l.Infof(template, row.Message, row.Calls)
case "WARNING":
m.l.Warningf(template, row.Message, row.Calls)
case "ERROR":
m.l.Errorf(template, row.Message, row.Calls)
}
}

return nil
}

// makeBuckets uses current state of pg_stat_monitor table and accumulated previous state
// to make metrics buckets.
func (m *PGStatMonitorQAN) makeBuckets(current, cache map[time.Time]map[string]*pgStatMonitorExtended) []*agentpb.MetricsBucket {
Expand Down