@cryptotaxi247 / netdata-1 / commits / f204e245c

MSSQL Replication - Publisher (Windows.plugin) (#21235)

thiagoftsm committed Nov 10, 2025 at 12:28 UTC f204e245c6ef1516aa6f90821734283d2caa4228
4 files changed +717 -3
src/collectors/windows.plugin/metadata.yaml
+72 -2
@@ -2129,7 +2129,18 @@ modules:
2129 GO
2130 ```
2131
2132 - 4. **Configure SQL Server Network Settings**
2132 + 4. **Enable Query replication stored procedure**
2133 +
2134 + Connect to your database and add `netdata_user` to `replmonitor`:
2135 +
2136 + ```tsql
2137 + USE distribution;
2138 + GO
2139 + EXEC sp_addrolemember 'replmonitor', 'netdata_user';
2140 + GO
2141 + ```
2142 +
2143 + 5. **Configure SQL Server Network Settings**
2144
2145 Enable SQL Server to accept TCP connections:
2146
@@ -2142,7 +2153,7 @@ modules:
2153 - Enter a port number in the `TCP Port` field (default is `1433`)
2154 - Select `SQL Server Services` and restart your SQL Server instance
2155
2145 - 5. **Configure SQL Server Authentication (Optional)**
2156 + 6. **Configure SQL Server Authentication (Optional)**
2157
2158 If you're using SQL Server authentication (rather than Windows authentication):
2159
@@ -2539,6 +2550,65 @@ modules:
2550 chart_type: line
2551 dimensions:
2552 - name: size
2553 + - name: MSSQL Replication
2554 + description: "These metrics refer to the Microsoft SQL Servers replication on host."
2555 + labels:
2556 + - name: mssql_instance
2557 + description: The instance name.
2558 + - name: publisher
2559 + description: The SQL server publisher name.
2560 + - name: database
2561 + description: The database being replicated.
2562 + - name: publication
2563 + description: The publication name.
2564 + metrics:
2565 + - name: mssql.replication_status
2566 + description: Current replication status
2567 + unit: status
2568 + chart_type: line
2569 + dimensions:
2570 + - name: started
2571 + - name: succeeded
2572 + - name: in_progress
2573 + - name: idle
2574 + - name: retrying
2575 + - name: failed
2576 + - name: mssql.replication_warning
2577 + description: Maximum threshold warning.
2578 + unit: status
2579 + chart_type: line
2580 + dimensions:
2581 + - name: expiration
2582 + - name: latency
2583 + - name: merge expiration
2584 + - name: fast duration
2585 + - name: low duration
2586 + - name: fast run speed
2587 + - name: low run speed
2588 + - name: mssql.replication_avg_latency
2589 + description: Average latency for a transactional publication.
2590 + unit: seconds
2591 + chart_type: line
2592 + dimensions:
2593 + - name: latency
2594 + - name: mssql.replication_subscription
2595 + description: Number of subscriptions to a publication.
2596 + unit: subscription
2597 + chart_type: line
2598 + dimensions:
2599 + - name: subscription
2600 + - name: mssql.replication_agent_running
2601 + description: Distribution agents running.
2602 + unit: agents
2603 + chart_type: line
2604 + dimensions:
2605 + - name: agents
2606 + - name: mssql.replication_synchronization
2607 + description: The shortest synchronization.
2608 + unit: seconds
2609 + chart_type: line
2610 + dimensions:
2611 + - name: seconds
2612 - meta:
2613 plugin_name: windows.plugin
2614 module_name: PerflibNetFramework
src/collectors/windows.plugin/perflib-mssql-queries.h
+4
@@ -7,6 +7,10 @@
7 #define NETDATA_QUERY_LOCKS_MASK \
8 "SELECT resource_type, count(*) FROM %s.sys.dm_tran_locks WHERE DB_NAME(resource_database_id) = '%s' group by resource_type;"
9
10 +#define NETDATA_REPLICATION_DB "distribution"
11 +
12 +#define NETDATA_REPLICATION_MONITOR_QUERY "EXEC sp_replmonitorhelppublication;"
13 +
14 #define NETDATA_QUERY_LIST_DB "SELECT name FROM sys.databases;"
15
16 // https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-database-files-transact-sql?view=sql-server-ver16
src/collectors/windows.plugin/perflib-mssql.c
+624 -1
@@ -42,6 +42,7 @@ struct netdata_mssql_conn {
42 SQLHSTMT dbLocksSTMT;
43 SQLHSTMT dbSQLState;
44 SQLHSTMT dbSQLJobs;
45 + SQLHSTMT dbReplicationPublisher;
46
47 BOOL is_connected;
48 };
@@ -90,6 +91,62 @@ struct mssql_db_waits {
91 COUNTER_DATA MSSQLDatabaseWaitingTasks;
92 };
93
94 +// https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-replmonitorhelppublication-transact-sql?view=sql-server-ver17
95 +struct mssql_publisher_publication {
96 + struct mssql_instance *parent;
97 +
98 + // Lables
99 + char *publisher;
100 + char *publication;
101 + char *db;
102 + int type;
103 +
104 + // Charts
105 + int status;
106 + int warning;
107 +
108 + int avg_latency;
109 +
110 + int retention;
111 +
112 + int subscriptioncount;
113 + int runningdistagentcount;
114 +
115 + int average_runspeedPerf;
116 +
117 + RRDSET *st_publisher_status;
118 + RRDDIM *rd_publisher_status_started;
119 + RRDDIM *rd_publisher_status_successed;
120 + RRDDIM *rd_publisher_status_in_progress;
121 + RRDDIM *rd_publisher_status_idle;
122 + RRDDIM *rd_publisher_status_retrying;
123 + RRDDIM *rd_publisher_status_failed;
124 +
125 + RRDSET *st_warning;
126 + RRDDIM *rd_warning_expiration;
127 + RRDDIM *rd_warning_latency;
128 + RRDDIM *rd_warning_mergeeexpiration;
129 + RRDDIM *rd_warning_mergefastduration;
130 + RRDDIM *rd_warning_mergelowduration;
131 + RRDDIM *rd_warning_mergefastrunspeed;
132 + RRDDIM *rd_warning_mergelowrunspeed;
133 +
134 + RRDSET *st_avg_latency;
135 + RRDDIM *rd_avg_latency;
136 +
137 + RRDSET *st_retention;
138 + RRDDIM *rd_retention;
139 +
140 + RRDSET *st_subscription_count;
141 + RRDDIM *rd_subscription_count;
142 +
143 + RRDSET *st_running_agent;
144 + RRDDIM *rd_running_agent;
145 +
146 + RRDSET *st_synchronization_time;
147 + RRDDIM *rd_synchronization_time;
148 +};
149 +
150 struct mssql_instance {
151 char *instanceID;
152 int update_every;
@@ -123,6 +180,7 @@ struct mssql_instance {
180
181 DICTIONARY *databases;
182 DICTIONARY *sysjobs;
183 + DICTIONARY *publisher_publication;
184
185 RRDSET *st_conn_memory;
186 RRDDIM *rd_conn_memory;
@@ -181,6 +239,7 @@ struct mssql_db_instance {
239
240 bool collecting_data;
241 bool collect_instance;
242 + bool running_replication;
243
244 RRDSET *st_db_data_file_size;
245 RRDSET *st_db_active_transactions;
@@ -271,7 +330,8 @@ enum netdata_mssql_odbc_errors {
330 NETDATA_MSSQL_ODBC_FETCH
331 };
332
274 -static inline int netdata_mssql_check_result(SQLRETURN ret) {
333 +static inline int netdata_mssql_check_result(SQLRETURN ret)
334 +{
335 return (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO);
336 }
337
@@ -750,6 +810,228 @@ endwait:
810 return success;
811 }
812
813 +int netdata_select_db(SQLHDBC hdbc, const char *database)
814 +{
815 + SQLHSTMT hstmt;
816 + SQLRETURN ret;
817 +
818 + ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
819 + if (netdata_mssql_check_result(ret)) {
820 + return -1;
821 + }
822 +
823 + char query[512];
824 + snprintfz(query, sizeof(query), "USE %s", database);
825 + ret = SQLExecDirect(hstmt, (SQLCHAR *)query, SQL_NTS);
826 + int result = 0;
827 + if (netdata_mssql_check_result(ret)) {
828 + result = -1;
829 + }
830 + SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
831 + return result;
832 +}
833 +
834 +void dict_mssql_fill_replication(struct mssql_db_instance *mdi)
835 +{
836 + char publisher[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
837 + char publisher_db[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
838 + char publication[NETDATA_MAX_INSTANCE_OBJECT + 1] = {};
839 + char key[NETDATA_MAX_INSTANCE_OBJECT * 2 + 2];
840 + int type = 0, status = 0, warning = 0, avg_latency = 0, retention = 0, subscriptioncount = 0,
841 + runningdistagentcount = 0, average_runspeedPerf = 0;
842 + SQLLEN publisher_len = 0, publisherdb_len = 0, publication_len = 0, type_len = 0, status_len = 0, warning_len = 0,
843 + avg_latency_len = 0, retention_len = 0, subscriptioncount_len = 0, runningagentcount_len = 0,
844 + average_runspeedperf_len = 0;
845 +
846 + if (netdata_select_db(mdi->parent->conn->netdataSQLHDBc, NETDATA_REPLICATION_DB)) {
847 + return;
848 + }
849 +
850 + SQLRETURN ret =
851 + SQLExecDirect(mdi->parent->conn->dbReplicationPublisher, (SQLCHAR *)NETDATA_REPLICATION_MONITOR_QUERY, SQL_NTS);
852 + if (netdata_mssql_check_result(ret)) {
853 + mdi->collecting_data = false;
854 + netdata_MSSQL_error(
855 + SQL_HANDLE_STMT,
856 + mdi->parent->conn->dbReplicationPublisher,
857 + NETDATA_MSSQL_ODBC_QUERY,
858 + mdi->parent->instanceID);
859 + goto endreplication;
860 + }
861 +
862 + ret = SQLBindCol(
863 + mdi->parent->conn->dbReplicationPublisher, 1, SQL_C_CHAR, publisher_db, sizeof(publisher_db), &publisherdb_len);
864 + if (netdata_mssql_check_result(ret)) {
865 + netdata_MSSQL_error(
866 + SQL_HANDLE_STMT,
867 + mdi->parent->conn->dbReplicationPublisher,
868 + NETDATA_MSSQL_ODBC_PREPARE,
869 + mdi->parent->instanceID);
870 + goto endreplication;
871 + }
872 +
873 + ret = SQLBindCol(
874 + mdi->parent->conn->dbReplicationPublisher, 2, SQL_C_CHAR, publication, sizeof(publication), &publication_len);
875 + if (netdata_mssql_check_result(ret)) {
876 + netdata_MSSQL_error(
877 + SQL_HANDLE_STMT,
878 + mdi->parent->conn->dbReplicationPublisher,
879 + NETDATA_MSSQL_ODBC_PREPARE,
880 + mdi->parent->instanceID);
881 + goto endreplication;
882 + }
883 +
884 + ret = SQLBindCol(mdi->parent->conn->dbReplicationPublisher, 4, SQL_C_LONG, &type, sizeof(type), &type_len);
885 + if (netdata_mssql_check_result(ret)) {
886 + netdata_MSSQL_error(
887 + SQL_HANDLE_STMT,
888 + mdi->parent->conn->dbReplicationPublisher,
889 + NETDATA_MSSQL_ODBC_PREPARE,
890 + mdi->parent->instanceID);
891 + goto endreplication;
892 + }
893 +
894 + ret = SQLBindCol(mdi->parent->conn->dbReplicationPublisher, 5, SQL_C_LONG, &status, sizeof(status), &status_len);
895 + if (netdata_mssql_check_result(ret)) {
896 + netdata_MSSQL_error(
897 + SQL_HANDLE_STMT,
898 + mdi->parent->conn->dbReplicationPublisher,
899 + NETDATA_MSSQL_ODBC_PREPARE,
900 + mdi->parent->instanceID);
901 + goto endreplication;
902 + }
903 +
904 + ret = SQLBindCol(mdi->parent->conn->dbReplicationPublisher, 6, SQL_C_LONG, &warning, sizeof(warning), &warning_len);
905 + if (netdata_mssql_check_result(ret)) {
906 + netdata_MSSQL_error(
907 + SQL_HANDLE_STMT,
908 + mdi->parent->conn->dbReplicationPublisher,
909 + NETDATA_MSSQL_ODBC_PREPARE,
910 + mdi->parent->instanceID);
911 + goto endreplication;
912 + }
913 +
914 + ret = SQLBindCol(
915 + mdi->parent->conn->dbReplicationPublisher, 9, SQL_C_LONG, &avg_latency, sizeof(avg_latency), &avg_latency_len);
916 + if (netdata_mssql_check_result(ret)) {
917 + // It is still a NULL value
918 + avg_latency = 0;
919 + }
920 +
921 + ret = SQLBindCol(
922 + mdi->parent->conn->dbReplicationPublisher, 11, SQL_C_LONG, &retention, sizeof(retention), &retention_len);
923 + if (netdata_mssql_check_result(ret)) {
924 + netdata_MSSQL_error(
925 + SQL_HANDLE_STMT,
926 + mdi->parent->conn->dbReplicationPublisher,
927 + NETDATA_MSSQL_ODBC_PREPARE,
928 + mdi->parent->instanceID);
929 + goto endreplication;
930 + }
931 +
932 + ret = SQLBindCol(
933 + mdi->parent->conn->dbReplicationPublisher,
934 + 15,
935 + SQL_C_LONG,
936 + &subscriptioncount,
937 + sizeof(subscriptioncount),
938 + &subscriptioncount_len);
939 + if (netdata_mssql_check_result(ret)) {
940 + netdata_MSSQL_error(
941 + SQL_HANDLE_STMT,
942 + mdi->parent->conn->dbReplicationPublisher,
943 + NETDATA_MSSQL_ODBC_PREPARE,
944 + mdi->parent->instanceID);
945 + goto endreplication;
946 + }
947 +
948 + ret = SQLBindCol(
949 + mdi->parent->conn->dbReplicationPublisher,
950 + 16,
951 + SQL_C_LONG,
952 + &runningdistagentcount,
953 + sizeof(runningdistagentcount),
954 + &runningagentcount_len);
955 + if (netdata_mssql_check_result(ret)) {
956 + netdata_MSSQL_error(
957 + SQL_HANDLE_STMT,
958 + mdi->parent->conn->dbReplicationPublisher,
959 + NETDATA_MSSQL_ODBC_PREPARE,
960 + mdi->parent->instanceID);
961 + goto endreplication;
962 + }
963 +
964 + ret = SQLBindCol(
965 + mdi->parent->conn->dbReplicationPublisher,
966 + 22,
967 + SQL_C_LONG,
968 + &average_runspeedPerf,
969 + sizeof(average_runspeedPerf),
970 + &average_runspeedperf_len);
971 + if (netdata_mssql_check_result(ret)) {
972 + netdata_MSSQL_error(
973 + SQL_HANDLE_STMT,
974 + mdi->parent->conn->dbReplicationPublisher,
975 + NETDATA_MSSQL_ODBC_PREPARE,
976 + mdi->parent->instanceID);
977 + goto endreplication;
978 + }
979 +
980 + ret = SQLBindCol(
981 + mdi->parent->conn->dbReplicationPublisher, 24, SQL_C_CHAR, publisher, sizeof(publisher), &publisher_len);
982 + if (netdata_mssql_check_result(ret)) {
983 + netdata_MSSQL_error(
984 + SQL_HANDLE_STMT,
985 + mdi->parent->conn->dbReplicationPublisher,
986 + NETDATA_MSSQL_ODBC_PREPARE,
987 + mdi->parent->instanceID);
988 + goto endreplication;
989 + }
990 +
991 + do {
992 + ret = SQLFetch(mdi->parent->conn->dbReplicationPublisher);
993 + switch (ret) {
994 + case SQL_SUCCESS:
995 + case SQL_SUCCESS_WITH_INFO:
996 + break;
997 + case SQL_NO_DATA:
998 + default:
999 + goto endreplication;
1000 + }
1001 +
1002 + snprintfz(key, sizeof(key) - 1, "%s:%s", publisher_db, publication);
1003 + struct mssql_publisher_publication *mpp =
1004 + dictionary_set(mdi->parent->publisher_publication, key, NULL, sizeof(*mpp));
1005 +
1006 + if (!mpp->publisher) {
1007 + mpp->publisher = strdupz(publisher);
1008 + mpp->parent = mdi->parent;
1009 + }
1010 +
1011 + if (!mpp->publication)
1012 + mpp->publication = strdupz(publication);
1013 +
1014 + if (!mpp->db)
1015 + mpp->db = strdupz(publisher_db);
1016 +
1017 + mpp->type = type;
1018 + mpp->status = status;
1019 + mpp->warning = warning;
1020 +
1021 + mpp->avg_latency = avg_latency;
1022 +
1023 + mpp->retention = retention;
1024 +
1025 + mpp->subscriptioncount = subscriptioncount;
1026 + mpp->runningdistagentcount = runningdistagentcount;
1027 +
1028 + mpp->average_runspeedPerf = average_runspeedPerf;
1029 + } while (true);
1030 +
1031 +endreplication:
1032 + (void)netdata_select_db(mdi->parent->conn->netdataSQLHDBc, "master");
1033 + netdata_MSSQL_release_results(mdi->parent->conn->dbReplicationPublisher);
1034 +}
1035 int dict_mssql_databases_run_queries(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1036 {
1037 struct mssql_db_instance *mdi = value;
@@ -771,6 +1053,9 @@ int dict_mssql_databases_run_queries(const DICTIONARY_ITEM *item __maybe_unused,
1053 dict_mssql_fill_transactions(mdi, dbname);
1054 dict_mssql_fill_locks(mdi, dbname);
1055
1056 + if (mdi->running_replication)
1057 + dict_mssql_fill_replication(mdi);
1058 +
1059 enddrunquery:
1060 return 1;
1061 }
@@ -962,6 +1247,10 @@ void metdata_mssql_fill_dictionary_from_db(struct mssql_instance *mi)
1247 mdi->parent = mi;
1248 }
1249
1250 + if (mi->conn && !strncmp(dbname, NETDATA_REPLICATION_DB, sizeof(NETDATA_REPLICATION_DB) - 1)) {
1251 + mdi->running_replication = true;
1252 + }
1253 +
1254 if (!i) {
1255 mdi->collect_instance = true;
1256 }
@@ -1075,6 +1364,12 @@ static bool netdata_MSSQL_initialize_connection(struct netdata_mssql_conn *nmc)
1364 retConn = FALSE;
1365 goto endMSSQLInitializationConnection;
1366 }
1367 +
1368 + ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbReplicationPublisher);
1369 + if (netdata_mssql_check_result(ret)) {
1370 + retConn = FALSE;
1371 + goto endMSSQLInitializationConnection;
1372 + }
1373 }
1374
1375 endMSSQLInitializationConnection:
@@ -1187,6 +1482,11 @@ void dict_mssql_insert_databases_cb(const DICTIONARY_ITEM *item __maybe_unused,
1482 mdi->collecting_data = true;
1483 }
1484
1485 +void dict_mssql_insert_replication_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1486 +{
1487 + UNUSED(value);
1488 +}
1489 +
1490 void dict_mssql_insert_jobs_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
1491 {
1492 UNUSED(value);
@@ -1342,6 +1642,14 @@ void dict_mssql_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *valu
1642 dictionary_register_insert_callback(mi->databases, dict_mssql_insert_databases_cb, NULL);
1643 }
1644
1645 + if (!mi->publisher_publication) {
1646 + mi->publisher_publication = dictionary_create_advanced(
1647 + DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
1648 + NULL,
1649 + sizeof(struct mssql_publisher_publication));
1650 + dictionary_register_insert_callback(mi->publisher_publication, dict_mssql_insert_replication_cb, NULL);
1651 + }
1652 +
1653 if (!mi->sysjobs) {
1654 mi->sysjobs = dictionary_create_advanced(
1655 DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct mssql_db_jobs));
@@ -2372,6 +2680,319 @@ static void do_mssql_job_status_sql(PERF_DATA_BLOCK *pDataBlock, struct mssql_in
2680 dictionary_sorted_walkthrough_read(mi->sysjobs, dict_mssql_sysjobs_chart_cb, mi);
2681 }
2682
2683 +void dict_mssql_replication_status(struct mssql_publisher_publication *mpp, int update_every)
2684 +{
2685 + if (!mpp->st_publisher_status) {
2686 + char id[RRD_ID_LENGTH_MAX + 1];
2687 +
2688 + snprintfz(
2689 + id,
2690 + RRD_ID_LENGTH_MAX,
2691 + "instance_%s_replication_%s_%s_status",
2692 + mpp->parent->instanceID,
2693 + mpp->publication,
2694 + mpp->db);
2695 + netdata_fix_chart_name(id);
2696 + mpp->st_publisher_status = rrdset_create_localhost(
2697 + "mssql",
2698 + id,
2699 + NULL,
2700 + "replication",
2701 + "mssql.replication_status",
2702 + "Current replication status",
2703 + "status",
2704 + PLUGIN_WINDOWS_NAME,
2705 + "PerflibMSSQL",
2706 + PRIO_MSSQL_REPLICATION_STATUS,
2707 + update_every,
2708 + RRDSET_TYPE_LINE);
2709 +
2710 + rrdlabels_add(
2711 + mpp->st_publisher_status->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2712 + rrdlabels_add(mpp->st_publisher_status->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2713 + rrdlabels_add(mpp->st_publisher_status->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2714 + rrdlabels_add(mpp->st_publisher_status->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2715 +
2716 + mpp->rd_publisher_status_started =
2717 + rrddim_add(mpp->st_publisher_status, "started", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2718 + mpp->rd_publisher_status_successed =
2719 + rrddim_add(mpp->st_publisher_status, "succeeded", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2720 + mpp->rd_publisher_status_in_progress =
2721 + rrddim_add(mpp->st_publisher_status, "in_progress", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2722 + mpp->rd_publisher_status_idle =
2723 + rrddim_add(mpp->st_publisher_status, "idle", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2724 + mpp->rd_publisher_status_retrying =
2725 + rrddim_add(mpp->st_publisher_status, "retrying", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2726 + mpp->rd_publisher_status_failed =
2727 + rrddim_add(mpp->st_publisher_status, "failed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2728 + }
2729 +
2730 + int status = mpp->status;
2731 + rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_started, (collected_number)(status == 1));
2732 + rrddim_set_by_pointer(
2733 + mpp->st_publisher_status, mpp->rd_publisher_status_successed, (collected_number)(status == 2));
2734 + rrddim_set_by_pointer(
2735 + mpp->st_publisher_status, mpp->rd_publisher_status_in_progress, (collected_number)(status == 3));
2736 + rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_idle, (collected_number)(status == 4));
2737 + rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_retrying, (collected_number)(status == 5));
2738 + rrddim_set_by_pointer(mpp->st_publisher_status, mpp->rd_publisher_status_failed, (collected_number)(status == 6));
2739 + rrdset_done(mpp->st_publisher_status);
2740 +}
2741 +
2742 +void dict_mssql_replication_warning(struct mssql_publisher_publication *mpp, int update_every)
2743 +{
2744 + if (!mpp->st_warning) {
2745 + char id[RRD_ID_LENGTH_MAX + 1];
2746 +
2747 + snprintfz(
2748 + id,
2749 + RRD_ID_LENGTH_MAX,
2750 + "instance_%s_replication_%s_%s_warning",
2751 + mpp->parent->instanceID,
2752 + mpp->publication,
2753 + mpp->db);
2754 + netdata_fix_chart_name(id);
2755 + mpp->st_warning = rrdset_create_localhost(
2756 + "mssql",
2757 + id,
2758 + NULL,
2759 + "replication",
2760 + "mssql.replication_warning",
2761 + "Maximum threshold warning.",
2762 + "status",
2763 + PLUGIN_WINDOWS_NAME,
2764 + "PerflibMSSQL",
2765 + PRIO_MSSQL_REPLICATION_WARNING,
2766 + update_every,
2767 + RRDSET_TYPE_LINE);
2768 +
2769 + rrdlabels_add(mpp->st_warning->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2770 + rrdlabels_add(mpp->st_warning->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2771 + rrdlabels_add(mpp->st_warning->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2772 + rrdlabels_add(mpp->st_warning->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2773 +
2774 + mpp->rd_warning_expiration = rrddim_add(mpp->st_warning, "expiration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2775 + mpp->rd_warning_latency = rrddim_add(mpp->st_warning, "latency", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2776 + mpp->rd_warning_mergeeexpiration =
2777 + rrddim_add(mpp->st_warning, "merge expiration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2778 + mpp->rd_warning_mergefastduration =
2779 + rrddim_add(mpp->st_warning, "fast duration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2780 + mpp->rd_warning_mergelowduration =
2781 + rrddim_add(mpp->st_warning, "low duration", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2782 + mpp->rd_warning_mergefastrunspeed =
2783 + rrddim_add(mpp->st_warning, "fast run speed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2784 + mpp->rd_warning_mergelowrunspeed =
2785 + rrddim_add(mpp->st_warning, "low run speed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2786 + }
2787 +
2788 + int warning = mpp->warning;
2789 + rrddim_set_by_pointer(
2790 + mpp->st_warning, mpp->rd_warning_expiration, (collected_number)(warning & MSSQL_REPLICATON_EXPIRATION));
2791 + rrddim_set_by_pointer(
2792 + mpp->st_warning, mpp->rd_warning_latency, (collected_number)(warning & MSSQL_REPLICATON_LATENCY));
2793 + rrddim_set_by_pointer(
2794 + mpp->st_warning,
2795 + mpp->rd_warning_mergeeexpiration,
2796 + (collected_number)(warning & MSSQL_REPLICATON_MERGEEXPIRATION));
2797 + rrddim_set_by_pointer(
2798 + mpp->st_warning,
2799 + mpp->rd_warning_mergefastduration,
2800 + (collected_number)(warning & MSSQL_REPLICATON_MERGEFASTDURATION));
2801 + rrddim_set_by_pointer(
2802 + mpp->st_warning,
2803 + mpp->rd_warning_mergelowduration,
2804 + (collected_number)(warning & MSSQL_REPLICATON_MERGELOWDURATION));
2805 + rrddim_set_by_pointer(
2806 + mpp->st_warning,
2807 + mpp->rd_warning_mergefastrunspeed,
2808 + (collected_number)(warning & MSSQL_REPLICATON_MERGEFASTRUNSPEED));
2809 + rrddim_set_by_pointer(
2810 + mpp->st_warning,
2811 + mpp->rd_warning_mergelowrunspeed,
2812 + (collected_number)(warning & MSSQL_REPLICATON_MERGELOWRUNSPEED));
2813 + rrdset_done(mpp->st_warning);
2814 +}
2815 +
2816 +void dict_mssql_replication_avg_latency(struct mssql_publisher_publication *mpp, int update_every)
2817 +{
2818 + if (!mpp->st_avg_latency) {
2819 + char id[RRD_ID_LENGTH_MAX + 1];
2820 +
2821 + snprintfz(
2822 + id,
2823 + RRD_ID_LENGTH_MAX,
2824 + "instance_%s_replication_%s_%s_avg_latency",
2825 + mpp->parent->instanceID,
2826 + mpp->publication,
2827 + mpp->db);
2828 + netdata_fix_chart_name(id);
2829 + mpp->st_avg_latency = rrdset_create_localhost(
2830 + "mssql",
2831 + id,
2832 + NULL,
2833 + "replication",
2834 + "mssql.replication_avg_latency",
2835 + "Average latency for a transactional publication.",
2836 + "seconds",
2837 + PLUGIN_WINDOWS_NAME,
2838 + "PerflibMSSQL",
2839 + PRIO_MSSQL_REPLICATION_AVG_LATENCY,
2840 + update_every,
2841 + RRDSET_TYPE_LINE);
2842 +
2843 + rrdlabels_add(mpp->st_avg_latency->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2844 + rrdlabels_add(mpp->st_avg_latency->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2845 + rrdlabels_add(mpp->st_avg_latency->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2846 + rrdlabels_add(mpp->st_avg_latency->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2847 +
2848 + mpp->rd_avg_latency = rrddim_add(mpp->st_avg_latency, "latency", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2849 + }
2850 +
2851 + rrddim_set_by_pointer(mpp->st_avg_latency, mpp->rd_avg_latency, (collected_number)mpp->avg_latency);
2852 + rrdset_done(mpp->st_avg_latency);
2853 +}
2854 +
2855 +void dict_mssql_replication_subscription(struct mssql_publisher_publication *mpp, int update_every)
2856 +{
2857 + if (!mpp->st_subscription_count) {
2858 + char id[RRD_ID_LENGTH_MAX + 1];
2859 +
2860 + snprintfz(
2861 + id,
2862 + RRD_ID_LENGTH_MAX,
2863 + "instance_%s_replication_%s_%s_subscription",
2864 + mpp->parent->instanceID,
2865 + mpp->publication,
2866 + mpp->db);
2867 + netdata_fix_chart_name(id);
2868 + mpp->st_subscription_count = rrdset_create_localhost(
2869 + "mssql",
2870 + id,
2871 + NULL,
2872 + "replication",
2873 + "mssql.replication_subscription",
2874 + "Number of subscriptions to a publication.",
2875 + "subscription",
2876 + PLUGIN_WINDOWS_NAME,
2877 + "PerflibMSSQL",
2878 + PRIO_MSSQL_REPLICATION_SUBSCRIPTION_COUNT,
2879 + update_every,
2880 + RRDSET_TYPE_LINE);
2881 +
2882 + rrdlabels_add(
2883 + mpp->st_subscription_count->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2884 + rrdlabels_add(mpp->st_subscription_count->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2885 + rrdlabels_add(mpp->st_subscription_count->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2886 + rrdlabels_add(mpp->st_subscription_count->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2887 +
2888 + mpp->rd_subscription_count =
2889 + rrddim_add(mpp->st_subscription_count, "subscription", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2890 + }
2891 +
2892 + rrddim_set_by_pointer(
2893 + mpp->st_subscription_count, mpp->rd_subscription_count, (collected_number)mpp->subscriptioncount);
2894 + rrdset_done(mpp->st_subscription_count);
2895 +}
2896 +
2897 +void dict_mssql_replication_dist_agent_running(struct mssql_publisher_publication *mpp, int update_every)
2898 +{
2899 + if (!mpp->st_running_agent) {
2900 + char id[RRD_ID_LENGTH_MAX + 1];
2901 +
2902 + snprintfz(
2903 + id,
2904 + RRD_ID_LENGTH_MAX,
2905 + "instance_%s_replication_%s_%s_agent_running",
2906 + mpp->parent->instanceID,
2907 + mpp->publication,
2908 + mpp->db);
2909 + netdata_fix_chart_name(id);
2910 + mpp->st_running_agent = rrdset_create_localhost(
2911 + "mssql",
2912 + id,
2913 + NULL,
2914 + "replication",
2915 + "mssql.replication_agent_running",
2916 + "Distribution agents running.",
2917 + "agents",
2918 + PLUGIN_WINDOWS_NAME,
2919 + "PerflibMSSQL",
2920 + PRIO_MSSQL_REPLICATION_AGENT_RUNNING,
2921 + update_every,
2922 + RRDSET_TYPE_LINE);
2923 +
2924 + rrdlabels_add(mpp->st_running_agent->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2925 + rrdlabels_add(mpp->st_running_agent->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2926 + rrdlabels_add(mpp->st_running_agent->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2927 + rrdlabels_add(mpp->st_running_agent->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2928 +
2929 + mpp->rd_running_agent = rrddim_add(mpp->st_running_agent, "agents", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2930 + }
2931 +
2932 + rrddim_set_by_pointer(mpp->st_running_agent, mpp->rd_running_agent, (collected_number)mpp->runningdistagentcount);
2933 + rrdset_done(mpp->st_running_agent);
2934 +}
2935 +
2936 +void dict_mssql_replication_sync_time(struct mssql_publisher_publication *mpp, int update_every)
2937 +{
2938 + if (!mpp->st_synchronization_time) {
2939 + char id[RRD_ID_LENGTH_MAX + 1];
2940 +
2941 + snprintfz(
2942 + id,
2943 + RRD_ID_LENGTH_MAX,
2944 + "instance_%s_replication_%s_%s_synchronization",
2945 + mpp->parent->instanceID,
2946 + mpp->publication,
2947 + mpp->db);
2948 + netdata_fix_chart_name(id);
2949 + mpp->st_synchronization_time = rrdset_create_localhost(
2950 + "mssql",
2951 + id,
2952 + NULL,
2953 + "replication",
2954 + "mssql.replication_synchronization",
2955 + "The shortest synchronization.",
2956 + "seconds",
2957 + PLUGIN_WINDOWS_NAME,
2958 + "PerflibMSSQL",
2959 + PRIO_MSSQL_REPLICATION_SYNC_TIME,
2960 + update_every,
2961 + RRDSET_TYPE_LINE);
2962 +
2963 + rrdlabels_add(
2964 + mpp->st_synchronization_time->rrdlabels, "mssql_instance", mpp->parent->instanceID, RRDLABEL_SRC_AUTO);
2965 + rrdlabels_add(mpp->st_synchronization_time->rrdlabels, "publisher", mpp->publisher, RRDLABEL_SRC_AUTO);
2966 + rrdlabels_add(mpp->st_synchronization_time->rrdlabels, "database", mpp->db, RRDLABEL_SRC_AUTO);
2967 + rrdlabels_add(mpp->st_synchronization_time->rrdlabels, "publication", mpp->publication, RRDLABEL_SRC_AUTO);
2968 +
2969 + mpp->rd_synchronization_time =
2970 + rrddim_add(mpp->st_synchronization_time, "seconds", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2971 + }
2972 +
2973 + rrddim_set_by_pointer(
2974 + mpp->st_synchronization_time, mpp->rd_synchronization_time, (collected_number)mpp->runningdistagentcount);
2975 + rrdset_done(mpp->st_synchronization_time);
2976 +}
2977 +
2978 +int dict_mssql_replication_chart_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2979 +{
2980 + struct mssql_publisher_publication *mpp = value;
2981 + int *update_every = data;
2982 +
2983 + dict_mssql_replication_status(mpp, *update_every);
2984 + dict_mssql_replication_warning(mpp, *update_every);
2985 + dict_mssql_replication_avg_latency(mpp, *update_every);
2986 + dict_mssql_replication_subscription(mpp, *update_every);
2987 + dict_mssql_replication_dist_agent_running(mpp, *update_every);
2988 + dict_mssql_replication_sync_time(mpp, *update_every);
2989 +}
2990 +
2991 +static void do_mssql_replication(struct mssql_instance *mi, int update_every)
2992 +{
2993 + dictionary_sorted_walkthrough_read(mi->publisher_publication, dict_mssql_replication_chart_cb, &update_every);
2994 +}
2995 +
2996 static void mssql_database_backup_restore_chart(struct mssql_db_instance *mdi, const char *db, int update_every)
2997 {
2998 char id[RRD_ID_LENGTH_MAX + 1];
@@ -3104,6 +3725,8 @@ int dict_mssql_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value
3725 doMSSQL[i](pDataBlock, mi, *update_every);
3726 }
3727
3728 + do_mssql_replication(mi, *update_every);
3729 +
3730 return 1;
3731 }
3732
src/collectors/windows.plugin/windows_plugin.h
+17
@@ -56,6 +56,16 @@ void do_PerflibMSSQL_cleanup();
56 void do_GetHardwareInfo_cleanup();
57 void do_Sensors_cleanup();
58
59 +enum MSSQL_REPLICATION_WARNINGS {
60 + MSSQL_REPLICATON_EXPIRATION = 1<<0,
61 + MSSQL_REPLICATON_LATENCY = 1<<1,
62 + MSSQL_REPLICATON_MERGEEXPIRATION = 1<<2,
63 + MSSQL_REPLICATON_MERGEFASTDURATION = 1<<3,
64 + MSSQL_REPLICATON_MERGELOWDURATION = 1<<4,
65 + MSSQL_REPLICATON_MERGEFASTRUNSPEED = 1<<5,
66 + MSSQL_REPLICATON_MERGELOWRUNSPEED = 1<<6
67 +};
68 +
69 enum PERFLIB_PRIO {
70 PRIO_WEBSITE_IIS_REQUESTS_RATE = 21000, // PRIO selected, because APPS is using 20YYY
71 PRIO_WEBSITE_IIS_REQUESTS_BY_TYPE_RATE,
@@ -148,6 +158,13 @@ enum PERFLIB_PRIO {
158
159 PRIO_MSSQL_SQL_ERRORS,
160
161 + PRIO_MSSQL_REPLICATION_STATUS,
162 + PRIO_MSSQL_REPLICATION_WARNING,
163 + PRIO_MSSQL_REPLICATION_AVG_LATENCY,
164 + PRIO_MSSQL_REPLICATION_SUBSCRIPTION_COUNT,
165 + PRIO_MSSQL_REPLICATION_AGENT_RUNNING,
166 + PRIO_MSSQL_REPLICATION_SYNC_TIME,
167 +
168 PRIO_NETFRAMEWORK_CLR_EXCEPTION_THROWN,
169 PRIO_NETFRAMEWORK_CLR_EXCEPTION_FILTERS,
170 PRIO_NETFRAMEWORK_CLR_EXCEPTION_FINALLYS,