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(§ion_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(§ion_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
}