master
go 127 lines 3.07 KB
Raw
1 //go:build cgo
2
3 package db2
4
5 import (
6 "fmt"
7 "sort"
8 "strings"
9
10 "github.com/netdata/netdata/go/plugins/plugin/ibm.d/modules/db2/contexts"
11 )
12
13 type indexEntry struct {
14 name string
15 metrics indexInstanceMetrics
16 }
17
18 type indexGroupAggregate struct {
19 LeafNodes int64
20 IndexScans int64
21 FullScans int64
22 }
23
24 func indexGroupKey(name string) string {
25 if idx := strings.Index(name, "."); idx > 0 {
26 return name[:idx]
27 }
28 return name
29 }
30
31 func (a *indexGroupAggregate) add(m indexInstanceMetrics) {
32 a.LeafNodes += m.LeafNodes
33 a.IndexScans += m.IndexScans
34 a.FullScans += m.FullScans
35 }
36
37 func (c *Collector) exportIndexMetrics() {
38 entries := make([]indexEntry, 0, len(c.mx.indexes))
39 for name, metrics := range c.mx.indexes {
40 entries = append(entries, indexEntry{name: name, metrics: metrics})
41 }
42
43 if len(entries) == 0 {
44 c.clearWarnOnce("db2_index_overflow")
45 return
46 }
47
48 sort.Slice(entries, func(i, j int) bool {
49 return entries[i].name < entries[j].name
50 })
51
52 limit := c.MaxIndexes
53 if limit <= 0 || limit > len(entries) {
54 limit = len(entries)
55 }
56
57 groupAgg := make(map[string]*indexGroupAggregate)
58 overflowAgg := &indexGroupAggregate{}
59 overflowCount := 0
60 overflowGroups := make(map[string]int)
61 overflowExample := make(map[string]string)
62
63 for idx, entry := range entries {
64 key := indexGroupKey(entry.name)
65 agg := groupAgg[key]
66 if agg == nil {
67 agg = &indexGroupAggregate{}
68 groupAgg[key] = agg
69 }
70 agg.add(entry.metrics)
71
72 if idx < limit {
73 labels := contexts.IndexLabels{Index: entry.name}
74 contexts.Index.Usage.Set(c.State, labels, contexts.IndexUsageValues{
75 Index: entry.metrics.IndexScans,
76 Full: entry.metrics.FullScans,
77 })
78 continue
79 }
80
81 overflowAgg.add(entry.metrics)
82 overflowCount++
83 overflowGroups[key]++
84 if _, ok := overflowExample[key]; !ok {
85 overflowExample[key] = entry.name
86 }
87 }
88
89 c.emitIndexGroupMetrics(groupAgg, overflowAgg, overflowCount)
90
91 if overflowCount > 0 {
92 parts := make([]string, 0, len(overflowGroups))
93 for group, count := range overflowGroups {
94 parts = append(parts, fmt.Sprintf("%s:%d (e.g. %s)", group, count, overflowExample[group]))
95 }
96 sort.Strings(parts)
97 c.warnOnce("db2_index_overflow", "too many indexes for per-instance charts (MaxIndexes=%d). Aggregated %d additional indexes: %s", c.MaxIndexes, overflowCount, strings.Join(parts, ", "))
98 } else {
99 c.clearWarnOnce("db2_index_overflow")
100 }
101 }
102
103 func (c *Collector) emitIndexGroupMetrics(groups map[string]*indexGroupAggregate, overflow *indexGroupAggregate, overflowCount int) {
104 keys := make([]string, 0, len(groups))
105 for k := range groups {
106 keys = append(keys, k)
107 }
108 sort.Strings(keys)
109
110 for _, key := range keys {
111 agg := groups[key]
112 labels := contexts.IndexGroupLabels{Group: key}
113
114 contexts.IndexGroup.Usage.Set(c.State, labels, contexts.IndexGroupUsageValues{
115 Index: agg.IndexScans,
116 Full: agg.FullScans,
117 })
118 }
119
120 if overflowCount > 0 && overflow != nil {
121 labels := contexts.IndexGroupLabels{Group: "__other__"}
122 contexts.IndexGroup.Usage.Set(c.State, labels, contexts.IndexGroupUsageValues{
123 Index: overflow.IndexScans,
124 Full: overflow.FullScans,
125 })
126 }
127 }