Add MSSQL metrics (Part I). (#18591)
thiagoftsm committed
Oct 4, 2024 at 21:42 UTC
88d6f0fcdcc27a62ae91bb1ffbe23ff1977d449b
4 files changed
+801
-1
CMakeLists.txt
+1
@@ -1446,6 +1446,7 @@ set(WINDOWS_PLUGIN_FILES
1446
src/collectors/windows.plugin/GetSystemCPU.c
1447
src/collectors/windows.plugin/perflib-rrd.c
1448
src/collectors/windows.plugin/perflib-rrd.h
1449
+ src/collectors/windows.plugin/perflib-mssql.c
1450
src/collectors/windows.plugin/perflib-storage.c
1451
src/collectors/windows.plugin/perflib-processor.c
1452
src/collectors/windows.plugin/perflib-thermalzone.c
src/collectors/windows.plugin/perflib-mssql.c
new
+779
@@ -0,0 +1,779 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "windows_plugin.h"
4
+#include "windows-internals.h"
5
+
6
+// https://learn.microsoft.com/en-us/sql/sql-server/install/instance-configuration?view=sql-server-ver16
7
+#define NETDATA_MAX_INSTANCE_NAME 32
8
+#define NETDATA_MAX_INSTANCE_OBJECT 128
9
+
10
+enum netdata_mssql_metrics {
11
+ NETDATA_MSSQL_GENERAL_STATS,
12
+ NETDATA_MSSQL_SQL_ERRORS,
13
+ NETDATA_MSSQL_DATABASE,
14
+ NETDATA_MSSQL_LOCKS,
15
+ NETDATA_MSSQL_MEMORY,
16
+ NETDATA_MSSQL_BUFFER_MANAGEMENT,
17
+ NETDATA_MSSQL_SQL_STATS,
18
+ NETDATA_MSSQL_TRANSACTIONS,
19
+ NETDATA_MSSQL_ACCESS_METHODS,
20
+
21
+ NETDATA_MSSQL_METRICS_END
22
+};
23
+
24
+struct mssql_instance {
25
+ char *instanceID;
26
+
27
+ char *objectName[NETDATA_MSSQL_METRICS_END];
28
+
29
+ RRDSET *st_user_connections;
30
+ RRDDIM *rd_user_connections;
31
+
32
+ RRDSET *st_process_blocked;
33
+ RRDDIM *rd_process_blocked;
34
+
35
+ RRDSET *st_stats_auto_param;
36
+ RRDDIM *rd_stats_auto_param;
37
+
38
+ RRDSET *st_stats_batch_request;
39
+ RRDDIM *rd_stats_batch_request;
40
+
41
+ RRDSET *st_stats_safe_auto;
42
+ RRDDIM *rd_stats_safe_auto;
43
+
44
+ RRDSET *st_stats_compilation;
45
+ RRDDIM *rd_stats_compilation;
46
+
47
+ RRDSET *st_stats_recompiles;
48
+ RRDDIM *rd_stats_recompiles;
49
+
50
+ RRDSET *st_buff_cache_hits;
51
+ RRDDIM *rd_buff_cache_hits;
52
+
53
+ RRDSET *st_buff_cache_page_life_expectancy;
54
+ RRDDIM *rd_buff_cache_page_life_expectancy;
55
+
56
+ RRDSET *st_buff_checkpoint_pages;
57
+ RRDDIM *rd_buff_checkpoint_pages;
58
+
59
+ RRDSET *st_buff_page_iops;
60
+ RRDDIM *rd_buff_page_reads;
61
+ RRDDIM *rd_buff_page_writes;
62
+
63
+ RRDSET *st_access_method_page_splits;
64
+ RRDDIM *rd_access_method_page_splits;
65
+
66
+ RRDSET *st_sql_errors;
67
+ RRDDIM *rd_sql_errors;
68
+
69
+
70
+ COUNTER_DATA MSSQLAccessMethodPageSplits;
71
+ COUNTER_DATA MSSQLBufferCacheHits;
72
+ COUNTER_DATA MSSQLBufferCheckpointPages;
73
+ COUNTER_DATA MSSQLBufferPageLifeExpectancy;
74
+ COUNTER_DATA MSSQLBufferPageReads;
75
+ COUNTER_DATA MSSQLBufferPageWrites;
76
+ COUNTER_DATA MSSQLBlockedProcesses;
77
+ COUNTER_DATA MSSQLUserConnections;
78
+ COUNTER_DATA MSSQLLockWait;
79
+ COUNTER_DATA MSSQLDeadlocks;
80
+ COUNTER_DATA MSSQLConnectionMemoryBytes;
81
+ COUNTER_DATA MSSQLExternalBenefitOfMemory;
82
+ COUNTER_DATA MSSQLPendingMemoryGrants;
83
+ COUNTER_DATA MSSQLSQLErrorsTotal;
84
+ COUNTER_DATA MSSQLTotalServerMemory;
85
+ COUNTER_DATA MSSQLStatsAutoParameterization;
86
+ COUNTER_DATA MSSQLStatsBatchRequests;
87
+ COUNTER_DATA MSSQLStatSafeAutoParameterization;
88
+ COUNTER_DATA MSSQLCompilations;
89
+ COUNTER_DATA MSSQLRecompilations;
90
+
91
+ COUNTER_DATA MSSQLDatabaseActiveTransactions;
92
+ COUNTER_DATA MSSQLDatabaseBackupRestoreOperations;
93
+ COUNTER_DATA MSSQLDatabaseDataFileSize;
94
+ COUNTER_DATA MSSQLDatabaseLogFlushed;
95
+ COUNTER_DATA MSSQLDatabaseLogFlushes;
96
+ COUNTER_DATA MSSQLDatabaseTransactions;
97
+ COUNTER_DATA MSSQLDatabaseWriteTransactions;
98
+};
99
+
100
+static DICTIONARY *mssql_instances = NULL;
101
+
102
+static void initialize_mssql_objects(struct mssql_instance *p, const char *instance) {
103
+ char prefix[NETDATA_MAX_INSTANCE_NAME];
104
+ if (!strcmp(instance, "MSSQLSERVER")) {
105
+ strncpyz(prefix, "SQLServer:", sizeof(prefix) -1);
106
+ } else {
107
+ snprintfz(prefix, sizeof(prefix) -1, "MSSQL$:%s:", instance);
108
+ }
109
+
110
+ size_t length = strlen(prefix);
111
+ char name[NETDATA_MAX_INSTANCE_OBJECT];
112
+ snprintfz(name, sizeof(name) -1, "%s%s", prefix, "General Statistics");
113
+ p->objectName[NETDATA_MSSQL_GENERAL_STATS] = strdup(name);
114
+
115
+ strncpyz(&name[length], "SQL Errors", sizeof(name) - length);
116
+ p->objectName[NETDATA_MSSQL_SQL_ERRORS] = strdup(name);
117
+
118
+ strncpyz(&name[length], "Databases", sizeof(name) - length);
119
+ p->objectName[NETDATA_MSSQL_DATABASE] = strdup(name);
120
+
121
+ strncpyz(&name[length], "Transactions", sizeof(name) - length);
122
+ p->objectName[NETDATA_MSSQL_TRANSACTIONS] = strdup(name);
123
+
124
+ strncpyz(&name[length], "SQL Statistics", sizeof(name) - length);
125
+ p->objectName[NETDATA_MSSQL_SQL_STATS] = strdup(name);
126
+
127
+ strncpyz(&name[length], "Buffer Manager", sizeof(name) - length);
128
+ p->objectName[NETDATA_MSSQL_BUFFER_MANAGEMENT] = strdup(name);
129
+
130
+ strncpyz(&name[length], "Memory Manager", sizeof(name) - length);
131
+ p->objectName[NETDATA_MSSQL_MEMORY] = strdup(name);
132
+
133
+ strncpyz(&name[length], "Locks", sizeof(name) - length);
134
+ p->objectName[NETDATA_MSSQL_LOCKS] = strdup(name);
135
+
136
+ strncpyz(&name[length], "Access Methods", sizeof(name) - length);
137
+ p->objectName[NETDATA_MSSQL_ACCESS_METHODS] = strdup(name);
138
+
139
+ p->instanceID = strdup(instance);
140
+ netdata_fix_chart_name(p->instanceID);
141
+}
142
+
143
+static inline void initialize_mssql_keys(struct mssql_instance *p) {
144
+ // General Statistics
145
+ p->MSSQLUserConnections.key = "User Connections";
146
+ p->MSSQLBlockedProcesses.key = "Processes blocked";
147
+
148
+ // SQL Statistics
149
+ p->MSSQLStatsAutoParameterization.key = "Auto-Param Attempts/sec";
150
+ p->MSSQLStatsBatchRequests.key = "Batch Requests/sec";
151
+ p->MSSQLStatSafeAutoParameterization.key = "Safe Auto-Params/sec";
152
+ p->MSSQLCompilations.key = "SQL Compilations/sec";
153
+ p->MSSQLRecompilations.key = "SQL Re-Compilations/sec";
154
+
155
+ // Buffer Management
156
+ p->MSSQLBufferCacheHits.key = "Buffer cache hit ratio";
157
+ p->MSSQLBufferPageLifeExpectancy.key = "Page life expectancy";
158
+ p->MSSQLBufferCheckpointPages.key = "Checkpoint pages/sec";
159
+ p->MSSQLBufferPageReads.key = "Page reads/sec";
160
+ p->MSSQLBufferPageWrites.key = "Page writes/sec";
161
+
162
+ // Access Methods
163
+ p->MSSQLAccessMethodPageSplits.key = "Page Splits/sec";
164
+
165
+ // Errors
166
+ p->MSSQLSQLErrorsTotal.key = "Errors/sec";
167
+
168
+ /*
169
+ p->MSSQLLockWait.key = "";
170
+ p->MSSQLDeadlocks.key = "";
171
+ p->MSSQLConnectionMemoryBytes.key = "";
172
+ p->MSSQLExternalBenefitOfMemory.key = "";
173
+ p->MSSQLPendingMemoryGrants.key = "";
174
+ p->MSSQLTotalServerMemory.key = "";
175
+
176
+ p->MSSQLDatabaseActiveTransactions.key = "";
177
+ p->MSSQLDatabaseBackupRestoreOperations.key = "";
178
+ p->MSSQLDatabaseDataFileSize.key = "";
179
+ p->MSSQLDatabaseLogFlushed.key = "";
180
+ p->MSSQLDatabaseLogFlushes.key = "";
181
+ p->MSSQLDatabaseTransactions.key = "";
182
+ p->MSSQLDatabaseWriteTransactions.key = "";
183
+ */
184
+}
185
+
186
+void dict_mssql_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
187
+ struct mssql_instance *p = value;
188
+ const char *instance = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
189
+
190
+ initialize_mssql_objects(p, instance);
191
+ initialize_mssql_keys(p);
192
+}
193
+
194
+static int mssql_fill_dictionary() {
195
+ HKEY hKey;
196
+ LSTATUS ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
197
+ "SOFTWARE\\Microsoft\\Microsoft SQL Server\\Instance Names\\SQL",
198
+ 0,
199
+ KEY_READ,
200
+ &hKey);
201
+ if (ret != ERROR_SUCCESS)
202
+ return -1;
203
+
204
+ DWORD values = 0;
205
+
206
+ ret = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &values, NULL, NULL, NULL, NULL);
207
+ if (ret != ERROR_SUCCESS) {
208
+ goto endMSSQLFillDict;
209
+ }
210
+
211
+ if (!values) {
212
+ ret = ERROR_PATH_NOT_FOUND;
213
+ goto endMSSQLFillDict;
214
+ }
215
+
216
+// https://learn.microsoft.com/en-us/windows/win32/sysinfo/enumerating-registry-subkeys
217
+#define REGISTRY_MAX_VALUE 16383
218
+
219
+ DWORD i;
220
+ char avalue[REGISTRY_MAX_VALUE] = {'\0'};
221
+ DWORD length = REGISTRY_MAX_VALUE;
222
+ for (i = 0; i < values; i++) {
223
+ avalue[0] = '\0';
224
+
225
+ ret = RegEnumValue(hKey, i, avalue, &length, NULL, NULL, NULL, NULL);
226
+ if (ret != ERROR_SUCCESS)
227
+ continue;
228
+
229
+ struct mssql_instance *p = dictionary_set(mssql_instances, avalue, NULL, sizeof(*p));
230
+ }
231
+
232
+endMSSQLFillDict:
233
+ RegCloseKey(hKey);
234
+
235
+ return (ret == ERROR_SUCCESS) ? 0 : -1;
236
+}
237
+
238
+static int initialize(void) {
239
+ mssql_instances = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
240
+ DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_instance));
241
+
242
+ dictionary_register_insert_callback(mssql_instances, dict_mssql_insert_cb, NULL);
243
+
244
+ if (mssql_fill_dictionary()) {
245
+ return -1;
246
+ }
247
+
248
+ return 0;
249
+}
250
+
251
+static void do_mssql_general_stats(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *p, int update_every)
252
+{
253
+ char id[RRD_ID_LENGTH_MAX + 1];
254
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, p->objectName[NETDATA_MSSQL_GENERAL_STATS]);
255
+ if (!pObjectType)
256
+ return;
257
+
258
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLUserConnections)) {
259
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_user_connection", p->instanceID);
260
+ if (!p->st_user_connections) {
261
+ p->st_user_connections = rrdset_create_localhost("mssql"
262
+ , id, NULL
263
+ , "connections"
264
+ , "mssql.instance_user_connection"
265
+ , "User connections"
266
+ , "connections"
267
+ , PLUGIN_WINDOWS_NAME
268
+ , "PerflibMSSQL"
269
+ , PRIO_MSSQL_USER_CONNECTIONS
270
+ , update_every
271
+ , RRDSET_TYPE_LINE
272
+ );
273
+
274
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_genstats_user_connections", p->instanceID);
275
+ p->rd_user_connections = rrddim_add(p->st_user_connections,
276
+ id,
277
+ "user",
278
+ 1,
279
+ 1,
280
+ RRD_ALGORITHM_ABSOLUTE);
281
+
282
+ rrdlabels_add(p->st_user_connections->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
283
+ }
284
+
285
+ rrddim_set_by_pointer(p->st_user_connections,
286
+ p->rd_user_connections,
287
+ (collected_number)p->MSSQLUserConnections.current.Data);
288
+ rrdset_done(p->st_user_connections);
289
+ }
290
+
291
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLBlockedProcesses)) {
292
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_blocked_process", p->instanceID);
293
+ if (!p->st_process_blocked) {
294
+ p->st_process_blocked = rrdset_create_localhost("mssql"
295
+ , id, NULL
296
+ , "processes"
297
+ , "mssql.instance_blocked_processes"
298
+ , "Blocked processes"
299
+ , "process"
300
+ , PLUGIN_WINDOWS_NAME
301
+ , "PerflibMSSQL"
302
+ , PRIO_MSSQL_BLOCKED_PROCESSES
303
+ , update_every
304
+ , RRDSET_TYPE_LINE
305
+ );
306
+
307
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_genstats_blocked_processes", p->instanceID);
308
+ p->rd_process_blocked = rrddim_add(p->st_process_blocked,
309
+ id,
310
+ "blocked",
311
+ 1,
312
+ 1,
313
+ RRD_ALGORITHM_ABSOLUTE);
314
+
315
+ rrdlabels_add(p->st_process_blocked->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
316
+ }
317
+
318
+ rrddim_set_by_pointer(p->st_process_blocked,
319
+ p->rd_process_blocked,
320
+ (collected_number)p->MSSQLBlockedProcesses.current.Data);
321
+ rrdset_done(p->st_process_blocked);
322
+ }
323
+}
324
+
325
+static void do_mssql_sql_statistics(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *p, int update_every)
326
+{
327
+ char id[RRD_ID_LENGTH_MAX + 1];
328
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, p->objectName[NETDATA_MSSQL_SQL_STATS]);
329
+ if (!pObjectType)
330
+ return;
331
+
332
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLStatsAutoParameterization)) {
333
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_auto_parameterization_attempts", p->instanceID);
334
+ if (!p->st_stats_auto_param) {
335
+ p->st_stats_auto_param = rrdset_create_localhost("mssql"
336
+ , id, NULL
337
+ , "sql activity"
338
+ , "mssql.instance_sqlstats_auto_parameterization_attempts"
339
+ , "Failed auto-parameterization attempts"
340
+ , "attempts/s"
341
+ , PLUGIN_WINDOWS_NAME
342
+ , "PerflibMSSQL"
343
+ , PRIO_MSSQL_STATS_AUTO_PARAMETRIZATION
344
+ , update_every
345
+ , RRDSET_TYPE_LINE
346
+ );
347
+
348
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_sqlstats_auto_parameterization_attempts", p->instanceID);
349
+ p->rd_stats_auto_param = rrddim_add(p->st_stats_auto_param,
350
+ id,
351
+ "failed",
352
+ 1,
353
+ 1,
354
+ RRD_ALGORITHM_INCREMENTAL);
355
+
356
+ rrdlabels_add(p->st_stats_auto_param->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
357
+ }
358
+
359
+ rrddim_set_by_pointer(p->st_stats_auto_param,
360
+ p->rd_stats_auto_param,
361
+ (collected_number)p->MSSQLStatsAutoParameterization.current.Data);
362
+ rrdset_done(p->st_stats_auto_param);
363
+ }
364
+
365
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLStatsBatchRequests)) {
366
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_batch_requests", p->instanceID);
367
+ if (!p->st_stats_batch_request) {
368
+ p->st_stats_batch_request = rrdset_create_localhost("mssql"
369
+ , id, NULL
370
+ , "sql activity"
371
+ , "mssql.instance_sqlstats_batch_requests"
372
+ , "Total of batches requests"
373
+ , "requests/s"
374
+ , PLUGIN_WINDOWS_NAME
375
+ , "PerflibMSSQL"
376
+ , PRIO_MSSQL_STATS_BATCH_REQUEST
377
+ , update_every
378
+ , RRDSET_TYPE_LINE
379
+ );
380
+
381
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_sqlstats_batch_requests", p->instanceID);
382
+ p->rd_stats_batch_request = rrddim_add(p->st_stats_batch_request,
383
+ id,
384
+ "batch",
385
+ 1,
386
+ 1,
387
+ RRD_ALGORITHM_INCREMENTAL);
388
+
389
+ rrdlabels_add(p->st_stats_batch_request->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
390
+ }
391
+
392
+ rrddim_set_by_pointer(p->st_stats_batch_request,
393
+ p->rd_stats_batch_request,
394
+ (collected_number)p->MSSQLStatsBatchRequests.current.Data);
395
+ rrdset_done(p->st_stats_batch_request);
396
+ }
397
+
398
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLStatSafeAutoParameterization)) {
399
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_safe_auto_parameterization_attempts", p->instanceID);
400
+ if (!p->st_stats_safe_auto) {
401
+ p->st_stats_safe_auto = rrdset_create_localhost("mssql"
402
+ , id, NULL
403
+ , "sql activity"
404
+ , "mssql.instance_sqlstats_safe_auto_parameterization_attempts"
405
+ , "Safe auto-parameterization attempts"
406
+ , "attempts/s"
407
+ , PLUGIN_WINDOWS_NAME
408
+ , "PerflibMSSQL"
409
+ , PRIO_MSSQL_STATS_SAFE_AUTO_PARAMETRIZATION
410
+ , update_every
411
+ , RRDSET_TYPE_LINE
412
+ );
413
+
414
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_sqlstats_safe_auto_parameterization_attempts", p->instanceID);
415
+ p->rd_stats_safe_auto = rrddim_add(p->st_stats_safe_auto,
416
+ id,
417
+ "safe",
418
+ 1,
419
+ 1,
420
+ RRD_ALGORITHM_INCREMENTAL);
421
+
422
+ rrdlabels_add(p->st_stats_safe_auto->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
423
+ }
424
+
425
+ rrddim_set_by_pointer(p->st_stats_safe_auto,
426
+ p->rd_stats_safe_auto,
427
+ (collected_number)p->MSSQLStatSafeAutoParameterization.current.Data);
428
+ rrdset_done(p->st_stats_safe_auto);
429
+ }
430
+
431
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLCompilations)) {
432
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_sql_compilations", p->instanceID);
433
+ if (!p->st_stats_compilation) {
434
+ p->st_stats_compilation = rrdset_create_localhost("mssql"
435
+ , id, NULL
436
+ , "sql activity"
437
+ , "mssql.instance_sqlstats_sql_compilations"
438
+ , "SQL compilations"
439
+ , "compilations/s"
440
+ , PLUGIN_WINDOWS_NAME
441
+ , "PerflibMSSQL"
442
+ , PRIO_MSSQL_STATS_COMPILATIONS
443
+ , update_every
444
+ , RRDSET_TYPE_LINE
445
+ );
446
+
447
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_sqlstats_sql_compilations", p->instanceID);
448
+ p->rd_stats_compilation = rrddim_add(p->st_stats_compilation,
449
+ id,
450
+ "compilations",
451
+ 1,
452
+ 1,
453
+ RRD_ALGORITHM_INCREMENTAL);
454
+
455
+ rrdlabels_add(p->st_stats_compilation->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
456
+ }
457
+
458
+ rrddim_set_by_pointer(p->st_stats_compilation,
459
+ p->rd_stats_compilation,
460
+ (collected_number)p->MSSQLCompilations.current.Data);
461
+ rrdset_done(p->st_stats_compilation);
462
+ }
463
+
464
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLRecompilations)) {
465
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sqlstats_sql_recompilations", p->instanceID);
466
+ if (!p->st_stats_recompiles) {
467
+ p->st_stats_recompiles = rrdset_create_localhost("mssql"
468
+ , id, NULL
469
+ , "sql activity"
470
+ , "mssql.instance_sqlstats_sql_recompilations"
471
+ , "SQL re-compilations"
472
+ , "recompiles/"
473
+ , PLUGIN_WINDOWS_NAME
474
+ , "PerflibMSSQL"
475
+ , PRIO_MSSQL_STATS_RECOMPILATIONS
476
+ , update_every
477
+ , RRDSET_TYPE_LINE
478
+ );
479
+
480
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_sqlstats_sql_recompilations", p->instanceID);
481
+ p->rd_stats_recompiles = rrddim_add(p->st_stats_recompiles,
482
+ id,
483
+ "recompiles",
484
+ 1,
485
+ 1,
486
+ RRD_ALGORITHM_INCREMENTAL);
487
+
488
+ rrdlabels_add(p->st_stats_recompiles->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
489
+ }
490
+
491
+ rrddim_set_by_pointer(p->st_stats_recompiles,
492
+ p->rd_stats_recompiles,
493
+ (collected_number)p->MSSQLRecompilations.current.Data);
494
+ rrdset_done(p->st_stats_recompiles);
495
+ }
496
+}
497
+
498
+static void do_mssql_buffer_management(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *p, int update_every)
499
+{
500
+ char id[RRD_ID_LENGTH_MAX + 1];
501
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, p->objectName[NETDATA_MSSQL_BUFFER_MANAGEMENT]);
502
+ if (!pObjectType)
503
+ return;
504
+
505
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLBufferCacheHits)) {
506
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_cache_hit_ratio", p->instanceID);
507
+ if (!p->st_buff_cache_hits) {
508
+ p->st_buff_cache_hits = rrdset_create_localhost("mssql"
509
+ , id, NULL
510
+ , "buffer cache"
511
+ , "mssql.instance_cache_hit_ratio"
512
+ , "Buffer Cache hit ratio"
513
+ , "percentage"
514
+ , PLUGIN_WINDOWS_NAME
515
+ , "PerflibMSSQL"
516
+ , PRIO_MSSQL_BUFF_CACHE_HIT_RATIO
517
+ , update_every
518
+ , RRDSET_TYPE_LINE
519
+ );
520
+
521
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_cache_hit_ratio", p->instanceID);
522
+ p->rd_buff_cache_hits = rrddim_add(p->st_buff_cache_hits,
523
+ id,
524
+ "hit_ratio",
525
+ 1,
526
+ 1,
527
+ RRD_ALGORITHM_ABSOLUTE);
528
+
529
+ rrdlabels_add(p->st_buff_cache_hits->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
530
+ }
531
+
532
+ rrddim_set_by_pointer(p->st_buff_cache_hits,
533
+ p->rd_buff_cache_hits,
534
+ (collected_number)p->MSSQLBufferCacheHits.current.Data);
535
+ rrdset_done(p->st_buff_cache_hits);
536
+ }
537
+
538
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLBufferCheckpointPages)) {
539
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_checkpoint_pages", p->instanceID);
540
+ if (!p->st_buff_checkpoint_pages) {
541
+ p->st_buff_checkpoint_pages = rrdset_create_localhost("mssql"
542
+ , id, NULL
543
+ , "buffer cache"
544
+ , "mssql.instance_bufman_checkpoint_pages"
545
+ , "Flushed pages"
546
+ , "pages/s"
547
+ , PLUGIN_WINDOWS_NAME
548
+ , "PerflibMSSQL"
549
+ , PRIO_MSSQL_BUFF_CHECKPOINT_PAGES
550
+ , update_every
551
+ , RRDSET_TYPE_LINE
552
+ );
553
+
554
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_bufman_checkpoint_pages", p->instanceID);
555
+ p->rd_buff_checkpoint_pages = rrddim_add(p->st_buff_checkpoint_pages,
556
+ id,
557
+ "flushed",
558
+ 1,
559
+ 1,
560
+ RRD_ALGORITHM_INCREMENTAL);
561
+
562
+ rrdlabels_add(p->st_buff_checkpoint_pages->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
563
+ }
564
+
565
+ rrddim_set_by_pointer(p->st_buff_checkpoint_pages,
566
+ p->rd_buff_checkpoint_pages,
567
+ (collected_number)p->MSSQLBufferCheckpointPages.current.Data);
568
+ rrdset_done(p->st_buff_checkpoint_pages);
569
+ }
570
+
571
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLBufferPageLifeExpectancy)) {
572
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_page_life_expectancy", p->instanceID);
573
+ if (!p->st_buff_cache_page_life_expectancy) {
574
+ p->st_buff_cache_page_life_expectancy = rrdset_create_localhost("mssql"
575
+ , id, NULL
576
+ , "buffer cache"
577
+ , "mssql.instance_bufman_page_life_expectancy"
578
+ , "Page life expectancy"
579
+ , "seconds"
580
+ , PLUGIN_WINDOWS_NAME
581
+ , "PerflibMSSQL"
582
+ , PRIO_MSSQL_BUFF_PAGE_LIFE_EXPECTANCY
583
+ , update_every
584
+ , RRDSET_TYPE_LINE
585
+ );
586
+
587
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_bufman_page_life_expectancy_seconds", p->instanceID);
588
+ p->rd_buff_cache_page_life_expectancy = rrddim_add(p->st_buff_cache_page_life_expectancy,
589
+ id,
590
+ "life_expectancy",
591
+ 1,
592
+ 1,
593
+ RRD_ALGORITHM_ABSOLUTE);
594
+
595
+ rrdlabels_add(p->st_buff_cache_page_life_expectancy->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
596
+ }
597
+
598
+ rrddim_set_by_pointer(p->st_buff_cache_page_life_expectancy,
599
+ p->rd_buff_cache_page_life_expectancy,
600
+ (collected_number)p->MSSQLBufferPageLifeExpectancy.current.Data);
601
+ rrdset_done(p->st_buff_cache_page_life_expectancy);
602
+ }
603
+
604
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLBufferPageReads) &&
605
+ perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLBufferPageWrites)) {
606
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_bufman_iops", p->instanceID);
607
+ if (!p->st_buff_page_iops) {
608
+ p->st_buff_page_iops = rrdset_create_localhost("mssql"
609
+ , id, NULL
610
+ , "buffer cache"
611
+ , "mssql.instance_bufman_iops"
612
+ , "Number of pages input and output"
613
+ , "pages/s"
614
+ , PLUGIN_WINDOWS_NAME
615
+ , "PerflibMSSQL"
616
+ , PRIO_MSSQL_BUFF_MAN_IOPS
617
+ , update_every
618
+ , RRDSET_TYPE_LINE
619
+ );
620
+
621
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_bufman_page_reads", p->instanceID);
622
+ p->rd_buff_page_reads = rrddim_add(p->st_buff_page_iops,
623
+ id,
624
+ "read",
625
+ 1,
626
+ 1,
627
+ RRD_ALGORITHM_INCREMENTAL);
628
+
629
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_bufman_page_writes", p->instanceID);
630
+ p->rd_buff_page_writes = rrddim_add(p->st_buff_page_iops,
631
+ id,
632
+ "written",
633
+ -1,
634
+ 1,
635
+ RRD_ALGORITHM_INCREMENTAL);
636
+
637
+ rrdlabels_add(p->st_buff_page_iops->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
638
+ }
639
+
640
+ rrddim_set_by_pointer(p->st_buff_page_iops,
641
+ p->rd_buff_page_reads,
642
+ (collected_number)p->MSSQLBufferPageReads.current.Data);
643
+
644
+ rrddim_set_by_pointer(p->st_buff_page_iops,
645
+ p->rd_buff_page_writes,
646
+ (collected_number)p->MSSQLBufferPageWrites.current.Data);
647
+ rrdset_done(p->st_buff_page_iops);
648
+ }
649
+}
650
+
651
+static void do_mssql_access_methods(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *p, int update_every)
652
+{
653
+ char id[RRD_ID_LENGTH_MAX + 1];
654
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, p->objectName[NETDATA_MSSQL_ACCESS_METHODS]);
655
+ if (!pObjectType)
656
+ return;
657
+
658
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLAccessMethodPageSplits)) {
659
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_accessmethods_page_splits", p->instanceID);
660
+ if (!p->st_access_method_page_splits) {
661
+ p->st_access_method_page_splits = rrdset_create_localhost("mssql"
662
+ , id, NULL
663
+ , "buffer cache"
664
+ , "mssql.instance_accessmethods_page_splits"
665
+ , "Page splits"
666
+ , "splits/s"
667
+ , PLUGIN_WINDOWS_NAME
668
+ , "PerflibMSSQL"
669
+ , PRIO_MSSQL_BUFF_METHODS_PAGE_SPLIT
670
+ , update_every
671
+ , RRDSET_TYPE_LINE
672
+ );
673
+
674
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_accessmethods_page_splits", p->instanceID);
675
+ p->rd_access_method_page_splits = rrddim_add(p->st_access_method_page_splits,
676
+ id,
677
+ "page",
678
+ 1,
679
+ 1,
680
+ RRD_ALGORITHM_INCREMENTAL);
681
+
682
+ rrdlabels_add(p->st_access_method_page_splits->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
683
+ }
684
+
685
+ rrddim_set_by_pointer(p->st_access_method_page_splits,
686
+ p->rd_access_method_page_splits,
687
+ (collected_number)p->MSSQLAccessMethodPageSplits.current.Data);
688
+ rrdset_done(p->st_access_method_page_splits);
689
+ }
690
+}
691
+
692
+static void do_mssql_errors(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *p, int update_every)
693
+{
694
+ char id[RRD_ID_LENGTH_MAX + 1];
695
+ PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, p->objectName[NETDATA_MSSQL_SQL_ERRORS]);
696
+ if (!pObjectType)
697
+ return;
698
+
699
+ if (perflibGetObjectCounter(pDataBlock, pObjectType, &p->MSSQLSQLErrorsTotal)) {
700
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_sql_errors_total", p->instanceID);
701
+ if (!p->st_sql_errors) {
702
+ p->st_sql_errors = rrdset_create_localhost("mssql"
703
+ , id, NULL
704
+ , "Errors"
705
+ , "mssql.instance_sql_errors"
706
+ , "Errors"
707
+ , "errors/s"
708
+ , PLUGIN_WINDOWS_NAME
709
+ , "PerflibMSSQL"
710
+ , PRIO_MSSQL_SQL_ERRORS
711
+ , update_every
712
+ , RRDSET_TYPE_LINE
713
+ );
714
+
715
+ snprintfz(id, RRD_ID_LENGTH_MAX, "mssql_instance_%s_sql_errors_total", p->instanceID);
716
+ p->rd_sql_errors = rrddim_add(p->st_sql_errors,
717
+ id,
718
+ "errors",
719
+ 1,
720
+ 1,
721
+ RRD_ALGORITHM_INCREMENTAL);
722
+
723
+ rrdlabels_add(p->st_sql_errors->rrdlabels, "mssql_instance", p->instanceID, RRDLABEL_SRC_AUTO);
724
+ }
725
+
726
+ rrddim_set_by_pointer(p->st_sql_errors,
727
+ p->rd_sql_errors,
728
+ (collected_number)p->MSSQLAccessMethodPageSplits.current.Data);
729
+ rrdset_done(p->st_sql_errors);
730
+ }
731
+}
732
+
733
+int dict_mssql_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
734
+ struct mssql_instance *p = value;
735
+ int *update_every = data;
736
+
737
+ static void (*doMSSQL[])(PERF_DATA_BLOCK *, struct mssql_instance *, int) = {
738
+ do_mssql_general_stats,
739
+ do_mssql_errors,
740
+ NULL, NULL, NULL,
741
+ do_mssql_buffer_management,
742
+ do_mssql_sql_statistics,
743
+ NULL,
744
+ do_mssql_access_methods
745
+ };
746
+
747
+ DWORD i;
748
+ for (i = 0; i < NETDATA_MSSQL_METRICS_END; i++) {
749
+ if (!doMSSQL[i])
750
+ continue;
751
+
752
+ DWORD id = RegistryFindIDByName(p->objectName[i]);
753
+ if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
754
+ return -1;
755
+
756
+ PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
757
+ if(!pDataBlock) return -1;
758
+
759
+ doMSSQL[i](pDataBlock, p, *update_every);
760
+ }
761
+
762
+ return 1;
763
+}
764
+
765
+int do_PerflibMSSQL(int update_every, usec_t dt __maybe_unused)
766
+{
767
+ static bool initialized = false;
768
+
769
+ if (unlikely(!initialized)) {
770
+ if (initialize())
771
+ return -1;
772
+
773
+ initialized = true;
774
+ }
775
+
776
+ dictionary_sorted_walkthrough_read(mssql_instances, dict_mssql_charts_cb, &update_every);
777
+
778
+ return 0;
779
+}
src/collectors/windows.plugin/windows_plugin.c
+1
@@ -29,6 +29,7 @@ static struct proc_module {
29
{.name = "PerflibThermalZone", .dim = "PerflibThermalZone", .enabled = CONFIG_BOOLEAN_NO, .func = do_PerflibThermalZone},
30
31
{.name = "PerflibWebService", .dim = "PerflibWebService", .enabled = CONFIG_BOOLEAN_YES, .func = do_PerflibWebService},
32
+ {.name = "PerflibMSSQL", .dim = "PerflibMSSQL", .enabled = CONFIG_BOOLEAN_YES, .func = do_PerflibMSSQL},
33
34
// the terminator of this array
35
{.name = NULL, .dim = NULL, .func = NULL}
src/collectors/windows.plugin/windows_plugin.h
+20
-1
@@ -26,6 +26,7 @@ int do_PerflibMemory(int update_every, usec_t dt);
26
int do_PerflibObjects(int update_every, usec_t dt);
27
int do_PerflibThermalZone(int update_every, usec_t dt);
28
int do_PerflibWebService(int update_every, usec_t dt);
29
+int do_PerflibMSSQL(int update_every, usec_t dt);
30
31
enum PERFLIB_PRIO {
32
PRIO_WEBSITE_IIS_TRAFFIC = 21000, // PRIO selected, because APPS is using 20YYY
@@ -38,7 +39,25 @@ enum PERFLIB_PRIO {
39
PRIO_WEBSITE_IIS_ISAPI_EXT_REQUEST_RATE,
40
PRIO_WEBSITE_IIS_ERRORS_RATE,
41
PRIO_WEBSITE_IIS_LOGON_ATTEMPTS,
41
- PRIO_WEBSITE_IIS_UPTIME
42
+ PRIO_WEBSITE_IIS_UPTIME,
43
+
44
+ PRIO_MSSQL_USER_CONNECTIONS,
45
+
46
+ PRIO_MSSQL_STATS_BATCH_REQUEST,
47
+ PRIO_MSSQL_STATS_COMPILATIONS,
48
+ PRIO_MSSQL_STATS_RECOMPILATIONS,
49
+ PRIO_MSSQL_STATS_AUTO_PARAMETRIZATION,
50
+ PRIO_MSSQL_STATS_SAFE_AUTO_PARAMETRIZATION,
51
+
52
+ PRIO_MSSQL_BLOCKED_PROCESSES,
53
+
54
+ PRIO_MSSQL_BUFF_CACHE_HIT_RATIO,
55
+ PRIO_MSSQL_BUFF_MAN_IOPS,
56
+ PRIO_MSSQL_BUFF_CHECKPOINT_PAGES,
57
+ PRIO_MSSQL_BUFF_METHODS_PAGE_SPLIT,
58
+ PRIO_MSSQL_BUFF_PAGE_LIFE_EXPECTANCY,
59
+
60
+ PRIO_MSSQL_SQL_ERRORS
61
};
62
63
#endif //NETDATA_WINDOWS_PLUGIN_H