1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+package mssql
4
+
5
+import (
6
+ "fmt"
7
+ "strings"
8
+
9
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
10
+)
11
+
12
+const (
13
+ prioUserConnections = module.Priority + iota
14
+ prioSessionConnections
15
+ prioBlockedProcesses
16
+
17
+ prioBatchRequests
18
+ prioCompilations
19
+ prioRecompilations
20
+ prioAutoParamAttempts
21
+ prioSQLErrors
22
+
23
+ prioBufferCacheHitRatio
24
+ prioBufferPageIOPS
25
+ prioBufferCheckpointPages
26
+ prioBufferPageLifeExpectancy
27
+ prioBufferLazyWrites
28
+ prioBufferPageLookups
29
+
30
+ prioPageSplits
31
+
32
+ prioMemoryTotal
33
+ prioMemoryConnection
34
+ prioMemoryPendingGrants
35
+ prioMemoryExternalBenefit
36
+
37
+ prioProcessMemoryResident
38
+ prioProcessMemoryVirtual
39
+ prioProcessMemoryUtilization
40
+ prioProcessPageFaults
41
+
42
+ prioOSMemory
43
+ prioOSPageFile
44
+
45
+ prioDatabaseActiveTransactions
46
+ prioDatabaseTransactions
47
+ prioDatabaseWriteTransactions
48
+ prioDatabaseLogFlushes
49
+ prioDatabaseLogFlushed
50
+ prioDatabaseLogGrowths
51
+ prioDatabaseIOStall
52
+ prioDatabaseDeadlocks
53
+ prioDatabaseLockWaits
54
+ prioDatabaseLockTimeouts
55
+ prioDatabaseLockRequests
56
+ prioDatabaseDataFileSize
57
+ prioDatabaseState
58
+ prioDatabaseReadOnly
59
+
60
+ prioLocksByResource
61
+
62
+ prioWaitTotalTime
63
+ prioWaitResourceTime
64
+ prioWaitSignalTime
65
+ prioWaitMaxTime
66
+ prioWaitCount
67
+
68
+ prioJobStatus
69
+
70
+ prioReplicationStatus
71
+ prioReplicationLatency
72
+)
73
+
74
+// instanceCharts are charts for the SQL Server instance level metrics
75
+var instanceCharts = module.Charts{
76
+ userConnectionsChart.Copy(),
77
+ sessionConnectionsChart.Copy(),
78
+ blockedProcessesChart.Copy(),
79
+
80
+ batchRequestsChart.Copy(),
81
+ compilationsChart.Copy(),
82
+ recompilationsChart.Copy(),
83
+ autoParamAttemptsChart.Copy(),
84
+ sqlErrorsChart.Copy(),
85
+
86
+ bufferCacheHitRatioChart.Copy(),
87
+ bufferPageIOPSChart.Copy(),
88
+ bufferCheckpointPagesChart.Copy(),
89
+ bufferPageLifeExpectancyChart.Copy(),
90
+ bufferLazyWritesChart.Copy(),
91
+ bufferPageLookupsChart.Copy(),
92
+
93
+ pageSplitsChart.Copy(),
94
+
95
+ memoryTotalChart.Copy(),
96
+ memoryConnectionChart.Copy(),
97
+ memoryPendingGrantsChart.Copy(),
98
+ memoryExternalBenefitChart.Copy(),
99
+
100
+ processMemoryResidentChart.Copy(),
101
+ processMemoryVirtualChart.Copy(),
102
+ processMemoryUtilizationChart.Copy(),
103
+ processPageFaultsChart.Copy(),
104
+
105
+ osMemoryChart.Copy(),
106
+ osPageFileChart.Copy(),
107
+}
108
+
109
+var (
110
+ userConnectionsChart = module.Chart{
111
+ ID: "user_connections",
112
+ Title: "User connections",
113
+ Units: "connections",
114
+ Fam: "connections",
115
+ Ctx: "mssql.user_connections",
116
+ Priority: prioUserConnections,
117
+ Dims: module.Dims{
118
+ {ID: "user_connections", Name: "user"},
119
+ },
120
+ }
121
+ blockedProcessesChart = module.Chart{
122
+ ID: "blocked_processes",
123
+ Title: "Blocked processes",
124
+ Units: "processes",
125
+ Fam: "processes",
126
+ Ctx: "mssql.blocked_processes",
127
+ Priority: prioBlockedProcesses,
128
+ Dims: module.Dims{
129
+ {ID: "blocked_processes", Name: "blocked"},
130
+ },
131
+ }
132
+ sessionConnectionsChart = module.Chart{
133
+ ID: "session_connections",
134
+ Title: "Session connections",
135
+ Units: "connections",
136
+ Fam: "connections",
137
+ Ctx: "mssql.session_connections",
138
+ Priority: prioSessionConnections,
139
+ Dims: module.Dims{
140
+ {ID: "session_connections_user", Name: "user"},
141
+ {ID: "session_connections_internal", Name: "internal"},
142
+ },
143
+ }
144
+
145
+ batchRequestsChart = module.Chart{
146
+ ID: "batch_requests",
147
+ Title: "Batch requests",
148
+ Units: "requests/s",
149
+ Fam: "queries",
150
+ Ctx: "mssql.batch_requests",
151
+ Priority: prioBatchRequests,
152
+ Dims: module.Dims{
153
+ {ID: "batch_requests", Name: "batch", Algo: module.Incremental},
154
+ },
155
+ }
156
+ compilationsChart = module.Chart{
157
+ ID: "compilations",
158
+ Title: "SQL compilations",
159
+ Units: "compilations/s",
160
+ Fam: "queries",
161
+ Ctx: "mssql.compilations",
162
+ Priority: prioCompilations,
163
+ Dims: module.Dims{
164
+ {ID: "sql_compilations", Name: "compilations", Algo: module.Incremental},
165
+ },
166
+ }
167
+ recompilationsChart = module.Chart{
168
+ ID: "recompilations",
169
+ Title: "SQL re-compilations",
170
+ Units: "recompilations/s",
171
+ Fam: "queries",
172
+ Ctx: "mssql.recompilations",
173
+ Priority: prioRecompilations,
174
+ Dims: module.Dims{
175
+ {ID: "sql_recompilations", Name: "recompilations", Algo: module.Incremental},
176
+ },
177
+ }
178
+ autoParamAttemptsChart = module.Chart{
179
+ ID: "auto_param_attempts",
180
+ Title: "Auto-parameterization attempts",
181
+ Units: "attempts/s",
182
+ Fam: "queries",
183
+ Ctx: "mssql.auto_param_attempts",
184
+ Priority: prioAutoParamAttempts,
185
+ Dims: module.Dims{
186
+ {ID: "auto_param_attempts", Name: "total", Algo: module.Incremental},
187
+ {ID: "auto_param_safe", Name: "safe", Algo: module.Incremental},
188
+ {ID: "auto_param_failed", Name: "failed", Algo: module.Incremental, Mul: -1},
189
+ },
190
+ }
191
+ sqlErrorsChart = module.Chart{
192
+ ID: "sql_errors",
193
+ Title: "SQL errors",
194
+ Units: "errors/s",
195
+ Fam: "errors",
196
+ Ctx: "mssql.sql_errors",
197
+ Priority: prioSQLErrors,
198
+ Dims: module.Dims{
199
+ {ID: "sql_errors_total", Name: "errors", Algo: module.Incremental},
200
+ },
201
+ }
202
+
203
+ bufferCacheHitRatioChart = module.Chart{
204
+ ID: "buffer_cache_hit_ratio",
205
+ Title: "Buffer cache hit ratio",
206
+ Units: "percentage",
207
+ Fam: "buffer",
208
+ Ctx: "mssql.buffer_cache_hit_ratio",
209
+ Priority: prioBufferCacheHitRatio,
210
+ Dims: module.Dims{
211
+ {ID: "buffer_cache_hit_ratio", Name: "hit_ratio"},
212
+ },
213
+ }
214
+ bufferPageIOPSChart = module.Chart{
215
+ ID: "buffer_page_iops",
216
+ Title: "Buffer page I/O",
217
+ Units: "pages/s",
218
+ Fam: "buffer",
219
+ Ctx: "mssql.buffer_page_iops",
220
+ Priority: prioBufferPageIOPS,
221
+ Dims: module.Dims{
222
+ {ID: "buffer_page_reads", Name: "read", Algo: module.Incremental},
223
+ {ID: "buffer_page_writes", Name: "written", Algo: module.Incremental, Mul: -1},
224
+ },
225
+ }
226
+ bufferCheckpointPagesChart = module.Chart{
227
+ ID: "buffer_checkpoint_pages",
228
+ Title: "Buffer checkpoint pages flushed",
229
+ Units: "pages/s",
230
+ Fam: "buffer",
231
+ Ctx: "mssql.buffer_checkpoint_pages",
232
+ Priority: prioBufferCheckpointPages,
233
+ Dims: module.Dims{
234
+ {ID: "buffer_checkpoint_pages", Name: "flushed", Algo: module.Incremental},
235
+ },
236
+ }
237
+ bufferPageLifeExpectancyChart = module.Chart{
238
+ ID: "buffer_page_life_expectancy",
239
+ Title: "Buffer page life expectancy",
240
+ Units: "seconds",
241
+ Fam: "buffer",
242
+ Ctx: "mssql.buffer_page_life_expectancy",
243
+ Priority: prioBufferPageLifeExpectancy,
244
+ Dims: module.Dims{
245
+ {ID: "buffer_page_life_expectancy", Name: "life_expectancy"},
246
+ },
247
+ }
248
+ bufferLazyWritesChart = module.Chart{
249
+ ID: "buffer_lazy_writes",
250
+ Title: "Buffer lazy writes",
251
+ Units: "writes/s",
252
+ Fam: "buffer",
253
+ Ctx: "mssql.buffer_lazy_writes",
254
+ Priority: prioBufferLazyWrites,
255
+ Dims: module.Dims{
256
+ {ID: "buffer_lazy_writes", Name: "lazy_writes", Algo: module.Incremental},
257
+ },
258
+ }
259
+ bufferPageLookupsChart = module.Chart{
260
+ ID: "buffer_page_lookups",
261
+ Title: "Buffer page lookups",
262
+ Units: "lookups/s",
263
+ Fam: "buffer",
264
+ Ctx: "mssql.buffer_page_lookups",
265
+ Priority: prioBufferPageLookups,
266
+ Dims: module.Dims{
267
+ {ID: "buffer_page_lookups", Name: "lookups", Algo: module.Incremental},
268
+ },
269
+ }
270
+
271
+ pageSplitsChart = module.Chart{
272
+ ID: "page_splits",
273
+ Title: "Page splits",
274
+ Units: "splits/s",
275
+ Fam: "access",
276
+ Ctx: "mssql.page_splits",
277
+ Priority: prioPageSplits,
278
+ Dims: module.Dims{
279
+ {ID: "page_splits", Name: "page", Algo: module.Incremental},
280
+ },
281
+ }
282
+
283
+ memoryTotalChart = module.Chart{
284
+ ID: "memory_total",
285
+ Title: "Total server memory",
286
+ Units: "bytes",
287
+ Fam: "memory",
288
+ Ctx: "mssql.memory_total",
289
+ Priority: prioMemoryTotal,
290
+ Dims: module.Dims{
291
+ {ID: "memory_total", Name: "memory"},
292
+ },
293
+ }
294
+ memoryConnectionChart = module.Chart{
295
+ ID: "memory_connection",
296
+ Title: "Connection memory",
297
+ Units: "bytes",
298
+ Fam: "memory",
299
+ Ctx: "mssql.memory_connection",
300
+ Priority: prioMemoryConnection,
301
+ Dims: module.Dims{
302
+ {ID: "memory_connection", Name: "memory"},
303
+ },
304
+ }
305
+ memoryPendingGrantsChart = module.Chart{
306
+ ID: "memory_pending_grants",
307
+ Title: "Pending memory grants",
308
+ Units: "processes",
309
+ Fam: "memory",
310
+ Ctx: "mssql.memory_pending_grants",
311
+ Priority: prioMemoryPendingGrants,
312
+ Dims: module.Dims{
313
+ {ID: "memory_pending_grants", Name: "pending"},
314
+ },
315
+ }
316
+ memoryExternalBenefitChart = module.Chart{
317
+ ID: "memory_external_benefit",
318
+ Title: "External benefit of memory",
319
+ Units: "benefit",
320
+ Fam: "memory",
321
+ Ctx: "mssql.memory_external_benefit",
322
+ Priority: prioMemoryExternalBenefit,
323
+ Dims: module.Dims{
324
+ {ID: "memory_external_benefit", Name: "benefit"},
325
+ },
326
+ }
327
+
328
+ processMemoryResidentChart = module.Chart{
329
+ ID: "process_memory_resident",
330
+ Title: "Process resident memory (working set)",
331
+ Units: "bytes",
332
+ Fam: "process memory",
333
+ Ctx: "mssql.process_memory_resident",
334
+ Priority: prioProcessMemoryResident,
335
+ Dims: module.Dims{
336
+ {ID: "process_memory_resident", Name: "resident"},
337
+ },
338
+ }
339
+ processMemoryVirtualChart = module.Chart{
340
+ ID: "process_memory_virtual",
341
+ Title: "Process virtual memory committed",
342
+ Units: "bytes",
343
+ Fam: "process memory",
344
+ Ctx: "mssql.process_memory_virtual",
345
+ Priority: prioProcessMemoryVirtual,
346
+ Dims: module.Dims{
347
+ {ID: "process_memory_virtual", Name: "virtual"},
348
+ },
349
+ }
350
+ processMemoryUtilizationChart = module.Chart{
351
+ ID: "process_memory_utilization",
352
+ Title: "Process memory utilization",
353
+ Units: "percentage",
354
+ Fam: "process memory",
355
+ Ctx: "mssql.process_memory_utilization",
356
+ Priority: prioProcessMemoryUtilization,
357
+ Dims: module.Dims{
358
+ {ID: "process_memory_utilization", Name: "utilization"},
359
+ },
360
+ }
361
+ processPageFaultsChart = module.Chart{
362
+ ID: "process_page_faults",
363
+ Title: "Process page faults",
364
+ Units: "faults",
365
+ Fam: "process memory",
366
+ Ctx: "mssql.process_page_faults",
367
+ Priority: prioProcessPageFaults,
368
+ Dims: module.Dims{
369
+ {ID: "process_page_faults", Name: "page_faults", Algo: module.Incremental},
370
+ },
371
+ }
372
+
373
+ osMemoryChart = module.Chart{
374
+ ID: "os_memory",
375
+ Title: "OS physical memory",
376
+ Units: "bytes",
377
+ Fam: "os memory",
378
+ Ctx: "mssql.os_memory",
379
+ Priority: prioOSMemory,
380
+ Dims: module.Dims{
381
+ {ID: "os_memory_used", Name: "used"},
382
+ {ID: "os_memory_available", Name: "available"},
383
+ },
384
+ }
385
+ osPageFileChart = module.Chart{
386
+ ID: "os_pagefile",
387
+ Title: "OS page file",
388
+ Units: "bytes",
389
+ Fam: "os memory",
390
+ Ctx: "mssql.os_pagefile",
391
+ Priority: prioOSPageFile,
392
+ Dims: module.Dims{
393
+ {ID: "os_pagefile_used", Name: "used"},
394
+ {ID: "os_pagefile_available", Name: "available"},
395
+ },
396
+ }
397
+)
398
+
399
+// Database chart templates
400
+var (
401
+ databaseActiveTransactionsChartTmpl = module.Chart{
402
+ ID: "database_%s_active_transactions",
403
+ Title: "Active transactions",
404
+ Units: "transactions",
405
+ Fam: "db transactions",
406
+ Ctx: "mssql.database_active_transactions",
407
+ Priority: prioDatabaseActiveTransactions,
408
+ Dims: module.Dims{
409
+ {ID: "database_%s_active_transactions", Name: "active"},
410
+ },
411
+ }
412
+ databaseTransactionsChartTmpl = module.Chart{
413
+ ID: "database_%s_transactions",
414
+ Title: "Transactions",
415
+ Units: "transactions/s",
416
+ Fam: "db transactions",
417
+ Ctx: "mssql.database_transactions",
418
+ Priority: prioDatabaseTransactions,
419
+ Dims: module.Dims{
420
+ {ID: "database_%s_transactions", Name: "transactions", Algo: module.Incremental},
421
+ },
422
+ }
423
+ databaseWriteTransactionsChartTmpl = module.Chart{
424
+ ID: "database_%s_write_transactions",
425
+ Title: "Write transactions",
426
+ Units: "transactions/s",
427
+ Fam: "db transactions",
428
+ Ctx: "mssql.database_write_transactions",
429
+ Priority: prioDatabaseWriteTransactions,
430
+ Dims: module.Dims{
431
+ {ID: "database_%s_write_transactions", Name: "write", Algo: module.Incremental},
432
+ },
433
+ }
434
+ databaseLogFlushesChartTmpl = module.Chart{
435
+ ID: "database_%s_log_flushes",
436
+ Title: "Log flushes",
437
+ Units: "flushes/s",
438
+ Fam: "db log",
439
+ Ctx: "mssql.database_log_flushes",
440
+ Priority: prioDatabaseLogFlushes,
441
+ Dims: module.Dims{
442
+ {ID: "database_%s_log_flushes", Name: "flushes", Algo: module.Incremental},
443
+ },
444
+ }
445
+ databaseLogFlushedChartTmpl = module.Chart{
446
+ ID: "database_%s_log_flushed",
447
+ Title: "Log bytes flushed",
448
+ Units: "bytes/s",
449
+ Fam: "db log",
450
+ Ctx: "mssql.database_log_flushed",
451
+ Priority: prioDatabaseLogFlushed,
452
+ Dims: module.Dims{
453
+ {ID: "database_%s_log_flushed", Name: "flushed", Algo: module.Incremental},
454
+ },
455
+ }
456
+ databaseDataFileSizeChartTmpl = module.Chart{
457
+ ID: "database_%s_data_file_size",
458
+ Title: "Data file size",
459
+ Units: "bytes",
460
+ Fam: "db size",
461
+ Ctx: "mssql.database_data_file_size",
462
+ Priority: prioDatabaseDataFileSize,
463
+ Dims: module.Dims{
464
+ {ID: "database_%s_data_file_size", Name: "size"},
465
+ },
466
+ }
467
+ databaseBackupRestoreThroughputChartTmpl = module.Chart{
468
+ ID: "database_%s_backup_restore_throughput",
469
+ Title: "Backup/Restore throughput",
470
+ Units: "bytes/s",
471
+ Fam: "db backup",
472
+ Ctx: "mssql.database_backup_restore_throughput",
473
+ Priority: prioDatabaseDataFileSize + 1,
474
+ Dims: module.Dims{
475
+ {ID: "database_%s_backup_restore_throughput", Name: "throughput", Algo: module.Incremental},
476
+ },
477
+ }
478
+ databaseStateChartTmpl = module.Chart{
479
+ ID: "database_%s_state",
480
+ Title: "Database state",
481
+ Units: "state",
482
+ Fam: "db status",
483
+ Ctx: "mssql.database_state",
484
+ Priority: prioDatabaseState,
485
+ Dims: module.Dims{
486
+ {ID: "database_%s_state_online", Name: "online"},
487
+ {ID: "database_%s_state_restoring", Name: "restoring"},
488
+ {ID: "database_%s_state_recovering", Name: "recovering"},
489
+ {ID: "database_%s_state_pending", Name: "pending"},
490
+ {ID: "database_%s_state_suspect", Name: "suspect"},
491
+ {ID: "database_%s_state_emergency", Name: "emergency"},
492
+ {ID: "database_%s_state_offline", Name: "offline"},
493
+ },
494
+ }
495
+ databaseReadOnlyChartTmpl = module.Chart{
496
+ ID: "database_%s_read_only",
497
+ Title: "Database read-only status",
498
+ Units: "status",
499
+ Fam: "db status",
500
+ Ctx: "mssql.database_read_only",
501
+ Priority: prioDatabaseReadOnly,
502
+ Dims: module.Dims{
503
+ {ID: "database_%s_read_only", Name: "read_only"},
504
+ {ID: "database_%s_read_write", Name: "read_write"},
505
+ },
506
+ }
507
+ databaseLogGrowthsChartTmpl = module.Chart{
508
+ ID: "database_%s_log_growths",
509
+ Title: "Database log growths",
510
+ Units: "growths",
511
+ Fam: "db log",
512
+ Ctx: "mssql.database_log_growths",
513
+ Priority: prioDatabaseLogGrowths,
514
+ Dims: module.Dims{
515
+ {ID: "database_%s_log_growths", Name: "growths", Algo: module.Incremental},
516
+ },
517
+ }
518
+ databaseIOStallChartTmpl = module.Chart{
519
+ ID: "database_%s_io_stall",
520
+ Title: "Database I/O stall time",
521
+ Units: "ms",
522
+ Fam: "db io",
523
+ Ctx: "mssql.database_io_stall",
524
+ Priority: prioDatabaseIOStall,
525
+ Dims: module.Dims{
526
+ {ID: "database_%s_io_stall_read", Name: "read", Algo: module.Incremental},
527
+ {ID: "database_%s_io_stall_write", Name: "write", Algo: module.Incremental},
528
+ },
529
+ }
530
+)
531
+
532
+// Lock stats chart templates (per lock resource type, from performance counters)
533
+var (
534
+ lockStatsDeadlocksChartTmpl = module.Chart{
535
+ ID: "lock_stats_%s_deadlocks",
536
+ Title: "Deadlocks by lock resource type",
537
+ Units: "deadlocks/s",
538
+ Fam: "lock stats",
539
+ Ctx: "mssql.lock_stats_deadlocks",
540
+ Priority: prioDatabaseDeadlocks,
541
+ Dims: module.Dims{
542
+ {ID: "lock_stats_%s_deadlocks", Name: "deadlocks", Algo: module.Incremental},
543
+ },
544
+ }
545
+ lockStatsWaitsChartTmpl = module.Chart{
546
+ ID: "lock_stats_%s_waits",
547
+ Title: "Lock waits by lock resource type",
548
+ Units: "waits/s",
549
+ Fam: "lock stats",
550
+ Ctx: "mssql.lock_stats_waits",
551
+ Priority: prioDatabaseLockWaits,
552
+ Dims: module.Dims{
553
+ {ID: "lock_stats_%s_waits", Name: "waits", Algo: module.Incremental},
554
+ },
555
+ }
556
+ lockStatsTimeoutsChartTmpl = module.Chart{
557
+ ID: "lock_stats_%s_timeouts",
558
+ Title: "Lock timeouts by lock resource type",
559
+ Units: "timeouts/s",
560
+ Fam: "lock stats",
561
+ Ctx: "mssql.lock_stats_timeouts",
562
+ Priority: prioDatabaseLockTimeouts,
563
+ Dims: module.Dims{
564
+ {ID: "lock_stats_%s_timeouts", Name: "timeouts", Algo: module.Incremental},
565
+ },
566
+ }
567
+ lockStatsRequestsChartTmpl = module.Chart{
568
+ ID: "lock_stats_%s_requests",
569
+ Title: "Lock requests by lock resource type",
570
+ Units: "requests/s",
571
+ Fam: "lock stats",
572
+ Ctx: "mssql.lock_stats_requests",
573
+ Priority: prioDatabaseLockRequests,
574
+ Dims: module.Dims{
575
+ {ID: "lock_stats_%s_requests", Name: "requests", Algo: module.Incremental},
576
+ },
577
+ }
578
+)
579
+
580
+// Lock resource chart template
581
+var locksByResourceChartTmpl = module.Chart{
582
+ ID: "locks_by_resource_%s",
583
+ Title: "Locks by resource type",
584
+ Units: "locks",
585
+ Fam: "locks",
586
+ Ctx: "mssql.locks_by_resource",
587
+ Priority: prioLocksByResource,
588
+ Dims: module.Dims{
589
+ {ID: "locks_%s_count", Name: "locks"},
590
+ },
591
+}
592
+
593
+// Wait type chart templates
594
+var (
595
+ waitTotalTimeChartTmpl = module.Chart{
596
+ ID: "wait_%s_total_time",
597
+ Title: "Total wait time",
598
+ Units: "ms",
599
+ Fam: "waits",
600
+ Ctx: "mssql.wait_total_time",
601
+ Priority: prioWaitTotalTime,
602
+ Dims: module.Dims{
603
+ {ID: "wait_%s_total_ms", Name: "duration", Algo: module.Incremental},
604
+ },
605
+ }
606
+ waitResourceTimeChartTmpl = module.Chart{
607
+ ID: "wait_%s_resource_time",
608
+ Title: "Resource wait time",
609
+ Units: "ms",
610
+ Fam: "waits",
611
+ Ctx: "mssql.wait_resource_time",
612
+ Priority: prioWaitResourceTime,
613
+ Dims: module.Dims{
614
+ {ID: "wait_%s_resource_ms", Name: "duration", Algo: module.Incremental},
615
+ },
616
+ }
617
+ waitSignalTimeChartTmpl = module.Chart{
618
+ ID: "wait_%s_signal_time",
619
+ Title: "Signal wait time",
620
+ Units: "ms",
621
+ Fam: "waits",
622
+ Ctx: "mssql.wait_signal_time",
623
+ Priority: prioWaitSignalTime,
624
+ Dims: module.Dims{
625
+ {ID: "wait_%s_signal_ms", Name: "duration", Algo: module.Incremental},
626
+ },
627
+ }
628
+ waitCountChartTmpl = module.Chart{
629
+ ID: "wait_%s_count",
630
+ Title: "Wait count",
631
+ Units: "waits/s",
632
+ Fam: "waits",
633
+ Ctx: "mssql.wait_count",
634
+ Priority: prioWaitCount,
635
+ Dims: module.Dims{
636
+ {ID: "wait_%s_tasks", Name: "waits", Algo: module.Incremental},
637
+ },
638
+ }
639
+ waitMaxTimeChartTmpl = module.Chart{
640
+ ID: "wait_%s_max_time",
641
+ Title: "Maximum wait time",
642
+ Units: "ms",
643
+ Fam: "waits",
644
+ Ctx: "mssql.wait_max_time",
645
+ Priority: prioWaitMaxTime,
646
+ Dims: module.Dims{
647
+ {ID: "wait_%s_max_ms", Name: "max_time"},
648
+ },
649
+ }
650
+)
651
+
652
+// Job status chart template
653
+var jobStatusChartTmpl = module.Chart{
654
+ ID: "job_%s_status",
655
+ Title: "Job status",
656
+ Units: "status",
657
+ Fam: "jobs",
658
+ Ctx: "mssql.job_status",
659
+ Priority: prioJobStatus,
660
+ Dims: module.Dims{
661
+ {ID: "job_%s_enabled", Name: "enabled"},
662
+ {ID: "job_%s_disabled", Name: "disabled"},
663
+ },
664
+}
665
+
666
+// Replication chart templates
667
+var (
668
+ replicationStatusChartTmpl = module.Chart{
669
+ ID: "replication_%s_status",
670
+ Title: "Replication status",
671
+ Units: "status",
672
+ Fam: "replication",
673
+ Ctx: "mssql.replication_status",
674
+ Priority: prioReplicationStatus,
675
+ Dims: module.Dims{
676
+ {ID: "replication_%s_status_started", Name: "started"},
677
+ {ID: "replication_%s_status_succeeded", Name: "succeeded"},
678
+ {ID: "replication_%s_status_in_progress", Name: "in_progress"},
679
+ {ID: "replication_%s_status_idle", Name: "idle"},
680
+ {ID: "replication_%s_status_retrying", Name: "retrying"},
681
+ {ID: "replication_%s_status_failed", Name: "failed"},
682
+ },
683
+ }
684
+ replicationWarningChartTmpl = module.Chart{
685
+ ID: "replication_%s_warning",
686
+ Title: "Replication warnings",
687
+ Units: "flags",
688
+ Fam: "replication",
689
+ Ctx: "mssql.replication_warning",
690
+ Priority: prioReplicationStatus + 1,
691
+ Dims: module.Dims{
692
+ {ID: "replication_%s_warning_expiration", Name: "expiration"},
693
+ {ID: "replication_%s_warning_latency", Name: "latency"},
694
+ {ID: "replication_%s_warning_mergeexpiration", Name: "merge_expiration"},
695
+ {ID: "replication_%s_warning_mergeslowrunduration", Name: "merge_slow_duration"},
696
+ {ID: "replication_%s_warning_mergefastrunduration", Name: "merge_fast_duration"},
697
+ {ID: "replication_%s_warning_mergefastrunspeed", Name: "merge_fast_speed"},
698
+ {ID: "replication_%s_warning_mergeslowrunspeed", Name: "merge_slow_speed"},
699
+ },
700
+ }
701
+ replicationLatencyChartTmpl = module.Chart{
702
+ ID: "replication_%s_latency",
703
+ Title: "Replication latency",
704
+ Units: "seconds",
705
+ Fam: "replication",
706
+ Ctx: "mssql.replication_latency",
707
+ Priority: prioReplicationLatency,
708
+ Dims: module.Dims{
709
+ {ID: "replication_%s_latency_avg", Name: "average"},
710
+ {ID: "replication_%s_latency_best", Name: "best"},
711
+ {ID: "replication_%s_latency_worst", Name: "worst"},
712
+ },
713
+ }
714
+ replicationSubscriptionsChartTmpl = module.Chart{
715
+ ID: "replication_%s_subscriptions",
716
+ Title: "Replication subscriptions",
717
+ Units: "subscriptions",
718
+ Fam: "replication",
719
+ Ctx: "mssql.replication_subscriptions",
720
+ Priority: prioReplicationStatus + 1,
721
+ Dims: module.Dims{
722
+ {ID: "replication_%s_subscriptions", Name: "total"},
723
+ {ID: "replication_%s_agents_running", Name: "agents_running"},
724
+ },
725
+ }
726
+)
727
+
728
+func (c *Collector) addDatabaseCharts(dbName string) {
729
+ charts := &module.Charts{
730
+ databaseActiveTransactionsChartTmpl.Copy(),
731
+ databaseTransactionsChartTmpl.Copy(),
732
+ databaseWriteTransactionsChartTmpl.Copy(),
733
+ databaseLogFlushesChartTmpl.Copy(),
734
+ databaseLogFlushedChartTmpl.Copy(),
735
+ databaseLogGrowthsChartTmpl.Copy(),
736
+ databaseIOStallChartTmpl.Copy(),
737
+ databaseDataFileSizeChartTmpl.Copy(),
738
+ databaseBackupRestoreThroughputChartTmpl.Copy(),
739
+ databaseStateChartTmpl.Copy(),
740
+ databaseReadOnlyChartTmpl.Copy(),
741
+ }
742
+
743
+ dbID := cleanDatabaseName(dbName)
744
+
745
+ for _, chart := range *charts {
746
+ chart.ID = fmt.Sprintf(chart.ID, dbID)
747
+ chart.Labels = []module.Label{
748
+ {Key: "database", Value: dbName},
749
+ }
750
+ for _, dim := range chart.Dims {
751
+ dim.ID = fmt.Sprintf(dim.ID, dbID)
752
+ }
753
+ }
754
+
755
+ if err := c.Charts().Add(*charts...); err != nil {
756
+ c.Warning(err)
757
+ }
758
+}
759
+
760
+func (c *Collector) addWaitTypeCharts(waitType string, waitCategory string) {
761
+ charts := &module.Charts{
762
+ waitTotalTimeChartTmpl.Copy(),
763
+ waitResourceTimeChartTmpl.Copy(),
764
+ waitSignalTimeChartTmpl.Copy(),
765
+ waitMaxTimeChartTmpl.Copy(),
766
+ waitCountChartTmpl.Copy(),
767
+ }
768
+
769
+ waitID := cleanWaitTypeName(waitType)
770
+
771
+ for _, chart := range *charts {
772
+ chart.ID = fmt.Sprintf(chart.ID, waitID)
773
+ chart.Labels = []module.Label{
774
+ {Key: "wait_type", Value: waitType},
775
+ {Key: "wait_category", Value: waitCategory},
776
+ }
777
+ for _, dim := range chart.Dims {
778
+ dim.ID = fmt.Sprintf(dim.ID, waitID)
779
+ }
780
+ }
781
+
782
+ if err := c.Charts().Add(*charts...); err != nil {
783
+ c.Warning(err)
784
+ }
785
+}
786
+
787
+func (c *Collector) addLockResourceCharts(resourceType string) {
788
+ chart := locksByResourceChartTmpl.Copy()
789
+
790
+ resID := cleanResourceTypeName(resourceType)
791
+
792
+ chart.ID = fmt.Sprintf(chart.ID, resID)
793
+ chart.Labels = []module.Label{
794
+ {Key: "resource", Value: resourceType},
795
+ }
796
+ for _, dim := range chart.Dims {
797
+ dim.ID = fmt.Sprintf(dim.ID, resID)
798
+ }
799
+
800
+ if err := c.Charts().Add(chart); err != nil {
801
+ c.Warning(err)
802
+ }
803
+}
804
+
805
+func (c *Collector) addLockStatsCharts(resourceType string) {
806
+ charts := &module.Charts{
807
+ lockStatsDeadlocksChartTmpl.Copy(),
808
+ lockStatsWaitsChartTmpl.Copy(),
809
+ lockStatsTimeoutsChartTmpl.Copy(),
810
+ lockStatsRequestsChartTmpl.Copy(),
811
+ }
812
+
813
+ resID := cleanResourceTypeName(resourceType)
814
+
815
+ for _, chart := range *charts {
816
+ chart.ID = fmt.Sprintf(chart.ID, resID)
817
+ chart.Labels = []module.Label{
818
+ {Key: "resource", Value: resourceType},
819
+ }
820
+ for _, dim := range chart.Dims {
821
+ dim.ID = fmt.Sprintf(dim.ID, resID)
822
+ }
823
+ }
824
+
825
+ if err := c.Charts().Add(*charts...); err != nil {
826
+ c.Warning(err)
827
+ }
828
+}
829
+
830
+func (c *Collector) addJobCharts(jobName string) {
831
+ chart := jobStatusChartTmpl.Copy()
832
+
833
+ jobID := cleanJobName(jobName)
834
+
835
+ chart.ID = fmt.Sprintf(chart.ID, jobID)
836
+ chart.Labels = []module.Label{
837
+ {Key: "job_name", Value: jobName},
838
+ }
839
+ for _, dim := range chart.Dims {
840
+ dim.ID = fmt.Sprintf(dim.ID, jobID)
841
+ }
842
+
843
+ if err := c.Charts().Add(chart); err != nil {
844
+ c.Warning(err)
845
+ }
846
+}
847
+
848
+func (c *Collector) addReplicationCharts(pubDB, publication string) {
849
+ charts := &module.Charts{
850
+ replicationStatusChartTmpl.Copy(),
851
+ replicationWarningChartTmpl.Copy(),
852
+ replicationLatencyChartTmpl.Copy(),
853
+ replicationSubscriptionsChartTmpl.Copy(),
854
+ }
855
+
856
+ pubID := cleanPublicationName(pubDB, publication)
857
+
858
+ for _, chart := range *charts {
859
+ chart.ID = fmt.Sprintf(chart.ID, pubID)
860
+ chart.Labels = []module.Label{
861
+ {Key: "publisher_db", Value: pubDB},
862
+ {Key: "publication", Value: publication},
863
+ }
864
+ for _, dim := range chart.Dims {
865
+ dim.ID = fmt.Sprintf(dim.ID, pubID)
866
+ }
867
+ }
868
+
869
+ if err := c.Charts().Add(*charts...); err != nil {
870
+ c.Warning(err)
871
+ }
872
+}
873
+
874
+func cleanDatabaseName(name string) string {
875
+ return strings.ReplaceAll(strings.ToLower(name), " ", "_")
876
+}
877
+
878
+func cleanWaitTypeName(name string) string {
879
+ return strings.ToLower(name)
880
+}
881
+
882
+func cleanResourceTypeName(name string) string {
883
+ return strings.ToLower(name)
884
+}
885
+
886
+func cleanJobName(name string) string {
887
+ r := strings.NewReplacer(" ", "_", ".", "_", "-", "_")
888
+ return strings.ToLower(r.Replace(name))
889
+}
890
+
891
+func cleanPublicationName(pubDB, publication string) string {
892
+ r := strings.NewReplacer(" ", "_", ".", "_", "-", "_")
893
+ return strings.ToLower(r.Replace(pubDB + "_" + publication))
894
+}