pangolin_exporter

Форк
0
/
pg_process_idle.go 
132 строки · 3.5 Кб
1
// Copyright 2023 The Prometheus Authors
2
// Licensed under the Apache License, Version 2.0 (the "License");
3
// you may not use this file except in compliance with the License.
4
// You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software
9
// distributed under the License is distributed on an "AS IS" BASIS,
10
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
// See the License for the specific language governing permissions and
12
// limitations under the License.
13

14
package collector
15

16
import (
17
	"context"
18
	"database/sql"
19

20
	"github.com/go-kit/log"
21
	"github.com/lib/pq"
22
	"github.com/prometheus/client_golang/prometheus"
23
)
24

25
func init() {
26
	// Making this default disabled because we have no tests for it
27
	registerCollector(processIdleSubsystem, defaultDisabled, NewPGProcessIdleCollector)
28
}
29

30
type PGProcessIdleCollector struct {
31
	log log.Logger
32
}
33

34
const processIdleSubsystem = "process_idle"
35

36
func NewPGProcessIdleCollector(config collectorConfig) (Collector, error) {
37
	return &PGProcessIdleCollector{log: config.logger}, nil
38
}
39

40
var pgProcessIdleSeconds = prometheus.NewDesc(
41
	prometheus.BuildFQName(namespace, processIdleSubsystem, "seconds"),
42
	"Idle time of server processes",
43
	[]string{"state", "application_name"},
44
	prometheus.Labels{},
45
)
46

47
func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
48
	db := instance.getDB()
49
	row := db.QueryRowContext(ctx,
50
		`WITH
51
			metrics AS (
52
				SELECT
53
				state,
54
				application_name,
55
				SUM(EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - state_change))::bigint)::float AS process_idle_seconds_sum,
56
				COUNT(*) AS process_idle_seconds_count
57
				FROM pg_stat_activity
58
				WHERE state ~ '^idle'
59
				GROUP BY state, application_name
60
			),
61
			buckets AS (
62
				SELECT
63
				state,
64
				application_name,
65
				le,
66
				SUM(
67
					CASE WHEN EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - state_change)) <= le
68
					THEN 1
69
					ELSE 0
70
					END
71
				)::bigint AS bucket
72
				FROM
73
				pg_stat_activity,
74
				UNNEST(ARRAY[1, 2, 5, 15, 30, 60, 90, 120, 300]) AS le
75
				GROUP BY state, application_name, le
76
				ORDER BY state, application_name, le
77
			)
78
			SELECT
79
			state,
80
			application_name,
81
			process_idle_seconds_sum as seconds_sum,
82
			process_idle_seconds_count as seconds_count,
83
			ARRAY_AGG(le) AS seconds,
84
			ARRAY_AGG(bucket) AS seconds_bucket
85
			FROM metrics JOIN buckets USING (state, application_name)
86
			GROUP BY 1, 2, 3, 4;`)
87

88
	var state sql.NullString
89
	var applicationName sql.NullString
90
	var secondsSum sql.NullFloat64
91
	var secondsCount sql.NullInt64
92
	var seconds []float64
93
	var secondsBucket []int64
94

95
	err := row.Scan(&state, &applicationName, &secondsSum, &secondsCount, pq.Array(&seconds), pq.Array(&secondsBucket))
96
	if err != nil {
97
		return err
98
	}
99

100
	var buckets = make(map[float64]uint64, len(seconds))
101
	for i, second := range seconds {
102
		if i >= len(secondsBucket) {
103
			break
104
		}
105
		buckets[second] = uint64(secondsBucket[i])
106
	}
107

108
	stateLabel := "unknown"
109
	if state.Valid {
110
		stateLabel = state.String
111
	}
112

113
	applicationNameLabel := "unknown"
114
	if applicationName.Valid {
115
		applicationNameLabel = applicationName.String
116
	}
117

118
	var secondsCountMetric uint64
119
	if secondsCount.Valid {
120
		secondsCountMetric = uint64(secondsCount.Int64)
121
	}
122
	secondsSumMetric := 0.0
123
	if secondsSum.Valid {
124
		secondsSumMetric = secondsSum.Float64
125
	}
126
	ch <- prometheus.MustNewConstHistogram(
127
		pgProcessIdleSeconds,
128
		secondsCountMetric, secondsSumMetric, buckets,
129
		stateLabel, applicationNameLabel,
130
	)
131
	return nil
132
}
133

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.