@cryptotaxi247 / netdata-1 / commits / d137eb956

User Connections (MSSQL) (#21348)

thiagoftsm committed Nov 25, 2025 at 18:19 UTC d137eb9562e00eb3057efc15e28833cd04e9e949
4 files changed +83 -16
src/collectors/windows.plugin/MonitorSQL.c
+64 -9
@@ -739,7 +739,7 @@ enddrunquery:
739 return 1;
740 }
741
742 -long metdata_mssql_check_permission(struct mssql_instance *mi)
742 +long netdata_mssql_check_permission(struct mssql_instance *mi)
743 {
744 static int next_try = NETDATA_MSSQL_NEXT_TRY - 1;
745 long perm = 0;
@@ -779,7 +779,7 @@ endperm:
779 return perm;
780 }
781
782 -void metdata_mssql_fill_mssql_status(struct mssql_instance *mi)
782 +void netdata_mssql_fill_mssql_status(struct mssql_instance *mi)
783 {
784 char dbname[SQLSERVER_MAX_NAME_LENGTH + 1];
785 int readonly = 0;
@@ -831,7 +831,7 @@ enddbstate:
831 netdata_MSSQL_release_results(mi->conn->dbSQLState);
832 }
833
834 -void metdata_mssql_fill_job_status(struct mssql_instance *mi)
834 +void netdata_mssql_fill_job_status(struct mssql_instance *mi)
835 {
836 char job[SQLSERVER_MAX_NAME_LENGTH + 1];
837 BYTE state = 0;
@@ -882,7 +882,42 @@ enddbjobs:
882 netdata_MSSQL_release_results(mi->conn->dbSQLJobs);
883 }
884
885 -void metdata_mssql_fill_dictionary_from_db(struct mssql_instance *mi)
885 +void netdata_mssql_fill_user_connection(struct mssql_instance *mi)
886 +{
887 + if (unlikely(!mi->conn->collect_user_connections))
888 + return;
889 +
890 + collected_number connections = 0;
891 + SQLLEN col_user_connections_len = 0;
892 +
893 + SQLRETURN ret;
894 +
895 + ret = SQLExecDirect(mi->conn->dbSQLUserConnections, (SQLCHAR *)NETDATA_QUERY_USER_CONNECTIONS, SQL_NTS);
896 + if (likely(netdata_mssql_check_result(ret))) {
897 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLUserConnections, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
898 + goto enduserconn;
899 + }
900 +
901 + ret = SQLBindCol(mi->conn->dbSQLUserConnections, 1, SQL_C_LONG, &connections, sizeof(connections), &col_user_connections_len);
902 + if (likely(netdata_mssql_check_result(ret))) {
903 + netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn->dbSQLUserConnections, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
904 + goto enduserconn;
905 + }
906 +
907 + do {
908 + ret = SQLFetch(mi->conn->dbSQLUserConnections);
909 + if (likely(netdata_mssql_check_result(ret))) {
910 + goto enduserconn;
911 + }
912 +
913 + mi->MSSQLUserConnections.current.Data = (ULONGLONG)connections;
914 + } while (true);
915 +
916 +enduserconn:
917 + netdata_MSSQL_release_results(mi->conn->dbSQLUserConnections);
918 +}
919 +
920 +void netdata_mssql_fill_dictionary_from_db(struct mssql_instance *mi)
921 {
922 char dbname[SQLSERVER_MAX_NAME_LENGTH + 1];
923 SQLLEN col_data_len = 0;
@@ -1043,6 +1078,12 @@ static bool netdata_MSSQL_initialize_connection(struct netdata_mssql_conn *nmc)
1078 goto endMSSQLInitializationConnection;
1079 }
1080
1081 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbSQLUserConnections);
1082 + if (likely(netdata_mssql_check_result(ret))) {
1083 + retConn = FALSE;
1084 + goto endMSSQLInitializationConnection;
1085 + }
1086 +
1087 ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbReplicationPublisher);
1088 if (likely(netdata_mssql_check_result(ret))) {
1089 retConn = FALSE;
@@ -1091,6 +1132,8 @@ static void initialize_mssql_objects(struct mssql_instance *mi, const char *inst
1132 strncpyz(&name[length], "SystemJobs", sizeof(name) - length);
1133 mi->objectName[NETDATA_MSSQL_JOBS] = strdupz(name);
1134
1135 + mi->objectName[NETDATA_USER_CONNECTIONS] = NULL;
1136 +
1137 strncpyz(&name[length], "Memory Manager", sizeof(name) - length);
1138 mi->objectName[NETDATA_MSSQL_MEMORY] = strdupz(name);
1139
@@ -1280,6 +1323,8 @@ static void netdata_read_config_options()
1323 &netdata_config, section_name, "collect buffer stats", true);
1324 dbconn->collect_data_size = inicfg_get_boolean(
1325 &netdata_config, section_name, "collect database size", true);
1326 + dbconn->collect_user_connections = inicfg_get_boolean(
1327 + &netdata_config, section_name, "collect user connections", true);
1328 dbconn->is_connected = FALSE;
1329
1330 netdata_mount_mssql_connection_string(dbconn);
@@ -1426,7 +1471,7 @@ int dict_mssql_query_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value,
1471 static long collecting = 1;
1472
1473 if (likely(mi->conn && mi->conn->is_connected && collecting)) {
1429 - collecting = metdata_mssql_check_permission(mi);
1474 + collecting = netdata_mssql_check_permission(mi);
1475 if (!collecting) {
1476 nd_log(
1477 NDLS_COLLECTORS,
@@ -1435,9 +1480,10 @@ int dict_mssql_query_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value,
1480 mi->conn->username,
1481 mi->instanceID);
1482 } else {
1438 - metdata_mssql_fill_dictionary_from_db(mi);
1439 - metdata_mssql_fill_mssql_status(mi);
1440 - metdata_mssql_fill_job_status(mi);
1483 + netdata_mssql_fill_dictionary_from_db(mi);
1484 + netdata_mssql_fill_mssql_status(mi);
1485 + netdata_mssql_fill_job_status(mi);
1486 + netdata_mssql_fill_user_connection(mi);
1487 dictionary_sorted_walkthrough_read(mi->databases, dict_mssql_databases_run_queries, NULL);
1488 }
1489
@@ -2135,6 +2181,14 @@ static void do_mssql_job_status_sql(PERF_DATA_BLOCK *pDataBlock, struct mssql_in
2181 dictionary_sorted_walkthrough_read(mi->sysjobs, dict_mssql_sysjobs_chart_cb, mi);
2182 }
2183
2184 +static void do_mssql_user_connection(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
2185 +{
2186 + if (unlikely(!mi->conn->collect_user_connections))
2187 + return;
2188 +
2189 + do_mssql_user_connections(mi, update_every);
2190 +}
2191 +
2192 void dict_mssql_replication_status(struct mssql_publisher_publication *mpp, int update_every)
2193 {
2194 if (unlikely(!mpp->st_publisher_status)) {
@@ -3004,13 +3058,14 @@ int dict_mssql_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value
3058 do_mssql_waits,
3059 do_mssql_bufferman_stats_sql,
3060 do_mssql_job_status_sql,
3061 + do_mssql_user_connection,
3062
3063 NULL};
3064
3065 DWORD i;
3066 PERF_DATA_BLOCK *pDataBlock;
3067 static bool collect_perflib[NETDATA_MSSQL_METRICS_END] = {
3013 - true, true, true, true, true, true, true, true, true, true};
3068 + true, true, true, true, true, true, true, true, true, true, false};
3069 for (i = 0; i < NETDATA_MSSQL_ACCESS_METHODS; i++) {
3070 if (unlikely(!collect_perflib[i]))
3071 continue;
src/collectors/windows.plugin/metadata.yaml
+4
@@ -2281,6 +2281,10 @@ modules:
2281 description: Run queries to collect information from the server's database size.
2282 default_value: yes
2283 required: false
2284 + - name: collect user connections
2285 + description: Run queries to collect information from the server's connection.
2286 + default_value: yes
2287 + required: false
2288 examples:
2289 folding:
2290 enabled: true
src/collectors/windows.plugin/perflib-mssql-queries.h
+11 -5
@@ -37,6 +37,8 @@
37
38 #define NETDATA_QUERY_JOBS_STATUS "SELECT name, enabled FROM msdb.dbo.sysjobs;"
39
40 +#define NETDATA_QUERY_USER_CONNECTIONS "SELECT COUNT(*) AS user_connections FROM sys.dm_exec_sessions WHERE is_user_process = 1;"
41 +
42 // https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql?view=sql-server-ver16
43 #define NETDATA_QUERY_CHECK_WAITS \
44 "SELECT \
@@ -670,6 +672,7 @@ struct netdata_mssql_conn {
672 SQLHSTMT dbLocksSTMT;
673 SQLHSTMT dbSQLState;
674 SQLHSTMT dbSQLJobs;
675 + SQLHSTMT dbSQLUserConnections;
676 SQLHSTMT dbReplicationPublisher;
677
678 BOOL collect_transactions;
@@ -679,6 +682,7 @@ struct netdata_mssql_conn {
682 BOOL collect_jobs;
683 BOOL collect_buffer;
684 BOOL collect_data_size;
685 + BOOL collect_user_connections;
686
687 BOOL is_connected;
688 };
@@ -695,6 +699,7 @@ enum netdata_mssql_metrics {
699 NETDATA_MSSQL_WAITS,
700 NETDATA_MSSQL_BUFFER_MANAGEMENT,
701 NETDATA_MSSQL_JOBS,
702 + NETDATA_USER_CONNECTIONS,
703
704 NETDATA_MSSQL_METRICS_END
705 };
@@ -982,9 +987,10 @@ netdata_mssql_get_perf_data_block(bool *collect_perflib, struct mssql_instance *
987 return pDataBlock;
988 }
989
985 -void do_mssql_general_stats(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
986 -void do_mssql_errors(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
987 -void do_mssql_memory_mgr(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
988 -void do_mssql_statistics_perflib(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
989 -void do_mssql_access_methods(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
990 +extern void do_mssql_general_stats(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
991 +extern void do_mssql_errors(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
992 +extern void do_mssql_memory_mgr(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
993 +extern void do_mssql_statistics_perflib(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
994 +extern void do_mssql_access_methods(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every);
995 +extern void do_mssql_user_connections(struct mssql_instance *mi, int update_every);
996 #endif
src/collectors/windows.plugin/perflib-mssql.c
+4 -2
@@ -420,8 +420,10 @@ void do_mssql_general_stats(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *
420 if (unlikely(!pObjectType))
421 return;
422
423 - if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLUserConnections))) {
424 - do_mssql_user_connections(mi, update_every);
423 + if (unlikely(!mi->conn) || unlikely(!mi->conn->collect_user_connections)) {
424 + if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLUserConnections))) {
425 + do_mssql_user_connections(mi, update_every);
426 + }
427 }
428
429 if (likely(perflibGetObjectCounter(pDataBlock, pObjectType, &mi->MSSQLBlockedProcesses))) {