@cryptotaxi247 / netdata-1 / commits / 88d6f0fcd

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