master
go 149 lines 3.75 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 tableEntry struct {
14 name string
15 metrics tableInstanceMetrics
16 }
17
18 type tableGroupAggregate struct {
19 DataSize int64
20 IndexSize int64
21 LongObjSize int64
22 RowsRead int64
23 RowsWritten int64
24 Count int64
25 }
26
27 func tableGroupKey(name string) string {
28 if idx := strings.Index(name, "."); idx > 0 {
29 return name[:idx]
30 }
31 return name
32 }
33
34 func (a *tableGroupAggregate) add(m tableInstanceMetrics) {
35 a.Count++
36 a.DataSize += m.DataSize
37 a.IndexSize += m.IndexSize
38 a.LongObjSize += m.LongObjSize
39 a.RowsRead += m.RowsRead
40 a.RowsWritten += m.RowsWritten
41 }
42
43 func (c *Collector) exportTableMetrics() {
44 entries := make([]tableEntry, 0, len(c.mx.tables))
45 for name, metrics := range c.mx.tables {
46 entries = append(entries, tableEntry{name: name, metrics: metrics})
47 }
48
49 if len(entries) == 0 {
50 c.clearWarnOnce("db2_table_overflow")
51 return
52 }
53
54 sort.Slice(entries, func(i, j int) bool {
55 return entries[i].name < entries[j].name
56 })
57
58 limit := c.MaxTables
59 if limit <= 0 || limit > len(entries) {
60 limit = len(entries)
61 }
62
63 groupAgg := make(map[string]*tableGroupAggregate)
64 overflowAgg := &tableGroupAggregate{}
65 overflowCount := 0
66 overflowGroups := make(map[string]int)
67 overflowExample := make(map[string]string)
68
69 for idx, entry := range entries {
70 key := tableGroupKey(entry.name)
71 agg := groupAgg[key]
72 if agg == nil {
73 agg = &tableGroupAggregate{}
74 groupAgg[key] = agg
75 }
76 agg.add(entry.metrics)
77
78 if idx < limit {
79 labels := contexts.TableLabels{Table: entry.name}
80 contexts.Table.Size.Set(c.State, labels, contexts.TableSizeValues{
81 Data: entry.metrics.DataSize,
82 Index: entry.metrics.IndexSize,
83 Long_obj: entry.metrics.LongObjSize,
84 })
85 contexts.Table.Activity.Set(c.State, labels, contexts.TableActivityValues{
86 Read: entry.metrics.RowsRead,
87 Written: entry.metrics.RowsWritten,
88 })
89 continue
90 }
91
92 overflowAgg.add(entry.metrics)
93 overflowCount++
94 overflowGroups[key]++
95 if _, ok := overflowExample[key]; !ok {
96 overflowExample[key] = entry.name
97 }
98 }
99
100 c.emitTableGroupMetrics(groupAgg, overflowAgg, overflowCount)
101
102 if overflowCount > 0 {
103 parts := make([]string, 0, len(overflowGroups))
104 for group, count := range overflowGroups {
105 parts = append(parts, fmt.Sprintf("%s:%d (e.g. %s)", group, count, overflowExample[group]))
106 }
107 sort.Strings(parts)
108 c.warnOnce("db2_table_overflow", "too many tables for per-instance charts (MaxTables=%d). Aggregated %d additional tables: %s", c.MaxTables, overflowCount, strings.Join(parts, ", "))
109 } else {
110 c.clearWarnOnce("db2_table_overflow")
111 }
112 }
113
114 func (c *Collector) emitTableGroupMetrics(groups map[string]*tableGroupAggregate, overflow *tableGroupAggregate, overflowCount int) {
115 keys := make([]string, 0, len(groups))
116 for k := range groups {
117 keys = append(keys, k)
118 }
119 sort.Strings(keys)
120
121 for _, key := range keys {
122 agg := groups[key]
123 labels := contexts.TableGroupLabels{Group: key}
124
125 contexts.TableGroup.Size.Set(c.State, labels, contexts.TableGroupSizeValues{
126 Data: agg.DataSize,
127 Index: agg.IndexSize,
128 Long_obj: agg.LongObjSize,
129 })
130
131 contexts.TableGroup.Activity.Set(c.State, labels, contexts.TableGroupActivityValues{
132 Read: agg.RowsRead,
133 Written: agg.RowsWritten,
134 })
135 }
136
137 if overflowCount > 0 && overflow != nil {
138 labels := contexts.TableGroupLabels{Group: "__other__"}
139 contexts.TableGroup.Size.Set(c.State, labels, contexts.TableGroupSizeValues{
140 Data: overflow.DataSize,
141 Index: overflow.IndexSize,
142 Long_obj: overflow.LongObjSize,
143 })
144 contexts.TableGroup.Activity.Set(c.State, labels, contexts.TableGroupActivityValues{
145 Read: overflow.RowsRead,
146 Written: overflow.RowsWritten,
147 })
148 }
149 }