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,