Skip to content

Commit

Permalink
[receiver/postgresql] Add Index Metrics (#13168)
Browse files Browse the repository at this point in the history
Add index metrics
  • Loading branch information
schmikei committed Aug 11, 2022
1 parent e11aa63 commit 5550277
Show file tree
Hide file tree
Showing 11 changed files with 1,332 additions and 147 deletions.
52 changes: 52 additions & 0 deletions receiver/postgresqlreceiver/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,17 @@ type databaseName string
// i.e. database1|table2
type tableIdentifier string

// indexIdentifier is a unique string that identifies a particular index and is separated by the "|" character
type indexIdentifer string

type client interface {
Close() error
getDatabaseStats(ctx context.Context, databases []string) (map[databaseName]databaseStats, error)
getBackends(ctx context.Context, databases []string) (map[databaseName]int64, error)
getDatabaseSize(ctx context.Context, databases []string) (map[databaseName]int64, error)
getDatabaseTableMetrics(ctx context.Context, db string) (map[tableIdentifier]tableStats, error)
getBlocksReadByTable(ctx context.Context, db string) (map[tableIdentifier]tableIOStats, error)
getIndexStats(ctx context.Context, database string) (map[indexIdentifer]indexStat, error)
listDatabases(ctx context.Context) ([]string, error)
}

Expand Down Expand Up @@ -307,6 +311,50 @@ func (c *postgreSQLClient) getBlocksReadByTable(ctx context.Context, db string)
return tios, errors
}

type indexStat struct {
index string
table string
database string
size int64
scans int64
}

func (c *postgreSQLClient) getIndexStats(ctx context.Context, database string) (map[indexIdentifer]indexStat, error) {
query := `SELECT relname, indexrelname,
pg_relation_size(indexrelid) AS index_size,
idx_scan
FROM pg_stat_user_indexes;`

stats := map[indexIdentifer]indexStat{}

rows, err := c.client.QueryContext(ctx, query)
if err != nil {
return nil, err
}
defer rows.Close()

var errs []error
for rows.Next() {
var (
table, index string
indexSize, indexScans int64
)
err := rows.Scan(&table, &index, &indexSize, &indexScans)
if err != nil {
errs = append(errs, err)
continue
}
stats[indexKey(database, table, index)] = indexStat{
index: index,
table: table,
database: database,
size: indexSize,
scans: indexScans,
}
}
return stats, multierr.Combine(errs...)
}

func (c *postgreSQLClient) listDatabases(ctx context.Context) ([]string, error) {
query := `SELECT datname FROM pg_database
WHERE datistemplate = false;`
Expand Down Expand Up @@ -350,3 +398,7 @@ func filterQueryByDatabases(baseQuery string, databases []string, groupBy bool)
func tableKey(database, table string) tableIdentifier {
return tableIdentifier(fmt.Sprintf("%s|%s", database, table))
}

func indexKey(database, table, index string) indexIdentifer {
return indexIdentifer(fmt.Sprintf("%s|%s|%s", database, table, index))
}
3 changes: 3 additions & 0 deletions receiver/postgresqlreceiver/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ These are the metrics available for this scraper.
| **postgresql.blocks_read** | The number of blocks read. | 1 | Sum(Int) | <ul> <li>database</li> <li>table</li> <li>source</li> </ul> |
| **postgresql.commits** | The number of commits. | 1 | Sum(Int) | <ul> <li>database</li> </ul> |
| **postgresql.db_size** | The database disk usage. | By | Sum(Int) | <ul> <li>database</li> </ul> |
| **postgresql.index.scans** | The number of index scans on a table. | {scans} | Sum(Int) | <ul> </ul> |
| **postgresql.index.size** | The size of the index on disk. | By | Gauge(Int) | <ul> </ul> |
| **postgresql.operations** | The number of db row operations. | 1 | Sum(Int) | <ul> <li>database</li> <li>table</li> <li>operation</li> </ul> |
| **postgresql.rollbacks** | The number of rollbacks. | 1 | Sum(Int) | <ul> <li>database</li> </ul> |
| **postgresql.rows** | The number of rows in the database. | 1 | Sum(Int) | <ul> <li>database</li> <li>table</li> <li>state</li> </ul> |
Expand All @@ -30,6 +32,7 @@ metrics:
| Name | Description | Type |
| ---- | ----------- | ---- |
| postgresql.database.name | The name of the database. | String |
| postgresql.index.name | The name of the index on a table. | String |
| postgresql.table.name | The schema name followed by the table name. | String |

## Metric attributes
Expand Down
131 changes: 131 additions & 0 deletions receiver/postgresqlreceiver/internal/metadata/generated_metrics_v2.go

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

19 changes: 19 additions & 0 deletions receiver/postgresqlreceiver/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ resource_attributes:
postgresql.table.name:
description: The schema name followed by the table name.
type: string
postgresql.index.name:
description: The name of the index on a table.
type: string

attributes:
database:
Expand Down Expand Up @@ -79,6 +82,22 @@ metrics:
monotonic: false
aggregation: cumulative
attributes: [database, table, state]
postgresql.index.scans:
attributes: []
description: The number of index scans on a table.
enabled: true
sum:
aggregation: cumulative
monotonic: true
value_type: int
unit: "{scans}"
postgresql.index.size:
attributes: []
description: The size of the index on disk.
enabled: true
gauge:
value_type: int
unit: "By"
postgresql.operations:
enabled: true
description: The number of db row operations.
Expand Down
28 changes: 28 additions & 0 deletions receiver/postgresqlreceiver/scraper.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ func (p *postgreSQLScraper) scrape(ctx context.Context) (pmetric.Metrics, error)
defer dbClient.Close()
p.recordDatabase(now, database, r)
p.collectTables(ctx, now, dbClient, database, &errs)

if p.emitMetricsWithResourceAttributes {
p.collectIndexes(ctx, now, dbClient, database, &errs)
}
}

return p.mb.Emit(), errs.Combine()
Expand Down Expand Up @@ -253,6 +257,30 @@ func (p *postgreSQLScraper) collectTables(ctx context.Context, now pcommon.Times
}
}

func (p *postgreSQLScraper) collectIndexes(
ctx context.Context,
now pcommon.Timestamp,
client client,
database string,
errs *scrapererror.ScrapeErrors,
) {
idxStats, err := client.getIndexStats(ctx, database)
if err != nil {
errs.AddPartial(1, err)
return
}

for _, stat := range idxStats {
p.mb.RecordPostgresqlIndexScansDataPoint(now, stat.scans)
p.mb.RecordPostgresqlIndexSizeDataPoint(now, stat.size)
p.mb.EmitForResource(
metadata.WithPostgresqlDatabaseName(stat.database),
metadata.WithPostgresqlTableName(stat.table),
metadata.WithPostgresqlIndexName(stat.index),
)
}
}

func (p *postgreSQLScraper) retrieveDatabaseStats(
ctx context.Context,
wg *sync.WaitGroup,
Expand Down
Loading

0 comments on commit 5550277

Please sign in to comment.