@cryptotaxi247 / netdata-1 / commits / 0d63413e2

Split collection (Windows.plugin) (#20677)

thiagoftsm committed Jul 31, 2025 at 13:25 UTC 0d63413e2a79c954692c1c5c108e96b218b1dc22
3 files changed +199 -152
src/collectors/windows.plugin/README.md
+6
@@ -147,9 +147,11 @@ Add the SQL Server connection details to your `netdata.conf` file:
147 [plugin:windows:PerflibMSSQL]
148 driver = SQL Server
149 server = 127.0.0.1\\Dev, 1433
150 + instance = Dev
151 #address = [protocol:]Address[,port |\pipe\pipename]
152 uid = netdata_user
153 pwd = 1ReallyStrongPasswordShouldBeInsertedHere
154 + express = no
155 # additional instances = 0
156 #windows authentication = no
157 ```
@@ -160,11 +162,15 @@ Configuration options:
162 |--------------------------|------------------------------------------------------------------------------|
163 | `driver` | ODBC driver used to connect to the SQL Server |
164 | `server` | Server address or instance name |
165 +| `instance` | Instance name |
166 | `address` | Alternative to `server`; supports named pipes if the server supports them |
167 | `uid` | SQL Server user identifier |
168 | `pwd` | Password for the specified user |
169 | `additional instances` | Number of additional SQL Server instances to monitor |
170 | `windows authentication` | Set to `yes` to use Windows credentials instead of SQL Server authentication |
171 +| `express` | Set to `yes` when running SQL Express version |
172 +
173 +The `instance` option is required when Netdata pulls data from outside an MSSQL server.
174
175 For more information on connection parameters, see the [Microsoft Official Documentation](https://learn.microsoft.com/en-us/sql/relational-databases/native-client/applications/using-connection-string-keywords-with-sql-server-native-client?view=sql-server-ver15&viewFallbackFrom=sql-server-ver16).
176
src/collectors/windows.plugin/metadata.yaml
+14
@@ -1891,6 +1891,10 @@ modules:
1891 description: ODBC driver used to connect to the SQL Server.
1892 default_value: SQL Server
1893 required: false
1894 + - name: instance
1895 + description: Instance name
1896 + default_value: empty
1897 + required: true
1898 - name: server
1899 description: Server address or instance name.
1900 default_value: empty
@@ -1915,6 +1919,10 @@ modules:
1919 description: Set to yes to use Windows credentials instead of SQL Server authentication.
1920 default_value: no
1921 required: false
1922 + - name: express
1923 + description: Set to yes when running SQL Express version.
1924 + default_value: no
1925 + required: false
1926 examples:
1927 folding:
1928 enabled: true
@@ -1927,9 +1935,11 @@ modules:
1935 config: |
1936 [plugin:windows:PerflibMSSQL]
1937 driver = SQL Server
1938 + instance = Dev
1939 server = 127.0.0.1\\Dev, 1433
1940 uid = netdata_user
1941 pwd = 1ReallyStrongPasswordShouldBeInsertedHere
1942 + express = no
1943 - name: Multiple Instances
1944 description: An example configuration with two instances.
1945 folding:
@@ -1938,14 +1948,18 @@ modules:
1948 [plugin:windows:PerflibMSSQL]
1949 driver = SQL Server
1950 server = 127.0.0.1\\Dev, 1433
1951 + instance = Dev
1952 uid = netdata_user
1953 pwd = 1ReallyStrongPasswordShouldBeInsertedHere
1954 additional instances = 1
1955 + express = no
1956 [plugin:windows:PerflibMSSQL1]
1957 driver = SQL Server
1958 server = 127.0.0.1\\Production, 1434
1959 + instance = Production
1960 uid = netdata_user
1961 pwd = AnotherReallyStrongPasswordShouldBeInsertedHere2
1962 + express = no
1963 troubleshooting:
1964 problems:
1965 list: []
src/collectors/windows.plugin/perflib-mssql.c
+179 -152
@@ -17,9 +17,8 @@
17 #define SQLSERVER_MAX_NAME_LENGTH NETDATA_MAX_INSTANCE_OBJECT
18 #define NETDATA_MSSQL_NEXT_TRY (60)
19
20 -BOOL is_sqlexpress = FALSE;
21 -
20 struct netdata_mssql_conn {
21 + const char *instance;
22 const char *driver;
23 const char *server;
24 const char *address;
@@ -27,6 +26,7 @@ struct netdata_mssql_conn {
26 const char *password;
27 int instances;
28 bool windows_auth;
29 + bool is_sqlexpress;
30
31 SQLCHAR *connectionString;
32
@@ -43,17 +43,20 @@ struct netdata_mssql_conn {
43 BOOL is_connected;
44 };
45
46 +DICTIONARY *conn_options;
47 +
48 enum netdata_mssql_metrics {
49 NETDATA_MSSQL_GENERAL_STATS,
50 NETDATA_MSSQL_SQL_ERRORS,
49 - NETDATA_MSSQL_DATABASE,
50 - NETDATA_MSSQL_LOCKS,
51 - NETDATA_MSSQL_WAITS,
51 NETDATA_MSSQL_MEMORY,
52 NETDATA_MSSQL_BUFFER_MANAGEMENT,
53 NETDATA_MSSQL_SQL_STATS,
54 NETDATA_MSSQL_ACCESS_METHODS,
55
56 + NETDATA_MSSQL_DATABASE,
57 + NETDATA_MSSQL_LOCKS,
58 + NETDATA_MSSQL_WAITS,
59 +
60 NETDATA_MSSQL_METRICS_END
61 };
62
@@ -87,7 +90,7 @@ struct mssql_instance {
90 char *instanceID;
91 int update_every;
92
90 - struct netdata_mssql_conn conn;
93 + struct netdata_mssql_conn *conn;
94
95 char *objectName[NETDATA_MSSQL_METRICS_END];
96
@@ -355,31 +358,31 @@ void dict_mssql_fill_transactions(struct mssql_db_instance *mdi, const char *dbn
358 dbname,
359 dbname);
360
358 - SQLRETURN ret = SQLExecDirect(mdi->parent->conn.dbTransactionSTMT, (SQLCHAR *)query, SQL_NTS);
361 + SQLRETURN ret = SQLExecDirect(mdi->parent->conn->dbTransactionSTMT, (SQLCHAR *)query, SQL_NTS);
362 if (ret != SQL_SUCCESS) {
363 mdi->collecting_data = false;
364 netdata_MSSQL_error(
362 - SQL_HANDLE_STMT, mdi->parent->conn.dbTransactionSTMT, NETDATA_MSSQL_ODBC_QUERY, mdi->parent->instanceID);
365 + SQL_HANDLE_STMT, mdi->parent->conn->dbTransactionSTMT, NETDATA_MSSQL_ODBC_QUERY, mdi->parent->instanceID);
366 goto endtransactions;
367 }
368
369 ret = SQLBindCol(
367 - mdi->parent->conn.dbTransactionSTMT, 1, SQL_C_CHAR, object_name, sizeof(object_name), &col_object_len);
370 + mdi->parent->conn->dbTransactionSTMT, 1, SQL_C_CHAR, object_name, sizeof(object_name), &col_object_len);
371 if (ret != SQL_SUCCESS) {
372 netdata_MSSQL_error(
370 - SQL_HANDLE_STMT, mdi->parent->conn.dbTransactionSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
373 + SQL_HANDLE_STMT, mdi->parent->conn->dbTransactionSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
374 goto endtransactions;
375 }
376
374 - ret = SQLBindCol(mdi->parent->conn.dbTransactionSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
377 + ret = SQLBindCol(mdi->parent->conn->dbTransactionSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
378 if (ret != SQL_SUCCESS) {
379 netdata_MSSQL_error(
377 - SQL_HANDLE_STMT, mdi->parent->conn.dbTransactionSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
380 + SQL_HANDLE_STMT, mdi->parent->conn->dbTransactionSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
381 goto endtransactions;
382 }
383
384 do {
382 - ret = SQLFetch(mdi->parent->conn.dbTransactionSTMT);
385 + ret = SQLFetch(mdi->parent->conn->dbTransactionSTMT);
386 switch (ret) {
387 case SQL_SUCCESS:
388 case SQL_SUCCESS_WITH_INFO:
@@ -429,7 +432,7 @@ void dict_mssql_fill_transactions(struct mssql_db_instance *mdi, const char *dbn
432 } while (true);
433
434 endtransactions:
432 - netdata_MSSQL_release_results(mdi->parent->conn.dbTransactionSTMT);
435 + netdata_MSSQL_release_results(mdi->parent->conn->dbTransactionSTMT);
436 }
437
438 void dict_mssql_fill_locks(struct mssql_db_instance *mdi, const char *dbname)
@@ -447,31 +450,31 @@ void dict_mssql_fill_locks(struct mssql_db_instance *mdi, const char *dbname)
450 dbname,
451 dbname);
452
450 - SQLRETURN ret = SQLExecDirect(mdi->parent->conn.dbLocksSTMT, (SQLCHAR *)query, SQL_NTS);
453 + SQLRETURN ret = SQLExecDirect(mdi->parent->conn->dbLocksSTMT, (SQLCHAR *)query, SQL_NTS);
454 if (ret != SQL_SUCCESS) {
455 mdi->collecting_data = false;
456 netdata_MSSQL_error(
454 - SQL_HANDLE_STMT, mdi->parent->conn.dbLocksSTMT, NETDATA_MSSQL_ODBC_QUERY, mdi->parent->instanceID);
457 + SQL_HANDLE_STMT, mdi->parent->conn->dbLocksSTMT, NETDATA_MSSQL_ODBC_QUERY, mdi->parent->instanceID);
458 goto endlocks;
459 }
460
458 - ret =
459 - SQLBindCol(mdi->parent->conn.dbLocksSTMT, 1, SQL_C_CHAR, resource_type, sizeof(resource_type), &col_object_len);
461 + ret = SQLBindCol(
462 + mdi->parent->conn->dbLocksSTMT, 1, SQL_C_CHAR, resource_type, sizeof(resource_type), &col_object_len);
463 if (ret != SQL_SUCCESS) {
464 netdata_MSSQL_error(
462 - SQL_HANDLE_STMT, mdi->parent->conn.dbLocksSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
465 + SQL_HANDLE_STMT, mdi->parent->conn->dbLocksSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
466 goto endlocks;
467 }
468
466 - ret = SQLBindCol(mdi->parent->conn.dbLocksSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
469 + ret = SQLBindCol(mdi->parent->conn->dbLocksSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
470 if (ret != SQL_SUCCESS) {
471 netdata_MSSQL_error(
469 - SQL_HANDLE_STMT, mdi->parent->conn.dbLocksSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
472 + SQL_HANDLE_STMT, mdi->parent->conn->dbLocksSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
473 goto endlocks;
474 }
475
476 do {
474 - ret = SQLFetch(mdi->parent->conn.dbLocksSTMT);
477 + ret = SQLFetch(mdi->parent->conn->dbLocksSTMT);
478 switch (ret) {
479 case SQL_SUCCESS:
480 case SQL_SUCCESS_WITH_INFO:
@@ -494,7 +497,7 @@ void dict_mssql_fill_locks(struct mssql_db_instance *mdi, const char *dbname)
497 } while (true);
498
499 endlocks:
497 - netdata_MSSQL_release_results(mdi->parent->conn.dbLocksSTMT);
500 + netdata_MSSQL_release_results(mdi->parent->conn->dbLocksSTMT);
501 }
502
503 int dict_mssql_fill_waits(struct mssql_instance *mi)
@@ -510,58 +513,59 @@ int dict_mssql_fill_waits(struct mssql_instance *mi)
513 SQLLEN col_wait_type_len = 0, col_total_wait_len = 0, col_resource_wait_len = 0, col_signal_wait_len = 0,
514 col_max_wait_len = 0, col_waiting_tasks_len = 0, col_wait_category_len = 0;
515
513 - SQLRETURN ret = SQLExecDirect(mi->conn.dbWaitsSTMT, (SQLCHAR *)NETDATA_QUERY_CHECK_WAITS, SQL_NTS);
516 + SQLRETURN ret = SQLExecDirect(mi->conn->dbWaitsSTMT, (SQLCHAR *)NETDATA_QUERY_CHECK_WAITS, SQL_NTS);
517 if (ret != SQL_SUCCESS) {
515 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.dbWaitsSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
518 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
519 goto endwait;
520 }
521
519 - ret = SQLBindCol(mi->conn.dbWaitsSTMT, 1, SQL_C_CHAR, wait_type, sizeof(wait_type), &col_wait_type_len);
522 + ret = SQLBindCol(mi->conn->dbWaitsSTMT, 1, SQL_C_CHAR, wait_type, sizeof(wait_type), &col_wait_type_len);
523 if (ret != SQL_SUCCESS) {
521 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
524 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
525 goto endwait;
526 }
527
525 - ret = SQLBindCol(mi->conn.dbWaitsSTMT, 2, SQL_C_LONG, &total_wait, sizeof(total_wait), &col_total_wait_len);
528 + ret = SQLBindCol(mi->conn->dbWaitsSTMT, 2, SQL_C_LONG, &total_wait, sizeof(total_wait), &col_total_wait_len);
529 if (ret != SQL_SUCCESS) {
527 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
530 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
531 goto endwait;
532 }
533
534 ret =
532 - SQLBindCol(mi->conn.dbWaitsSTMT, 3, SQL_C_LONG, &resource_wait, sizeof(resource_wait), &col_resource_wait_len);
535 + SQLBindCol(mi->conn->dbWaitsSTMT, 3, SQL_C_LONG, &resource_wait, sizeof(resource_wait), &col_resource_wait_len);
536 if (ret != SQL_SUCCESS) {
534 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
537 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
538 goto endwait;
539 }
540
538 - ret = SQLBindCol(mi->conn.dbWaitsSTMT, 4, SQL_C_LONG, &signal_wait, sizeof(signal_wait), &col_signal_wait_len);
541 + ret = SQLBindCol(mi->conn->dbWaitsSTMT, 4, SQL_C_LONG, &signal_wait, sizeof(signal_wait), &col_signal_wait_len);
542 if (ret != SQL_SUCCESS) {
540 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
543 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
544 goto endwait;
545 }
546
544 - ret = SQLBindCol(mi->conn.dbWaitsSTMT, 5, SQL_C_LONG, &max_wait, sizeof(max_wait), &col_max_wait_len);
547 + ret = SQLBindCol(mi->conn->dbWaitsSTMT, 5, SQL_C_LONG, &max_wait, sizeof(max_wait), &col_max_wait_len);
548 if (ret != SQL_SUCCESS) {
546 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
549 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
550 goto endwait;
551 }
552
553 ret =
551 - SQLBindCol(mi->conn.dbWaitsSTMT, 6, SQL_C_LONG, &waiting_tasks, sizeof(waiting_tasks), &col_waiting_tasks_len);
554 + SQLBindCol(mi->conn->dbWaitsSTMT, 6, SQL_C_LONG, &waiting_tasks, sizeof(waiting_tasks), &col_waiting_tasks_len);
555 if (ret != SQL_SUCCESS) {
553 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
556 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
557 goto endwait;
558 }
559
557 - ret = SQLBindCol(mi->conn.dbWaitsSTMT, 7, SQL_C_CHAR, wait_category, sizeof(wait_category), &col_wait_category_len);
560 + ret =
561 + SQLBindCol(mi->conn->dbWaitsSTMT, 7, SQL_C_CHAR, wait_category, sizeof(wait_category), &col_wait_category_len);
562 if (ret != SQL_SUCCESS) {
559 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
563 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbWaitsSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
564 goto endwait;
565 }
566
567 do {
564 - ret = SQLFetch(mi->conn.dbWaitsSTMT);
568 + ret = SQLFetch(mi->conn->dbWaitsSTMT);
569 switch (ret) {
570 case SQL_SUCCESS:
571 case SQL_SUCCESS_WITH_INFO:
@@ -590,7 +594,7 @@ int dict_mssql_fill_waits(struct mssql_instance *mi)
594 } while (true);
595
596 endwait:
593 - netdata_MSSQL_release_results(mi->conn.dbWaitsSTMT);
597 + netdata_MSSQL_release_results(mi->conn->dbWaitsSTMT);
598
599 return success;
600 }
@@ -600,14 +604,14 @@ int dict_mssql_databases_run_queries(const DICTIONARY_ITEM *item __maybe_unused,
604 struct mssql_db_instance *mdi = value;
605 const char *dbname = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
606
603 - if (!mdi->collecting_data) {
607 + if (!mdi->collecting_data || !mdi->parent || !mdi->parent->conn) {
608 goto enddrunquery;
609 }
610
611 // We failed to collect this for the database, so we are not going to try again
612 if (mdi->MSSQLDatabaseDataFileSize.current.Data != ULONG_LONG_MAX)
613 mdi->MSSQLDatabaseDataFileSize.current.Data = netdata_MSSQL_fill_long_value(
610 - mdi->parent->conn.dataFileSizeSTMT, NETDATA_QUERY_DATA_FILE_SIZE_MASK, dbname, mdi->parent->instanceID);
614 + mdi->parent->conn->dataFileSizeSTMT, NETDATA_QUERY_DATA_FILE_SIZE_MASK, dbname, mdi->parent->instanceID);
615 else {
616 mdi->collecting_data = false;
617 goto enddrunquery;
@@ -633,30 +637,30 @@ long metdata_mssql_check_permission(struct mssql_instance *mi)
637
638 SQLRETURN ret;
639
636 - ret = SQLExecDirect(mi->conn.checkPermSTMT, (SQLCHAR *)NETDATA_QUERY_CHECK_PERM, SQL_NTS);
640 + ret = SQLExecDirect(mi->conn->checkPermSTMT, (SQLCHAR *)NETDATA_QUERY_CHECK_PERM, SQL_NTS);
641 if (ret != SQL_SUCCESS) {
638 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.checkPermSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
642 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->checkPermSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
643 perm = LONG_MAX;
644 goto endperm;
645 }
646
643 - ret = SQLBindCol(mi->conn.checkPermSTMT, 1, SQL_C_LONG, &perm, sizeof(perm), &col_data_len);
647 + ret = SQLBindCol(mi->conn->checkPermSTMT, 1, SQL_C_LONG, &perm, sizeof(perm), &col_data_len);
648
649 if (ret != SQL_SUCCESS) {
646 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.checkPermSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
650 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->checkPermSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
651 perm = LONG_MAX;
652 goto endperm;
653 }
654
651 - ret = SQLFetch(mi->conn.checkPermSTMT);
655 + ret = SQLFetch(mi->conn->checkPermSTMT);
656 if (ret != SQL_SUCCESS) {
653 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.checkPermSTMT, NETDATA_MSSQL_ODBC_FETCH, mi->instanceID);
657 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->checkPermSTMT, NETDATA_MSSQL_ODBC_FETCH, mi->instanceID);
658 perm = LONG_MAX;
659 goto endperm;
660 }
661
662 endperm:
659 - netdata_MSSQL_release_results(mi->conn.checkPermSTMT);
663 + netdata_MSSQL_release_results(mi->conn->checkPermSTMT);
664 return perm;
665 }
666
@@ -674,21 +678,21 @@ void metdata_mssql_fill_dictionary_from_db(struct mssql_instance *mi)
678
679 SQLRETURN ret;
680
677 - ret = SQLExecDirect(mi->conn.databaseListSTMT, (SQLCHAR *)NETDATA_QUERY_LIST_DB, SQL_NTS);
681 + ret = SQLExecDirect(mi->conn->databaseListSTMT, (SQLCHAR *)NETDATA_QUERY_LIST_DB, SQL_NTS);
682 if (ret != SQL_SUCCESS) {
679 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.databaseListSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
683 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->databaseListSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
684 goto enddblist;
685 }
686
683 - ret = SQLBindCol(mi->conn.databaseListSTMT, 1, SQL_C_CHAR, dbname, sizeof(dbname), &col_data_len);
687 + ret = SQLBindCol(mi->conn->databaseListSTMT, 1, SQL_C_CHAR, dbname, sizeof(dbname), &col_data_len);
688
689 if (ret != SQL_SUCCESS) {
686 - netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.databaseListSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
690 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->databaseListSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
691 goto enddblist;
692 }
693
694 do {
691 - ret = SQLFetch(mi->conn.databaseListSTMT);
695 + ret = SQLFetch(mi->conn->databaseListSTMT);
696 if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
697 goto enddblist;
698 }
@@ -704,7 +708,7 @@ void metdata_mssql_fill_dictionary_from_db(struct mssql_instance *mi)
708 } while (true);
709
710 enddblist:
707 - netdata_MSSQL_release_results(mi->conn.databaseListSTMT);
711 + netdata_MSSQL_release_results(mi->conn->databaseListSTMT);
712 }
713
714 static bool netdata_MSSQL_initialize_conection(struct netdata_mssql_conn *nmc)
@@ -794,8 +798,10 @@ static void initialize_mssql_objects(struct mssql_instance *mi, const char *inst
798 strncpyz(prefix, "SQLServer:", sizeof(prefix) - 1);
799 } else if (!strcmp(instance, "SQLEXPRESS")) {
800 strncpyz(prefix, "MSSQL$SQLEXPRESS:", sizeof(prefix) - 1);
801 + if (mi->conn)
802 + mi->conn->is_sqlexpress = true;
803 } else {
798 - char *express = (!is_sqlexpress) ? "" : "SQLEXPRESS:";
804 + char *express = (mi->conn && mi->conn->is_sqlexpress) ? "SQLEXPRESS:": "";
805 snprintfz(prefix, sizeof(prefix) - 1, "MSSQL$%s%s:", express, instance);
806 }
807
@@ -940,45 +946,61 @@ void netdata_mount_mssql_connection_string(struct netdata_mssql_conn *dbInput)
946 dbInput->connectionString = (SQLCHAR *)strdupz((char *)conn);
947 }
948
943 -static void netdata_read_config_options(struct netdata_mssql_conn *dbconn)
949 +static void netdata_read_config_options()
950 {
945 - dbconn->netdataSQLEnv = NULL;
946 - dbconn->netdataSQLHDBc = NULL;
947 - dbconn->checkPermSTMT = NULL;
948 - dbconn->databaseListSTMT = NULL;
949 - dbconn->dataFileSizeSTMT = NULL;
950 - dbconn->dbTransactionSTMT = NULL;
951 - dbconn->dbWaitsSTMT = NULL;
952 - dbconn->dbLocksSTMT = NULL;
953 -
954 - dbconn->is_connected = FALSE;
955 -
956 - static uint16_t expected_instances = 1;
957 - static uint16_t total_instances = 0;
958 - if (total_instances > expected_instances)
959 - return;
960 -
951 #define NETDATA_MAX_MSSSQL_SECTION_LENGTH (40)
952 #define NETDATA_DEFAULT_MSSQL_SECTION "plugin:windows:PerflibMSSQL"
963 - char section_name[NETDATA_MAX_MSSSQL_SECTION_LENGTH + 1];
964 - strncpyz(section_name, NETDATA_DEFAULT_MSSQL_SECTION, sizeof(NETDATA_DEFAULT_MSSQL_SECTION));
965 - if (total_instances) {
966 - snprintfz(&section_name[sizeof(NETDATA_DEFAULT_MSSQL_SECTION) - 1], 5, "%d", total_instances);
967 - }
953 + uint16_t expected_instances = 1;
954 + uint16_t total_instances = 0;
955 + for (; total_instances < expected_instances; total_instances++) {
956 + char section_name[NETDATA_MAX_MSSSQL_SECTION_LENGTH + 1];
957 + char upper_instance[NETDATA_MAX_INSTANCE_OBJECT + 1];
958 + strncpyz(section_name, NETDATA_DEFAULT_MSSQL_SECTION, sizeof(NETDATA_DEFAULT_MSSQL_SECTION));
959 + if (total_instances) {
960 + snprintfz(&section_name[sizeof(NETDATA_DEFAULT_MSSQL_SECTION) - 1], 5, "%d", total_instances);
961 + }
962 + const char *instance = inicfg_get(&netdata_config, section_name, "instance", NULL);
963 + int additional_instances = (int)inicfg_get_number(&netdata_config, section_name, "additional instances", 0);
964 + if (!instance || strlen(instance) > NETDATA_MAX_INSTANCE_OBJECT) {
965 + nd_log(NDLS_COLLECTORS, NDLP_ERR, "You must specify a valid 'instance' name to collect data from database in section %s.", section_name);
966 + continue;
967 + }
968 +
969 + if (!total_instances && additional_instances) {
970 + if (additional_instances > 64) {
971 + nd_log(NDLS_COLLECTORS, NDLP_ERR, "Number of instances is bigger than expected (64)");
972 + expected_instances = 64;
973 + }
974 + expected_instances = additional_instances + 1;
975 + }
976
969 - dbconn->driver = inicfg_get(&netdata_config, section_name, "driver", "SQL Server");
970 - dbconn->server = inicfg_get(&netdata_config, section_name, "server", NULL);
971 - dbconn->address = inicfg_get(&netdata_config, section_name, "address", NULL);
972 - dbconn->username = inicfg_get(&netdata_config, section_name, "uid", NULL);
973 - dbconn->password = inicfg_get(&netdata_config, section_name, "pwd", NULL);
974 - dbconn->instances = (int)inicfg_get_number(&netdata_config, section_name, "additional instances", 0);
975 - dbconn->windows_auth = inicfg_get_boolean(&netdata_config, section_name, "windows authentication", false);
977 + const char *move = instance;
978 + int i;
979 + for (i = 0; *move; move++, i++) {
980 + upper_instance[i] = toupper(*move);
981 + }
982 + upper_instance[i] = '\0';
983 +
984 + struct netdata_mssql_conn *dbconn = dictionary_set(conn_options, upper_instance, NULL, sizeof(*dbconn));
985 +
986 + dbconn->instance = strdupz(upper_instance);
987 + dbconn->driver = inicfg_get(&netdata_config, section_name, "driver", "SQL Server");
988 + dbconn->server = inicfg_get(&netdata_config, section_name, "server", NULL);
989 + dbconn->address = inicfg_get(&netdata_config, section_name, "address", NULL);
990 + dbconn->username = inicfg_get(&netdata_config, section_name, "uid", NULL);
991 + dbconn->password = inicfg_get(&netdata_config, section_name, "pwd", NULL);
992 + dbconn->instances = additional_instances;
993 + dbconn->windows_auth = inicfg_get_boolean(&netdata_config, section_name, "windows authentication", false);
994 + dbconn->is_sqlexpress = inicfg_get_boolean(&netdata_config, section_name, "express", false);
995 + dbconn->is_connected = FALSE;
996
977 - netdata_mount_mssql_connection_string(dbconn);
978 - if (!total_instances)
979 - expected_instances = dbconn->instances;
997 + netdata_mount_mssql_connection_string(dbconn);
998 + }
999 +}
1000
981 - total_instances++;
1001 +static inline struct netdata_mssql_conn *netdata_mssql_get_conn_option(const char *instance)
1002 +{
1003 + return (struct netdata_mssql_conn *)dictionary_get(conn_options, instance);
1004 }
1005
1006 void mssql_fill_initial_instances(struct mssql_instance *mi)
@@ -1032,22 +1054,27 @@ void dict_mssql_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *valu
1054
1055 initialize_mssql_objects(mi, instance);
1056 initialize_mssql_keys(mi);
1035 - netdata_read_config_options(&mi->conn);
1057 + mi->conn = netdata_mssql_get_conn_option(instance);
1058
1037 - if (mi->conn.connectionString) {
1038 - mi->conn.is_connected = netdata_MSSQL_initialize_conection(&mi->conn);
1039 - if (mi->conn.is_connected)
1059 + if (mi->conn && mi->conn->connectionString) {
1060 + mi->conn->is_connected = netdata_MSSQL_initialize_conection(mi->conn);
1061 + if (mi->conn->is_connected)
1062 *create_thread = true;
1063 }
1064 }
1065
1044 -static int mssql_fill_dictionary(int update_every)
1066 +void dict_mssql_insert_conn_option(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1067 +{
1068 + ;
1069 +}
1070 +
1071 +static void mssql_fill_dictionary(int update_every)
1072 {
1073 HKEY hKey;
1074 LSTATUS ret = RegOpenKeyExA(
1075 HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Microsoft SQL Server\\Instance Names\\SQL", 0, KEY_READ, &hKey);
1076 if (ret != ERROR_SUCCESS)
1050 - return -1;
1077 + return;
1078
1079 DWORD values = 0;
1080
@@ -1074,18 +1101,12 @@ static int mssql_fill_dictionary(int update_every)
1101 if (ret != ERROR_SUCCESS)
1102 continue;
1103
1077 - if (!strcmp(avalue, "SQLEXPRESS")) {
1078 - is_sqlexpress = TRUE;
1079 - }
1080 -
1104 struct mssql_instance *p = dictionary_set(mssql_instances, avalue, NULL, sizeof(*p));
1105 p->update_every = update_every;
1106 }
1107
1108 endMSSQLFillDict:
1109 RegCloseKey(hKey);
1087 -
1088 - return (ret == ERROR_SUCCESS) ? 0 : -1;
1110 }
1111
1112 int netdata_mssql_reset_value(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
@@ -1102,14 +1123,14 @@ int dict_mssql_query_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value,
1123 struct mssql_instance *mi = value;
1124 static long collecting = 1;
1125
1105 - if (mi->conn.is_connected && collecting) {
1126 + if (mi->conn && mi->conn->is_connected && collecting) {
1127 collecting = metdata_mssql_check_permission(mi);
1128 if (!collecting) {
1129 nd_log(
1130 NDLS_COLLECTORS,
1131 NDLP_ERR,
1132 "User %s does not have permission to run queries on %s",
1112 - mi->conn.username,
1133 + mi->conn->username,
1134 mi->instanceID);
1135 } else {
1136 metdata_mssql_fill_dictionary_from_db(mi);
@@ -1150,9 +1171,12 @@ static int initialize(int update_every)
1171
1172 dictionary_register_insert_callback(mssql_instances, dict_mssql_insert_cb, &create_thread);
1173
1153 - if (mssql_fill_dictionary(update_every)) {
1154 - return -1;
1155 - }
1174 + conn_options = dictionary_create_advanced(
1175 + DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct netdata_mssql_conn));
1176 + dictionary_register_insert_callback(conn_options, dict_mssql_insert_conn_option, NULL);
1177 +
1178 + netdata_read_config_options();
1179 + mssql_fill_dictionary(update_every);
1180
1181 if (create_thread)
1182 mssql_queries_thread = nd_thread_create("mssql_queries", NETDATA_THREAD_OPTION_DEFAULT, netdata_mssql_queries, &update_every);
@@ -1675,6 +1699,9 @@ int dict_mssql_locks_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void
1699
1700 static void do_mssql_locks(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every __maybe_unused)
1701 {
1702 + if (!pDataBlock)
1703 + goto end_mssql_locks;
1704 +
1705 PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_LOCKS]);
1706 if (pObjectType) {
1707 if (pObjectType->NumInstances) {
@@ -1701,6 +1728,7 @@ static void do_mssql_locks(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *m
1728 }
1729 }
1730
1731 +end_mssql_locks:
1732 dictionary_sorted_walkthrough_read(mi->locks_instances, dict_mssql_locks_charts_cb, mi);
1733 }
1734
@@ -1900,9 +1928,6 @@ static void do_mssql_waits(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *m
1928
1929 static void mssql_database_backup_restore_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
1930 {
1903 - if (unlikely(!mdi->parent->conn.is_connected))
1904 - return;
1905 -
1931 char id[RRD_ID_LENGTH_MAX + 1];
1932
1933 if (!mdi->st_db_backup_restore_operations) {
@@ -1943,9 +1968,6 @@ static void mssql_database_backup_restore_chart(struct mssql_db_instance *mdi, c
1968
1969 static void mssql_database_log_flushes_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
1970 {
1946 - if (unlikely(!mdi->parent->conn.is_connected))
1947 - return;
1948 -
1971 char id[RRD_ID_LENGTH_MAX + 1];
1972
1973 if (!mdi->st_db_log_flushes) {
@@ -1981,9 +2003,6 @@ static void mssql_database_log_flushes_chart(struct mssql_db_instance *mdi, cons
2003
2004 static void mssql_database_log_flushed_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2005 {
1984 - if (unlikely(!mdi->parent->conn.is_connected))
1985 - return;
1986 -
2006 char id[RRD_ID_LENGTH_MAX + 1];
2007
2008 if (!mdi->st_db_log_flushed) {
@@ -2017,9 +2036,6 @@ static void mssql_database_log_flushed_chart(struct mssql_db_instance *mdi, cons
2036
2037 static void mssql_transactions_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2038 {
2020 - if (unlikely(!mdi->parent->conn.is_connected))
2021 - return;
2022 -
2039 char id[RRD_ID_LENGTH_MAX + 1];
2040
2041 if (!mdi->st_db_transactions) {
@@ -2056,9 +2072,6 @@ static void mssql_transactions_chart(struct mssql_db_instance *mdi, const char *
2072
2073 static void mssql_write_transactions_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2074 {
2059 - if (unlikely(!mdi->parent->conn.is_connected))
2060 - return;
2061 -
2075 char id[RRD_ID_LENGTH_MAX + 1];
2076
2077 if (!mdi->st_db_write_transactions) {
@@ -2096,9 +2109,6 @@ static void mssql_write_transactions_chart(struct mssql_db_instance *mdi, const
2109
2110 static void mssql_lockwait_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2111 {
2099 - if (unlikely(!mdi->parent->conn.is_connected))
2100 - return;
2101 -
2112 char id[RRD_ID_LENGTH_MAX + 1];
2113
2114 if (!mdi->st_db_lockwait) {
@@ -2132,9 +2142,6 @@ static void mssql_lockwait_chart(struct mssql_db_instance *mdi, const char *db,
2142
2143 static void mssql_deadlock_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2144 {
2135 - if (unlikely(!mdi->parent->conn.is_connected))
2136 - return;
2137 -
2145 char id[RRD_ID_LENGTH_MAX + 1];
2146
2147 if (!mdi->st_db_deadlock) {
@@ -2168,9 +2175,6 @@ static void mssql_deadlock_chart(struct mssql_db_instance *mdi, const char *db,
2175
2176 static void mssql_lock_request_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2177 {
2171 - if (unlikely(!mdi->parent->conn.is_connected))
2172 - return;
2173 -
2178 char id[RRD_ID_LENGTH_MAX + 1];
2179
2180 if (!mdi->st_lock_requests) {
@@ -2204,9 +2208,6 @@ static void mssql_lock_request_chart(struct mssql_db_instance *mdi, const char *
2208
2209 static void mssql_lock_timeout_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2210 {
2207 - if (unlikely(!mdi->parent->conn.is_connected))
2208 - return;
2209 -
2211 char id[RRD_ID_LENGTH_MAX + 1];
2212
2213 if (!mdi->st_lock_timeouts) {
@@ -2240,9 +2241,6 @@ static void mssql_lock_timeout_chart(struct mssql_db_instance *mdi, const char *
2241
2242 static void mssql_active_transactions_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2243 {
2243 - if (unlikely(!mdi->parent->conn.is_connected))
2244 - return;
2245 -
2244 char id[RRD_ID_LENGTH_MAX + 1];
2245
2246 if (!mdi->st_db_active_transactions) {
@@ -2280,9 +2278,6 @@ static void mssql_active_transactions_chart(struct mssql_db_instance *mdi, const
2278
2279 static inline void mssql_data_file_size_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2280 {
2283 - if (unlikely(!mdi->parent->conn.is_connected))
2284 - return;
2285 -
2281 char id[RRD_ID_LENGTH_MAX + 1];
2282
2283 if (unlikely(!mdi->st_db_data_file_size)) {
@@ -2353,6 +2348,9 @@ endchartcb:
2348
2349 static void do_mssql_databases(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
2350 {
2351 + if (!pDataBlock)
2352 + goto end_mssql_databases;
2353 +
2354 PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_DATABASE]);
2355 if (!pObjectType)
2356 return;
@@ -2378,6 +2376,7 @@ static void do_mssql_databases(PERF_DATA_BLOCK *pDataBlock, struct mssql_instanc
2376 }
2377 }
2378
2379 +end_mssql_databases:
2380 dictionary_sorted_walkthrough_read(mi->databases, dict_mssql_databases_charts_cb, &update_every);
2381 }
2382
@@ -2513,6 +2512,24 @@ static void do_mssql_memory_mgr(PERF_DATA_BLOCK *pDataBlock, struct mssql_instan
2512 }
2513 }
2514
2515 +static inline PERF_DATA_BLOCK *
2516 +netdata_mssql_get_perf_data_block(bool *collect_perflib, struct mssql_instance *mi, DWORD idx)
2517 +{
2518 + DWORD id = RegistryFindIDByName(mi->objectName[idx]);
2519 + if (id == PERFLIB_REGISTRY_NAME_NOT_FOUND) {
2520 + collect_perflib[idx] = false;
2521 + return NULL;
2522 + }
2523 +
2524 + PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
2525 + if (!pDataBlock) {
2526 + collect_perflib[idx] = true;
2527 + return NULL;
2528 + }
2529 +
2530 + return pDataBlock;
2531 +}
2532 +
2533 int dict_mssql_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2534 {
2535 struct mssql_instance *mi = value;
@@ -2521,26 +2538,36 @@ int dict_mssql_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value
2538 static void (*doMSSQL[])(PERF_DATA_BLOCK *, struct mssql_instance *, int) = {
2539 do_mssql_general_stats,
2540 do_mssql_errors,
2524 - do_mssql_databases,
2525 - do_mssql_locks,
2526 - do_mssql_waits,
2541 do_mssql_memory_mgr,
2542 do_mssql_buffer_management,
2543 do_mssql_sql_statistics,
2530 - do_mssql_access_methods};
2544 + do_mssql_access_methods,
2545 +
2546 + do_mssql_databases,
2547 + do_mssql_locks,
2548 + do_mssql_waits,
2549 +
2550 + NULL};
2551
2552 DWORD i;
2533 - for (i = 0; i < NETDATA_MSSQL_METRICS_END; i++) {
2534 - if (!doMSSQL[i])
2553 + PERF_DATA_BLOCK *pDataBlock;
2554 + static bool collect_perflib[NETDATA_MSSQL_METRICS_END] = {true, true, true, true, true, true, true, true, true};
2555 + for (i = 0; i < NETDATA_MSSQL_ACCESS_METHODS; i++) {
2556 + if (!collect_perflib[i])
2557 continue;
2558
2537 - DWORD id = RegistryFindIDByName(mi->objectName[i]);
2538 - if (id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
2539 - return -1;
2540 -
2541 - PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
2559 + pDataBlock = netdata_mssql_get_perf_data_block(collect_perflib, mi, i);
2560 if (!pDataBlock)
2543 - return -1;
2561 + continue;
2562 +
2563 + doMSSQL[i](pDataBlock, mi, *update_every);
2564 + }
2565 +
2566 + if (unlikely(!mi->conn || !mi->conn->is_connected))
2567 + return 1;
2568 +
2569 + for (i = NETDATA_MSSQL_DATABASE; doMSSQL[i]; i++) {
2570 + pDataBlock = (collect_perflib[i]) ? netdata_mssql_get_perf_data_block(collect_perflib, mi, i): NULL;
2571
2572 doMSSQL[i](pDataBlock, mi, *update_every);
2573 }