master
go 278 lines 8.14 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 connectionEntry struct {
14 id string
15 meta *connectionMetrics
16 metrics connectionInstanceMetrics
17 }
18
19 type connectionGroupAggregate struct {
20 Count int64
21
22 State int64
23 Executing int64
24 RowsRead int64
25 RowsWritten int64
26 TotalCPUTime int64
27 LockWaitTime int64
28 LogDiskWaitTime int64
29 LogBufferWaitTime int64
30 PoolReadTime int64
31 PoolWriteTime int64
32 DirectReadTime int64
33 DirectWriteTime int64
34 FCMRecvWaitTime int64
35 FCMSendWaitTime int64
36 RoutineTime int64
37 CompileTime int64
38 SectionTime int64
39 CommitTime int64
40 RollbackTime int64
41 }
42
43 func connectionGroupKey(meta *connectionMetrics) string {
44 if meta == nil {
45 return "__unknown__"
46 }
47 name := strings.TrimSpace(meta.applicationName)
48 if name == "" || name == "-" {
49 name = meta.applicationID
50 }
51 if name == "" {
52 name = "UNKNOWN"
53 }
54 fields := strings.Fields(name)
55 key := strings.ToUpper(fields[0])
56 if key == "" {
57 key = "UNKNOWN"
58 }
59 return key
60 }
61
62 func (a *connectionGroupAggregate) add(m connectionInstanceMetrics) {
63 a.Count++
64 a.State += m.State
65 a.Executing += m.ExecutingQueries
66 a.RowsRead += m.RowsRead
67 a.RowsWritten += m.RowsWritten
68 a.TotalCPUTime += m.TotalCPUTime
69 a.LockWaitTime += m.LockWaitTime
70 a.LogDiskWaitTime += m.LogDiskWaitTime
71 a.LogBufferWaitTime += m.LogBufferWaitTime
72 a.PoolReadTime += m.PoolReadTime
73 a.PoolWriteTime += m.PoolWriteTime
74 a.DirectReadTime += m.DirectReadTime
75 a.DirectWriteTime += m.DirectWriteTime
76 a.FCMRecvWaitTime += m.FCMRecvWaitTime
77 a.FCMSendWaitTime += m.FCMSendWaitTime
78 a.RoutineTime += m.TotalRoutineTime
79 a.CompileTime += m.TotalCompileTime
80 a.SectionTime += m.TotalSectionTime
81 a.CommitTime += m.TotalCommitTime
82 a.RollbackTime += m.TotalRollbackTime
83 }
84
85 func (c *Collector) exportConnectionMetrics() {
86 entries := make([]connectionEntry, 0, len(c.mx.connections))
87 for id, metrics := range c.mx.connections {
88 meta := c.connections[id]
89 entries = append(entries, connectionEntry{
90 id: id,
91 meta: meta,
92 metrics: metrics,
93 })
94 }
95
96 if len(entries) == 0 {
97 c.clearWarnOnce("db2_connection_overflow")
98 return
99 }
100
101 sort.Slice(entries, func(i, j int) bool {
102 return entries[i].id < entries[j].id
103 })
104
105 limit := c.MaxConnections
106 if limit <= 0 || limit > len(entries) {
107 limit = len(entries)
108 }
109
110 groupAgg := make(map[string]*connectionGroupAggregate)
111 overflowAgg := &connectionGroupAggregate{}
112 overflowCount := 0
113 overflowGroups := make(map[string]int)
114 overflowExample := make(map[string]string)
115
116 for idx, entry := range entries {
117 key := connectionGroupKey(entry.meta)
118 agg := groupAgg[key]
119 if agg == nil {
120 agg = &connectionGroupAggregate{}
121 groupAgg[key] = agg
122 }
123 agg.add(entry.metrics)
124
125 if idx < limit {
126 c.emitPerConnectionMetrics(entry)
127 continue
128 }
129
130 overflowAgg.add(entry.metrics)
131 overflowCount++
132 overflowGroups[key]++
133 if _, ok := overflowExample[key]; !ok {
134 overflowExample[key] = entry.id
135 }
136 }
137
138 c.emitConnectionGroupMetrics(groupAgg, overflowAgg, overflowCount)
139
140 if overflowCount > 0 {
141 parts := make([]string, 0, len(overflowGroups))
142 for group, count := range overflowGroups {
143 parts = append(parts, fmt.Sprintf("%s:%d (e.g. %s)", group, count, overflowExample[group]))
144 }
145 sort.Strings(parts)
146 c.warnOnce("db2_connection_overflow", "too many connections for per-connection charts (MaxConnections=%d). Aggregated %d additional connections: %s", c.MaxConnections, overflowCount, strings.Join(parts, ", "))
147 } else {
148 c.clearWarnOnce("db2_connection_overflow")
149 }
150 }
151
152 func (c *Collector) emitPerConnectionMetrics(entry connectionEntry) {
153 labels := contexts.ConnectionLabels{
154 Application_id: entry.id,
155 }
156
157 if entry.meta != nil {
158 if entry.meta.applicationName != "" && entry.meta.applicationName != "-" {
159 labels.Application_name = entry.meta.applicationName
160 }
161 if entry.meta.clientHostname != "" && entry.meta.clientHostname != "-" {
162 labels.Client_hostname = entry.meta.clientHostname
163 }
164 if entry.meta.clientIP != "" && entry.meta.clientIP != "-" {
165 labels.Client_ip = entry.meta.clientIP
166 }
167 if entry.meta.clientUser != "" && entry.meta.clientUser != "-" {
168 labels.Client_user = entry.meta.clientUser
169 }
170 if entry.meta.connectionState != "" {
171 labels.State = entry.meta.connectionState
172 }
173 }
174
175 contexts.Connection.State.Set(c.State, labels, contexts.ConnectionStateValues{
176 State: entry.metrics.State,
177 })
178
179 contexts.Connection.Activity.Set(c.State, labels, contexts.ConnectionActivityValues{
180 Read: entry.metrics.RowsRead,
181 Written: entry.metrics.RowsWritten,
182 })
183
184 contexts.Connection.WaitTime.Set(c.State, labels, contexts.ConnectionWaitTimeValues{
185 Lock: entry.metrics.LockWaitTime,
186 Log_disk: entry.metrics.LogDiskWaitTime,
187 Log_buffer: entry.metrics.LogBufferWaitTime,
188 Pool_read: entry.metrics.PoolReadTime,
189 Pool_write: entry.metrics.PoolWriteTime,
190 Direct_read: entry.metrics.DirectReadTime,
191 Direct_write: entry.metrics.DirectWriteTime,
192 Fcm_recv: entry.metrics.FCMRecvWaitTime,
193 Fcm_send: entry.metrics.FCMSendWaitTime,
194 })
195
196 contexts.Connection.ProcessingTime.Set(c.State, labels, contexts.ConnectionProcessingTimeValues{
197 Routine: entry.metrics.TotalRoutineTime,
198 Compile: entry.metrics.TotalCompileTime,
199 Section: entry.metrics.TotalSectionTime,
200 Commit: entry.metrics.TotalCommitTime,
201 Rollback: entry.metrics.TotalRollbackTime,
202 })
203 }
204
205 func (c *Collector) emitConnectionGroupMetrics(groups map[string]*connectionGroupAggregate, overflow *connectionGroupAggregate, overflowCount int) {
206 keys := make([]string, 0, len(groups))
207 for k := range groups {
208 keys = append(keys, k)
209 }
210 sort.Strings(keys)
211
212 for _, key := range keys {
213 agg := groups[key]
214 labels := contexts.ConnectionGroupLabels{Group: key}
215
216 contexts.ConnectionGroup.Count.Set(c.State, labels, contexts.ConnectionGroupCountValues{
217 Count: agg.Count,
218 })
219
220 contexts.ConnectionGroup.State.Set(c.State, labels, contexts.ConnectionGroupStateValues{
221 State: agg.State,
222 })
223
224 contexts.ConnectionGroup.Activity.Set(c.State, labels, contexts.ConnectionGroupActivityValues{
225 Read: agg.RowsRead,
226 Written: agg.RowsWritten,
227 })
228
229 contexts.ConnectionGroup.WaitTime.Set(c.State, labels, contexts.ConnectionGroupWaitTimeValues{
230 Lock: agg.LockWaitTime,
231 Log_disk: agg.LogDiskWaitTime,
232 Log_buffer: agg.LogBufferWaitTime,
233 Pool_read: agg.PoolReadTime,
234 Pool_write: agg.PoolWriteTime,
235 Direct_read: agg.DirectReadTime,
236 Direct_write: agg.DirectWriteTime,
237 Fcm_recv: agg.FCMRecvWaitTime,
238 Fcm_send: agg.FCMSendWaitTime,
239 })
240
241 contexts.ConnectionGroup.ProcessingTime.Set(c.State, labels, contexts.ConnectionGroupProcessingTimeValues{
242 Routine: agg.RoutineTime,
243 Compile: agg.CompileTime,
244 Section: agg.SectionTime,
245 Commit: agg.CommitTime,
246 Rollback: agg.RollbackTime,
247 })
248 }
249
250 if overflowCount > 0 && overflow != nil && overflow.Count > 0 {
251 labels := contexts.ConnectionGroupLabels{Group: "__other__"}
252
253 contexts.ConnectionGroup.Count.Set(c.State, labels, contexts.ConnectionGroupCountValues{Count: overflow.Count})
254 contexts.ConnectionGroup.State.Set(c.State, labels, contexts.ConnectionGroupStateValues{State: overflow.State})
255 contexts.ConnectionGroup.Activity.Set(c.State, labels, contexts.ConnectionGroupActivityValues{
256 Read: overflow.RowsRead,
257 Written: overflow.RowsWritten,
258 })
259 contexts.ConnectionGroup.WaitTime.Set(c.State, labels, contexts.ConnectionGroupWaitTimeValues{
260 Lock: overflow.LockWaitTime,
261 Log_disk: overflow.LogDiskWaitTime,
262 Log_buffer: overflow.LogBufferWaitTime,
263 Pool_read: overflow.PoolReadTime,
264 Pool_write: overflow.PoolWriteTime,
265 Direct_read: overflow.DirectReadTime,
266 Direct_write: overflow.DirectWriteTime,
267 Fcm_recv: overflow.FCMRecvWaitTime,
268 Fcm_send: overflow.FCMSendWaitTime,
269 })
270 contexts.ConnectionGroup.ProcessingTime.Set(c.State, labels, contexts.ConnectionGroupProcessingTimeValues{
271 Routine: overflow.RoutineTime,
272 Compile: overflow.CompileTime,
273 Section: overflow.SectionTime,
274 Commit: overflow.CommitTime,
275 Rollback: overflow.RollbackTime,
276 })
277 }
278 }