@cryptotaxi247 / netdata-1 / commits / 983a26d1a

Revert "Revert changes since v1.21 in pereparation for hotfix release."

This reverts commit e2874320fc027f7ab51ab3e115d5b1889b8fd747.

Austin S. Hemmelgarn committed Apr 13, 2020 at 10:32 UTC 983a26d1a2c110b35db252b4b79c3f03eb4eeb4b
56 files changed +1647 -442
CMakeLists.txt
+2
@@ -1112,6 +1112,8 @@ endif()
1112 -Wl,--wrap=recv
1113 -Wl,--wrap=send
1114 -Wl,--wrap=connect_to_one_of
1115 + -Wl,--wrap=create_main_rusage_chart
1116 + -Wl,--wrap=send_main_rusage
1117 ${PROMETHEUS_REMOTE_WRITE_LINK_OPTIONS}
1118 ${KINESIS_LINK_OPTIONS}
1119 ${MONGODB_LINK_OPTIONS}
Makefile.am
+6 -26
@@ -573,6 +573,7 @@ NETDATA_FILES = \
573 $(LIBNETDATA_FILES) \
574 $(API_PLUGIN_FILES) \
575 $(BACKENDS_PLUGIN_FILES) \
576 + $(EXPORTING_ENGINE_FILES) \
577 $(CHECKS_PLUGIN_FILES) \
578 $(HEALTH_PLUGIN_FILES) \
579 $(IDLEJITTER_PLUGIN_FILES) \
@@ -608,12 +609,6 @@ if LINUX
609
610 endif
611
611 -if ENABLE_EXPORTING
612 - NETDATA_FILES += \
613 - $(EXPORTING_ENGINE_FILES) \
614 - $(NULL)
615 -endif
616 -
612 NETDATA_COMMON_LIBS = \
613 $(OPTIONAL_MATH_LIBS) \
614 $(OPTIONAL_ZLIB_LIBS) \
@@ -745,23 +740,13 @@ if ENABLE_PLUGIN_SLABINFO
740 $(NULL)
741 endif
742
748 -if ENABLE_EXPORTING
749 -if ENABLE_BACKEND_KINESIS
750 - netdata_SOURCES += $(KINESIS_EXPORTING_FILES)
751 - netdata_LDADD += $(OPTIONAL_KINESIS_LIBS)
752 -endif
753 -endif
754 -
743 if ENABLE_BACKEND_KINESIS
756 - netdata_SOURCES += $(KINESIS_BACKEND_FILES)
744 + netdata_SOURCES += $(KINESIS_BACKEND_FILES) $(KINESIS_EXPORTING_FILES)
745 netdata_LDADD += $(OPTIONAL_KINESIS_LIBS)
746 endif
747
748 if ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE
761 -if ENABLE_EXPORTING
762 - netdata_SOURCES += $(PROMETHEUS_REMOTE_WRITE_EXPORTING_FILES)
763 -endif
764 - netdata_SOURCES += $(PROMETHEUS_REMOTE_WRITE_BACKEND_FILES)
749 + netdata_SOURCES += $(PROMETHEUS_REMOTE_WRITE_BACKEND_FILES) $(PROMETHEUS_REMOTE_WRITE_EXPORTING_FILES)
750 netdata_LDADD += $(OPTIONAL_PROMETHEUS_REMOTE_WRITE_LIBS)
751 BUILT_SOURCES = \
752 exporting/prometheus/remote_write/remote_write.pb.cc \
@@ -775,15 +760,8 @@ exporting/prometheus/remote_write/remote_write.pb.h: exporting/prometheus/remote
760
761 endif
762
778 -if ENABLE_EXPORTING
779 -if ENABLE_BACKEND_MONGODB
780 - netdata_SOURCES += $(MONGODB_EXPORTING_FILES)
781 - netdata_LDADD += $(OPTIONAL_MONGOC_LIBS)
782 -endif
783 -endif
784 -
763 if ENABLE_BACKEND_MONGODB
786 - netdata_SOURCES += $(MONGODB_BACKEND_FILES)
764 + netdata_SOURCES += $(MONGODB_BACKEND_FILES) $(MONGODB_EXPORTING_FILES)
765 netdata_LDADD += $(OPTIONAL_MONGOC_LIBS)
766 endif
767
@@ -895,6 +873,8 @@ if ENABLE_UNITTESTS
873 -Wl,--wrap=recv \
874 -Wl,--wrap=send \
875 -Wl,--wrap=connect_to_one_of \
876 + -Wl,--wrap=create_main_rusage_chart \
877 + -Wl,--wrap=send_main_rusage \
878 $(TEST_LDFLAGS) \
879 $(NULL)
880 exporting_tests_exporting_engine_testdriver_LDADD = $(NETDATA_COMMON_LIBS) $(TEST_LIBS)
README.md
+2 -1
@@ -1,6 +1,7 @@
1 <!--
2 ---
3 title: "Netdata"
4 +date: 2020-04-06
5 custom_edit_url: https://github.com/netdata/netdata/edit/master/README.md
6 ---
7 -->
@@ -33,7 +34,7 @@ granularity. Run this long-term storage autonomously, or integrate Netdata with
34 Netdata is **fast** and **efficient**, designed to permanently run on all systems (**physical** and **virtual** servers,
35 **containers**, **IoT** devices), without disrupting their core function.
36
36 -Netdata is **free, open-source software** and it currently runs on **Linux**, **FreeBSD**, and **MacOS**, along with
37 +Netdata is **free, open-source software** and it currently runs on **Linux**, **FreeBSD**, and **macOS**, along with
38 other systems derived from them, such as **Kubernetes** and **Docker**.
39
40 Netdata is not hosted by the CNCF but is the 3rd most starred open-source project in the [Cloud Native Computing
aclk/agent_cloud_link.c
+67 -53
@@ -23,6 +23,8 @@ static char *aclk_password = NULL;
23 static char *global_base_topic = NULL;
24 static int aclk_connecting = 0;
25 int aclk_connected = 0; // Exposed in the web-api
26 +usec_t aclk_session_us = 0; // Used by the mqtt layer
27 +time_t aclk_session_sec = 0; // Used by the mqtt layer
28
29 static netdata_mutex_t aclk_mutex = NETDATA_MUTEX_INITIALIZER;
30 static netdata_mutex_t query_mutex = NETDATA_MUTEX_INITIALIZER;
@@ -185,7 +187,7 @@ biofailed:
187 * should be called with
188 *
189 * mode 0 to reset the delay
188 - * mode 1 to sleep for the calculated amount of time [0 .. ACLK_MAX_BACKOFF_DELAY * 1000] ms
190 + * mode 1 to calculate sleep time [0 .. ACLK_MAX_BACKOFF_DELAY * 1000] ms
191 *
192 */
193 unsigned long int aclk_reconnect_delay(int mode)
@@ -208,8 +210,6 @@ unsigned long int aclk_reconnect_delay(int mode)
210 delay = (delay * 1000) + (random() % 1000);
211 }
212
211 - // sleep_usec(USEC_PER_MS * delay);
212 -
213 return delay;
214 }
215
@@ -306,7 +306,7 @@ int aclk_queue_query(char *topic, char *data, char *msg_id, char *query, int run
306 if (tmp_query->run_after == run_after) {
307 QUERY_UNLOCK;
308 QUERY_THREAD_WAKEUP;
309 - return 1;
309 + return 0;
310 }
311
312 if (last_query)
@@ -750,8 +750,8 @@ int aclk_execute_query(struct aclk_query *this_query)
750 buffer_flush(local_buffer);
751 local_buffer->contenttype = CT_APPLICATION_JSON;
752
753 - aclk_create_header(local_buffer, "http", this_query->msg_id);
754 -
753 + aclk_create_header(local_buffer, "http", this_query->msg_id, 0, 0);
754 + buffer_strcat(local_buffer, ",\n\t\"payload\": ");
755 char *encoded_response = aclk_encode_response(w->response.data);
756
757 buffer_sprintf(
@@ -821,11 +821,6 @@ int aclk_process_query()
821 aclk_send_message(this_query->topic, this_query->query, this_query->msg_id);
822 break;
823
824 - case ACLK_CMD_ALARMS:
825 - debug(D_ACLK, "EXECUTING an alarms update command");
826 - aclk_send_alarm_metadata();
827 - break;
828 -
824 case ACLK_CMD_CLOUD:
825 debug(D_ACLK, "EXECUTING a cloud command");
826 aclk_execute_query(this_query);
@@ -868,18 +863,22 @@ int aclk_process_queries()
863 static void aclk_query_thread_cleanup(void *ptr)
864 {
865 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
871 - static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
866
867 info("cleaning up...");
868
875 - COLLECTOR_LOCK;
876 -
869 _reset_collector_list();
870 freez(collector_list);
871
880 - COLLECTOR_UNLOCK;
872 + // Clean memory for pending queries if any
873 + struct aclk_query *this_query;
874
882 - static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
875 + do {
876 + this_query = aclk_queue_pop();
877 + aclk_query_free(this_query);
878 + } while (this_query);
879 +
880 + freez(static_thread->thread);
881 + freez(static_thread);
882 }
883
884 /**
@@ -916,7 +915,7 @@ void *aclk_query_main_thread(void *ptr)
915 if (unlikely(aclk_queue_query("on_connect", NULL, NULL, NULL, 0, 1, ACLK_CMD_ONCONNECT))) {
916 errno = 0;
917 error("ACLK failed to queue on_connect command");
919 - aclk_metadata_submitted = 0;
918 + aclk_metadata_submitted = ACLK_METADATA_REQUIRED;
919 }
920 }
921
@@ -939,7 +938,6 @@ void *aclk_query_main_thread(void *ptr)
938 // Thread cleanup
939 static void aclk_main_cleanup(void *ptr)
940 {
942 - char payload[512];
941 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
942 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
943
@@ -952,24 +950,11 @@ static void aclk_main_cleanup(void *ptr)
950 // Wakeup thread to cleanup
951 QUERY_THREAD_WAKEUP;
952 // Send a graceful disconnect message
955 - char *msg_id = create_uuid();
956 -
957 - usec_t time_created_offset_usec = now_realtime_usec();
958 - time_t time_created = time_created_offset_usec / USEC_PER_SEC;
959 - time_created_offset_usec = time_created_offset_usec % USEC_PER_SEC;
960 -
961 - snprintfz(
962 - payload, 511,
963 - "{ \"type\": \"disconnect\","
964 - " \"msg-id\": \"%s\","
965 - " \"timestamp\": %ld,"
966 - " \"timestamp-offset-usec\": %llu,"
967 - " \"version\": %d,"
968 - " \"payload\": \"graceful\" }",
969 - msg_id, time_created, time_created_offset_usec, ACLK_VERSION);
970 -
971 - aclk_send_message(ACLK_METADATA_TOPIC, payload, msg_id);
972 - freez(msg_id);
953 + BUFFER *b = buffer_create(512);
954 + aclk_create_header(b, "disconnect", NULL, 0, 0);
955 + buffer_strcat(b, ",\n\t\"payload\": \"graceful\"}\n");
956 + aclk_send_message(ACLK_METADATA_TOPIC, (char*)buffer_tostring(b), NULL);
957 + buffer_free(b);
958
959 event_loop_timeout = now_realtime_sec() + 5;
960 write_q = 1;
@@ -990,7 +975,6 @@ static void aclk_main_cleanup(void *ptr)
975 }
976 }
977
993 - info("Disconnected");
978
979 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
980 }
@@ -1295,7 +1279,6 @@ void *aclk_main(void *ptr)
1279 {
1280 struct netdata_static_thread *query_thread;
1281
1298 - netdata_thread_cleanup_push(aclk_main_cleanup, ptr);
1282 if (!netdata_cloud_setting) {
1283 info("Killing ACLK thread -> cloud functionality has been disabled");
1284 return NULL;
@@ -1335,10 +1318,11 @@ void *aclk_main(void *ptr)
1318 sleep_usec(USEC_PER_SEC * 60);
1319 }
1320 create_publish_base_topic();
1338 - create_private_key();
1321
1322 usec_t reconnect_expiry = 0; // In usecs
1323
1324 + netdata_thread_disable_cancelability();
1325 +
1326 while (!netdata_exit) {
1327 static int first_init = 0;
1328 size_t write_q, write_q_bytes, read_q;
@@ -1392,7 +1376,8 @@ void *aclk_main(void *ptr)
1376 }
1377 } // forever
1378 exited:
1395 - aclk_shutdown();
1379 + // Wakeup query thread to cleanup
1380 + QUERY_THREAD_WAKEUP;
1381
1382 freez(aclk_username);
1383 freez(aclk_password);
@@ -1401,7 +1386,7 @@ exited:
1386 if (aclk_private_key != NULL)
1387 RSA_free(aclk_private_key);
1388
1404 - netdata_thread_cleanup_pop(1);
1389 + aclk_main_cleanup(ptr);
1390 return NULL;
1391 }
1392
@@ -1514,7 +1499,7 @@ void aclk_shutdown()
1499 info("Shutdown complete");
1500 }
1501
1517 -inline void aclk_create_header(BUFFER *dest, char *type, char *msg_id)
1502 +inline void aclk_create_header(BUFFER *dest, char *type, char *msg_id, time_t ts_secs, usec_t ts_us)
1503 {
1504 uuid_t uuid;
1505 char uuid_str[36 + 1];
@@ -1525,9 +1510,11 @@ inline void aclk_create_header(BUFFER *dest, char *type, char *msg_id)
1510 msg_id = uuid_str;
1511 }
1512
1528 - usec_t time_created_offset_usec = now_realtime_usec();
1529 - time_t time_created = time_created_offset_usec / USEC_PER_SEC;
1530 - time_created_offset_usec = time_created_offset_usec % USEC_PER_SEC;
1513 + if (ts_secs == 0) {
1514 + ts_us = now_realtime_usec();
1515 + ts_secs = ts_us / USEC_PER_SEC;
1516 + ts_us = ts_us % USEC_PER_SEC;
1517 + }
1518
1519 buffer_sprintf(
1520 dest,
@@ -1535,11 +1522,12 @@ inline void aclk_create_header(BUFFER *dest, char *type, char *msg_id)
1522 "\t\"msg-id\": \"%s\",\n"
1523 "\t\"timestamp\": %ld,\n"
1524 "\t\"timestamp-offset-usec\": %llu,\n"
1538 - "\t\"version\": %d,\n"
1539 - "\t\"payload\": ",
1540 - type, msg_id, time_created, time_created_offset_usec, ACLK_VERSION);
1525 + "\t\"connect\": %ld,\n"
1526 + "\t\"connect-offset-usec\": %llu,\n"
1527 + "\t\"version\": %d",
1528 + type, msg_id, ts_secs, ts_us, aclk_session_sec, aclk_session_us, ACLK_VERSION);
1529
1542 - debug(D_ACLK, "Sending v%d msgid [%s] type [%s] time [%ld]", ACLK_VERSION, msg_id, type, time_created);
1530 + debug(D_ACLK, "Sending v%d msgid [%s] type [%s] time [%ld]", ACLK_VERSION, msg_id, type, ts_secs);
1531 }
1532
1533 /*
@@ -1599,7 +1587,15 @@ void aclk_send_alarm_metadata()
1587
1588 debug(D_ACLK, "Metadata alarms start");
1589
1602 - aclk_create_header(local_buffer, "connect_alarms", msg_id);
1590 + // on_connect messages are sent on a health reload, if the on_connect message is real then we
1591 + // use the session time as the fake timestamp to indicate that it starts the session. If it is
1592 + // a fake on_connect message then use the real timestamp to indicate it is within the existing
1593 + // session.
1594 + if (aclk_metadata_submitted == ACLK_METADATA_SENT)
1595 + aclk_create_header(local_buffer, "connect_alarms", msg_id, 0, 0);
1596 + else
1597 + aclk_create_header(local_buffer, "connect_alarms", msg_id, aclk_session_sec, aclk_session_us);
1598 + buffer_strcat(local_buffer, ",\n\t\"payload\": ");
1599
1600 buffer_sprintf(local_buffer, "{\n\t \"configured-alarms\" : ");
1601 health_alarms2json(localhost, local_buffer, 1);
@@ -1635,7 +1631,16 @@ int aclk_send_info_metadata()
1631 buffer_flush(local_buffer);
1632 local_buffer->contenttype = CT_APPLICATION_JSON;
1633
1638 - aclk_create_header(local_buffer, "connect", msg_id);
1634 + // on_connect messages are sent on a health reload, if the on_connect message is real then we
1635 + // use the session time as the fake timestamp to indicate that it starts the session. If it is
1636 + // a fake on_connect message then use the real timestamp to indicate it is within the existing
1637 + // session.
1638 + if (aclk_metadata_submitted == ACLK_METADATA_SENT)
1639 + aclk_create_header(local_buffer, "connect", msg_id, 0, 0);
1640 + else
1641 + aclk_create_header(local_buffer, "connect", msg_id, aclk_session_sec, aclk_session_us);
1642 + buffer_strcat(local_buffer, ",\n\t\"payload\": ");
1643 +
1644 buffer_sprintf(local_buffer, "{\n\t \"info\" : ");
1645 web_client_api_request_v1_info_fill_buffer(localhost, local_buffer);
1646 debug(D_ACLK, "Metadata %s with info has %zu bytes", msg_id, local_buffer->len);
@@ -1728,7 +1733,9 @@ int aclk_send_single_chart(char *hostname, char *chart)
1733 buffer_flush(local_buffer);
1734 local_buffer->contenttype = CT_APPLICATION_JSON;
1735
1731 - aclk_create_header(local_buffer, "chart", msg_id);
1736 + aclk_create_header(local_buffer, "chart", msg_id, 0, 0);
1737 + buffer_strcat(local_buffer, ",\n\t\"payload\": ");
1738 +
1739 rrdset2json(st, local_buffer, NULL, NULL, 1);
1740 buffer_sprintf(local_buffer, "\t\n}");
1741
@@ -1793,7 +1800,8 @@ int aclk_update_alarm(RRDHOST *host, ALARM_ENTRY *ae)
1800 char *msg_id = create_uuid();
1801
1802 buffer_flush(local_buffer);
1796 - aclk_create_header(local_buffer, "status-change", msg_id);
1803 + aclk_create_header(local_buffer, "status-change", msg_id, 0, 0);
1804 + buffer_strcat(local_buffer, ",\n\t\"payload\": ");
1805
1806 netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
1807 health_alarm_entry2json_nolock(local_buffer, ae, host);
@@ -1863,6 +1871,12 @@ int aclk_handle_cloud_request(char *payload)
1871 return 1;
1872 }
1873
1874 + // Checked to be "http", not needed anymore
1875 + if (likely(cloud_to_agent.type_id)) {
1876 + freez(cloud_to_agent.type_id);
1877 + cloud_to_agent.type_id = NULL;
1878 + }
1879 +
1880 if (unlikely(aclk_submit_request(&cloud_to_agent)))
1881 debug(D_ACLK, "ACLK failed to queue incoming message (%s)", payload);
1882
aclk/agent_cloud_link.h
+1 -6
@@ -44,7 +44,6 @@ typedef enum aclk_cmd {
44 ACLK_CMD_CHART,
45 ACLK_CMD_CHARTDEL,
46 ACLK_CMD_ALARM,
47 - ACLK_CMD_ALARMS,
47 ACLK_CMD_MAX
48 } ACLK_CMD;
49
@@ -74,16 +73,12 @@ void *aclk_main(void *ptr);
73
74 extern int aclk_send_message(char *sub_topic, char *message, char *msg_id);
75
77 -//int aclk_init();
78 -//char *get_base_topic();
79 -
76 extern char *is_agent_claimed(void);
77 extern void aclk_lws_wss_mqtt_layer_disconect_notif();
78 char *create_uuid();
79
80 // callbacks for agent cloud link
81 int aclk_subscribe(char *topic, int qos);
86 -void aclk_shutdown();
82 int cloud_to_agent_parse(JSON_ENTRY *e);
83 void aclk_disconnect();
84 void aclk_connect();
@@ -98,7 +93,7 @@ struct aclk_query *
93 aclk_query_find(char *token, char *data, char *msg_id, char *query, ACLK_CMD cmd, struct aclk_query **last_query);
94 int aclk_update_chart(RRDHOST *host, char *chart_name, ACLK_CMD aclk_cmd);
95 int aclk_update_alarm(RRDHOST *host, ALARM_ENTRY *ae);
101 -void aclk_create_header(BUFFER *dest, char *type, char *msg_id);
96 +void aclk_create_header(BUFFER *dest, char *type, char *msg_id, time_t ts_secs, usec_t ts_us);
97 int aclk_handle_cloud_request(char *payload);
98 int aclk_submit_request(struct aclk_request *);
99 void aclk_add_collector(const char *hostname, const char *plugin_name, const char *module_name);
aclk/mqtt.c
+20 -20
@@ -5,6 +5,9 @@
5 #include "mqtt.h"
6 #include "aclk_lws_wss_client.h"
7
8 +extern usec_t aclk_session_us;
9 +extern time_t aclk_session_sec;
10 +
11 inline const char *_link_strerror(int rc)
12 {
13 return mosquitto_strerror(rc);
@@ -49,7 +52,12 @@ void disconnect_callback(struct mosquitto *mosq, void *obj, int rc)
52 UNUSED(obj);
53 UNUSED(rc);
54
52 - info("Connection to cloud failed");
55 + if (netdata_exit)
56 + info("Connection to cloud terminated due to agent shutdown");
57 + else {
58 + errno = 0;
59 + error("Connection to cloud failed");
60 + }
61 aclk_disconnect();
62
63 aclk_lws_wss_mqtt_layer_disconect_notif();
@@ -131,6 +139,11 @@ static int _mqtt_create_connection(char *username, char *password)
139 return MOSQ_ERR_UNKNOWN;
140 }
141
142 + // Record the session start time to allow a nominal LWT timestamp
143 + usec_t now = now_realtime_usec();
144 + aclk_session_sec = now / USEC_PER_SEC;
145 + aclk_session_us = now % USEC_PER_SEC;
146 +
147 _link_set_lwt("outbound/meta", 2);
148
149 mosquitto_connect_callback_set(mosq, connect_callback);
@@ -259,7 +272,6 @@ int _link_set_lwt(char *sub_topic, int qos)
272 {
273 int rc;
274 char topic[ACLK_MAX_TOPIC + 1];
262 - char payload[512];
275 char *final_topic;
276
277 final_topic = get_topic(sub_topic, topic, ACLK_MAX_TOPIC);
@@ -269,25 +281,13 @@ int _link_set_lwt(char *sub_topic, int qos)
281 return 1;
282 }
283
272 - usec_t time_created_offset_usec = now_realtime_usec();
273 - time_t time_created = time_created_offset_usec / USEC_PER_SEC;
274 - time_created_offset_usec = time_created_offset_usec % USEC_PER_SEC;
275 -
276 - char *msg_id = create_uuid();
277 -
278 - snprintfz(
279 - payload, 511,
280 - "{ \"type\": \"disconnect\","
281 - " \"msg-id\": \"%s\","
282 - " \"timestamp\": %ld,"
283 - " \"timestamp-offset-usec\": %llu,"
284 - " \"version\": %d,"
285 - " \"payload\": \"unexpected\" }",
286 - msg_id, time_created, time_created_offset_usec, ACLK_VERSION);
287 -
288 - freez(msg_id);
284 + usec_t lwt_time = aclk_session_sec * USEC_PER_SEC + aclk_session_us + 1;
285 + BUFFER *b = buffer_create(512);
286 + aclk_create_header(b, "disconnect", NULL, lwt_time / USEC_PER_SEC, lwt_time % USEC_PER_SEC);
287 + buffer_strcat(b, ", \"payload\": \"unexpected\" }");
288 + rc = mosquitto_will_set(mosq, topic, buffer_strlen(b), buffer_tostring(b), qos, 0);
289 + buffer_free(b);
290
290 - rc = mosquitto_will_set(mosq, topic, strlen(payload), (const void *) payload, qos, 0);
291 return rc;
292 }
293
backends/backends.h
-4
@@ -27,10 +27,6 @@ typedef enum backend_types {
27 BACKEND_TYPE_NUM // Number of backend types
28 } BACKEND_TYPE;
29
30 -#ifdef ENABLE_EXPORTING
31 -#include "exporting/exporting_engine.h"
32 -#endif
33 -
30 typedef int (**backend_response_checker_t)(BUFFER *);
31 typedef int (**backend_request_formatter_t)(BUFFER *, const char *, RRDHOST *, const char *, RRDSET *, RRDDIM *, time_t, time_t, BACKEND_OPTIONS);
32
backends/prometheus/backend_prometheus.c
+20 -20
@@ -44,7 +44,7 @@ static inline time_t prometheus_server_last_access(const char *server, RRDHOST *
44 return 0;
45 }
46
47 -static inline size_t prometheus_name_copy(char *d, const char *s, size_t usable) {
47 +static inline size_t backends_prometheus_name_copy(char *d, const char *s, size_t usable) {
48 size_t n;
49
50 for(n = 0; *s && n < usable ; d++, s++, n++) {
@@ -58,7 +58,7 @@ static inline size_t prometheus_name_copy(char *d, const char *s, size_t usable)
58 return n;
59 }
60
61 -static inline size_t prometheus_label_copy(char *d, const char *s, size_t usable) {
61 +static inline size_t backends_prometheus_label_copy(char *d, const char *s, size_t usable) {
62 size_t n;
63
64 // make sure we can escape one character without overflowing the buffer
@@ -78,7 +78,7 @@ static inline size_t prometheus_label_copy(char *d, const char *s, size_t usable
78 return n;
79 }
80
81 -static inline char *prometheus_units_copy(char *d, const char *s, size_t usable, int showoldunits) {
81 +static inline char *backends_prometheus_units_copy(char *d, const char *s, size_t usable, int showoldunits) {
82 const char *sorig = s;
83 char *ret = d;
84 size_t n;
@@ -194,7 +194,7 @@ static int print_host_variables(RRDVAR *rv, void *data) {
194 label_post = "}";
195 }
196
197 - prometheus_name_copy(opts->name, rv->name, sizeof(opts->name));
197 + backends_prometheus_name_copy(opts->name, rv->name, sizeof(opts->name));
198
199 if(opts->output_options & BACKENDS_PROMETHEUS_OUTPUT_TIMESTAMPS)
200 buffer_sprintf(opts->wb
@@ -227,7 +227,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER
227 rrdhost_rdlock(host);
228
229 char hostname[PROMETHEUS_ELEMENT_MAX + 1];
230 - prometheus_label_copy(hostname, host->hostname, PROMETHEUS_ELEMENT_MAX);
230 + backends_prometheus_label_copy(hostname, host->hostname, PROMETHEUS_ELEMENT_MAX);
231
232 char labels[PROMETHEUS_LABELS_MAX + 1] = "";
233 if(allhosts) {
@@ -299,9 +299,9 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER
299 char family[PROMETHEUS_ELEMENT_MAX + 1];
300 char units[PROMETHEUS_ELEMENT_MAX + 1] = "";
301
302 - prometheus_label_copy(chart, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && st->name)?st->name:st->id, PROMETHEUS_ELEMENT_MAX);
303 - prometheus_label_copy(family, st->family, PROMETHEUS_ELEMENT_MAX);
304 - prometheus_name_copy(context, st->context, PROMETHEUS_ELEMENT_MAX);
302 + backends_prometheus_label_copy(chart, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && st->name)?st->name:st->id, PROMETHEUS_ELEMENT_MAX);
303 + backends_prometheus_label_copy(family, st->family, PROMETHEUS_ELEMENT_MAX);
304 + backends_prometheus_name_copy(context, st->context, PROMETHEUS_ELEMENT_MAX);
305
306 if(likely(backends_can_send_rrdset(backend_options, st))) {
307 rrdset_rdlock(st);
@@ -317,7 +317,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER
317 }
318 else {
319 if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AVERAGE && !(output_options & BACKENDS_PROMETHEUS_OUTPUT_HIDEUNITS))
320 - prometheus_units_copy(units, st->units, PROMETHEUS_ELEMENT_MAX, output_options & BACKENDS_PROMETHEUS_OUTPUT_OLDUNITS);
320 + backends_prometheus_units_copy(units, st->units, PROMETHEUS_ELEMENT_MAX, output_options & BACKENDS_PROMETHEUS_OUTPUT_OLDUNITS);
321 }
322
323 if(unlikely(output_options & BACKENDS_PROMETHEUS_OUTPUT_HELP))
@@ -354,7 +354,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER
354 // all the dimensions of the chart, has the same algorithm, multiplier and divisor
355 // we add all dimensions as labels
356
357 - prometheus_label_copy(dimension, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
357 + backends_prometheus_label_copy(dimension, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
358
359 if(unlikely(output_options & BACKENDS_PROMETHEUS_OUTPUT_HELP))
360 buffer_sprintf(wb
@@ -411,7 +411,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER
411 // the dimensions of the chart, do not have the same algorithm, multiplier or divisor
412 // we create a metric per dimension
413
414 - prometheus_name_copy(dimension, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
414 + backends_prometheus_name_copy(dimension, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
415
416 if(unlikely(output_options & BACKENDS_PROMETHEUS_OUTPUT_HELP))
417 buffer_sprintf(wb
@@ -480,7 +480,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER
480 else if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_SUM)
481 suffix = "_sum";
482
483 - prometheus_label_copy(dimension, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
483 + backends_prometheus_label_copy(dimension, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
484
485 if (unlikely(output_options & BACKENDS_PROMETHEUS_OUTPUT_HELP))
486 buffer_sprintf(wb, "# COMMENT %s_%s%s%s: dimension \"%s\", value is %s, gauge, dt %llu to %llu inclusive\n"
@@ -593,7 +593,7 @@ void backends_rrd_stats_remote_write_allmetrics_prometheus(
593 , size_t *count_dims_skipped
594 ) {
595 char hostname[PROMETHEUS_ELEMENT_MAX + 1];
596 - prometheus_label_copy(hostname, __hostname, PROMETHEUS_ELEMENT_MAX);
596 + backends_prometheus_label_copy(hostname, __hostname, PROMETHEUS_ELEMENT_MAX);
597
598 backends_add_host_info("netdata_info", hostname, host->program_name, host->program_version, now_realtime_usec() / USEC_PER_MS);
599
@@ -620,9 +620,9 @@ void backends_rrd_stats_remote_write_allmetrics_prometheus(
620 char family[PROMETHEUS_ELEMENT_MAX + 1];
621 char units[PROMETHEUS_ELEMENT_MAX + 1] = "";
622
623 - prometheus_label_copy(chart, (backend_options & BACKEND_OPTION_SEND_NAMES && st->name)?st->name:st->id, PROMETHEUS_ELEMENT_MAX);
624 - prometheus_label_copy(family, st->family, PROMETHEUS_ELEMENT_MAX);
625 - prometheus_name_copy(context, st->context, PROMETHEUS_ELEMENT_MAX);
623 + backends_prometheus_label_copy(chart, (backend_options & BACKEND_OPTION_SEND_NAMES && st->name)?st->name:st->id, PROMETHEUS_ELEMENT_MAX);
624 + backends_prometheus_label_copy(family, st->family, PROMETHEUS_ELEMENT_MAX);
625 + backends_prometheus_name_copy(context, st->context, PROMETHEUS_ELEMENT_MAX);
626
627 if(likely(backends_can_send_rrdset(backend_options, st))) {
628 rrdset_rdlock(st);
@@ -640,7 +640,7 @@ void backends_rrd_stats_remote_write_allmetrics_prometheus(
640 }
641 else {
642 if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AVERAGE)
643 - prometheus_units_copy(units, st->units, PROMETHEUS_ELEMENT_MAX, 0);
643 + backends_prometheus_units_copy(units, st->units, PROMETHEUS_ELEMENT_MAX, 0);
644 }
645
646 // for each dimension
@@ -664,7 +664,7 @@ void backends_rrd_stats_remote_write_allmetrics_prometheus(
664 // all the dimensions of the chart, has the same algorithm, multiplier and divisor
665 // we add all dimensions as labels
666
667 - prometheus_label_copy(dimension, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
667 + backends_prometheus_label_copy(dimension, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
668 snprintf(name, PROMETHEUS_LABELS_MAX, "%s_%s%s", prefix, context, suffix);
669
670 backends_add_metric(name, chart, family, dimension, hostname, rd->last_collected_value, timeval_msec(&rd->last_collected_time));
@@ -674,7 +674,7 @@ void backends_rrd_stats_remote_write_allmetrics_prometheus(
674 // the dimensions of the chart, do not have the same algorithm, multiplier or divisor
675 // we create a metric per dimension
676
677 - prometheus_name_copy(dimension, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
677 + backends_prometheus_name_copy(dimension, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
678 snprintf(name, PROMETHEUS_LABELS_MAX, "%s_%s_%s%s", prefix, context, dimension, suffix);
679
680 backends_add_metric(name, chart, family, NULL, hostname, rd->last_collected_value, timeval_msec(&rd->last_collected_time));
@@ -694,7 +694,7 @@ void backends_rrd_stats_remote_write_allmetrics_prometheus(
694 else if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_SUM)
695 suffix = "_sum";
696
697 - prometheus_label_copy(dimension, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
697 + backends_prometheus_label_copy(dimension, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
698 snprintf(name, PROMETHEUS_LABELS_MAX, "%s_%s%s%s", prefix, context, units, suffix);
699
700 backends_add_metric(name, chart, family, dimension, hostname, value, last_t * MSEC_PER_SEC);
build_external/README.md
+2 -1
@@ -1,6 +1,7 @@
1 <!--
2 ---
3 title: "External build-system"
4 +date: 2020-03-31
5 custom_edit_url: https://github.com/netdata/netdata/edit/master/build_external/README.md
6 ---
7 -->
@@ -9,7 +10,7 @@ custom_edit_url: https://github.com/netdata/netdata/edit/master/build_external/R
10
11 This wraps the build-system in Docker so that the host system and the target system are
12 decoupled. This allows:
12 -* Cross-compilation (e.g. linux development from MacOS)
13 +* Cross-compilation (e.g. linux development from macOS)
14 * Cross-distro (e.g. using CentOS user-land while developing on Debian)
15 * Multi-host scenarios (e.g. master/slave configurations)
16 * Bleeding-edge sceneraios (e.g. using the ACLK (**currently for internal-use only**))
collectors/COLLECTORS.md
+2 -1
@@ -1,6 +1,7 @@
1 <!--
2 ---
3 title: "Supported collectors list"
4 +date: 2020-03-31
5 custom_edit_url: https://github.com/netdata/netdata/edit/master/collectors/COLLECTORS.md
6 ---
7 -->
@@ -37,7 +38,7 @@ collector—we may be looking for contributions from users such as yourself!
38 | [diskspace.plugin](diskspace.plugin/README.md) | Linux | Collects disk space usage metrics on Linux mount points. |
39 | [freebsd.plugin](freebsd.plugin/README.md) | FreeBSD | Collects resource usage and performance data on FreeBSD systems. |
40 | [idlejitter.plugin](idlejitter.plugin/README.md) | any | Measures CPU latency and jitter on all operating systems. |
40 -| [macos.plugin](macos.plugin/README.md) | macos | Collects resource usage and performance data on MacOS systems. |
41 +| [macos.plugin](macos.plugin/README.md) | macos | Collects resource usage and performance data on macOS systems. |
42 | [proc.plugin](proc.plugin/README.md) | Linux | Collects resource usage and performance data on Linux systems. |
43 | [slabinfo.plugin](slabinfo.plugin/README.md) | Linux | Collects kernel SLAB details on Linux systems. |
44 | [statsd.plugin](statsd.plugin/README.md) | any | Implements a high performance `statsd` server for Netdata. |
collectors/apps.plugin/apps_groups.conf
+4 -4
@@ -96,7 +96,7 @@ fail2ban: fail2ban*
96 # -----------------------------------------------------------------------------
97 # web/ftp servers
98
99 -httpd: apache* httpd nginx* lighttpd
99 +httpd: apache* httpd nginx* lighttpd hiawatha
100 proxy: squid* c-icap squidGuard varnish*
101 php: php*
102 ftpd: proftpd in.tftpd vsftpd
@@ -107,7 +107,7 @@ puma: *puma*
107 # -----------------------------------------------------------------------------
108 # database servers
109
110 -sql: mysqld* mariad* postgres* postmaster* oracle_* ora_*
110 +sql: mysqld* mariad* postgres* postmaster* oracle_* ora_* sqlservr
111 nosql: mongod redis* memcached *couchdb*
112 timedb: prometheus *carbon-cache.py* *carbon-aggregator.py* *graphite/manage.py* *net.opentsdb.tools.TSDMain* influxd*
113 columndb: clickhouse-server*
@@ -223,7 +223,7 @@ torrents: *deluge* transmission* *SickBeard* *CouchPotato* *rtorrent*
223 # -----------------------------------------------------------------------------
224 # backup servers and clients
225
226 -backup: rsync lsyncd bacula*
226 +backup: rsync lsyncd bacula* borg
227
228 # -----------------------------------------------------------------------------
229 # cron
@@ -239,7 +239,7 @@ ups: upsmon upsd */nut/*
239 # media players, servers, clients
240
241 media: mplayer vlc xine mediatomb omxplayer* kodi* xbmc* mediacenter eventlircd
242 -media: mpd minidlnad mt-daapd avahi* Plex*
242 +media: mpd minidlnad mt-daapd avahi* Plex* squeeze*
243
244 # -----------------------------------------------------------------------------
245 # java applications
collectors/apps.plugin/apps_plugin.c
-5
@@ -4110,8 +4110,6 @@ int main(int argc, char **argv) {
4110
4111 procfile_adaptive_initial_allocation = 1;
4112
4113 - time_t started_t = now_monotonic_sec();
4114 -
4113 get_system_HZ();
4114 #ifdef __FreeBSD__
4115 time_factor = 1000000ULL / RATES_DETAIL; // FreeBSD uses usecs
@@ -4212,8 +4210,5 @@ int main(int argc, char **argv) {
4210 show_guest_time_old = show_guest_time;
4211
4212 debug_log("done Loop No %zu", global_iterations_counter);
4215 -
4216 - // restart check (14400 seconds)
4217 - if(now_monotonic_sec() - started_t > 14400) exit(0);
4213 }
4214 }
collectors/charts.d.plugin/libreswan/libreswan.chart.sh
+15
@@ -37,6 +37,16 @@ declare -A libreswan_established_add_time=()
37 # we need this to avoid converting tunnel names to chart IDs on every iteration
38 declare -A libreswan_tunnel_charts=()
39
40 +is_able_sudo_ipsec() {
41 + if ! sudo -n -l "${IPSEC_CMD}" whack --status > /dev/null 2>&1; then
42 + return 1
43 + fi
44 + if ! sudo -n -l "${IPSEC_CMD}" whack --trafficstatus > /dev/null 2>&1; then
45 + return 1
46 + fi
47 + return 0
48 +}
49 +
50 # run the ipsec command
51 libreswan_ipsec() {
52 if [ ${libreswan_sudo} -ne 0 ]; then
@@ -92,6 +102,11 @@ libreswan_check() {
102 return 1
103 fi
104
105 + if [ ${libreswan_sudo} -ne 0 ] && ! is_able_sudo_ipsec; then
106 + error "not enough permissions to execute ipsec with sudo. Disabling Libreswan plugin."
107 + return 1
108 + fi
109 +
110 # check that we can collect data
111 libreswan_get || return 1
112
collectors/macos.plugin/README.md
+1 -1
@@ -7,7 +7,7 @@ custom_edit_url: https://github.com/netdata/netdata/edit/master/collectors/macos
7
8 # macos.plugin
9
10 -Collects resource usage and performance data on MacOS systems
10 +Collects resource usage and performance data on macOS systems
11
12 By default, Netdata will enable monitoring metrics for disks, memory, and network only when they are not zero. If they are constantly zero they are ignored. Metrics that will start having values, after Netdata is started, will be detected and charts will be automatically added to the dashboard (a refresh of the dashboard is needed for them to appear though). Use `yes` instead of `auto` in plugin configuration sections to enable these charts permanently. You can also set the `enable zero metrics` option to `yes` in the `[global]` section which enables charts with zero metrics for all internal Netdata plugins.
13
collectors/python.d.plugin/mysql/mysql.chart.py
+1 -1
@@ -347,7 +347,7 @@ CHARTS = {
347 ]
348 },
349 'threads_creation_rate': {
350 - 'options': [None, 'Threads Creation Rate', 'threads/s', 'threads', 'mysql.threads', 'line'],
350 + 'options': [None, 'Threads Creation Rate', 'threads/s', 'threads', 'mysql.threads_creation_rate', 'line'],
351 'lines': [
352 ['Threads_created', 'created', 'incremental'],
353 ]
configure.ac
-14
@@ -433,20 +433,6 @@ fi
433 AC_MSG_RESULT([${enable_https}])
434 AM_CONDITIONAL([ENABLE_HTTPS], [test "${enable_https}" = "yes"])
435
436 -# -----------------------------------------------------------------------------
437 -# Exporting engine
438 -AC_MSG_CHECKING([if netdata exporting engine should be used])
439 -if test "${UV_LIBS}"; then
440 - enable_exporting_engine="yes"
441 - AC_DEFINE([ENABLE_EXPORTING], [1], [netdata exporting engine usability])
442 - OPTIONAL_UV_CFLAGS="${UV_CFLAGS}"
443 - OPTIONAL_UV_LIBS="${UV_LIBS}"
444 -else
445 - enable_exporting_engine="no"
446 -fi
447 -AC_MSG_RESULT([${enable_exporting_engine}])
448 -AM_CONDITIONAL([ENABLE_EXPORTING], [test "${enable_exporting_engine}" = "yes"])
449 -
436 # -----------------------------------------------------------------------------
437 # JSON-C
438 test "${enable_jsonc}" = "yes" -a -z "${JSONC_LIBS}" && \
daemon/common.h
+2
@@ -50,6 +50,8 @@
50
51 // backends for archiving the metrics
52 #include "backends/backends.h"
53 +// the new exporting engine for archiving the metrics
54 +#include "exporting/exporting_engine.h"
55
56 // the netdata API
57 #include "web/api/web_api_v1.h"
daemon/config/README.md
+2 -1
@@ -1,6 +1,7 @@
1 <!--
2 ---
3 title: "Daemon configuration"
4 +date: 2020-03-31
5 custom_edit_url: https://github.com/netdata/netdata/edit/master/daemon/config/README.md
6 ---
7 -->
@@ -220,7 +221,7 @@ For example, the `system.io` chart has the following default settings:
221 These `dim` settings produce two dimensions, `in` and `out`, both of which use the `incremental` algorithm. By
222 multiplying the value of `out` by -1, Netdata creates the negative values seen in the following area chart:
223
223 -![The system.io chart on a MacOS
224 +![The system.io chart on a macOS
225 laptop](https://user-images.githubusercontent.com/1153921/69286708-2cfb3900-0bb1-11ea-9fcd-dd8fbb2adf11.png)
226
227 [![analytics](https://www.google-analytics.com/collect?v=1&aip=1&t=pageview&_s=1&ds=github&dr=https%3A%2F%2Fgithub.com%2Fnetdata%2Fnetdata&dl=https%3A%2F%2Fmy-netdata.io%2Fgithub%2Fdaemon%2Fconfig%2FREADME&_u=MAC~&cid=5792dfd7-8dc4-476b-af31-da2fdb9f93d2&tid=UA-64295674-3)](<>)
daemon/main.c
-2
@@ -80,9 +80,7 @@ struct netdata_static_thread static_threads[] = {
80
81 // common plugins for all systems
82 {"BACKENDS", NULL, NULL, 1, NULL, NULL, backends_main},
83 -#ifdef ENABLE_EXPORTING
83 {"EXPORTING", NULL, NULL, 1, NULL, NULL, exporting_main},
85 -#endif
84 {"WEB_SERVER[static1]", NULL, NULL, 0, NULL, NULL, socket_listen_main_static_threaded},
85 {"STREAM", NULL, NULL, 0, NULL, NULL, rrdpush_sender_thread},
86
docs/generator/requirements.txt
+1 -1
@@ -1,2 +1,2 @@
1 mkdocs>=1.0.1
2 -mkdocs-material
2 +mkdocs-material==4.6.3
docs/netdata-security.md
+1 -1
@@ -81,7 +81,7 @@ You can bind Netdata to multiple IPs and ports. If you use hostnames, Netdata wi
81
82 For cloud based installations, if your cloud provider does not provide such a private LAN (or if you use multiple providers), you can create a virtual management and administration LAN with tools like `tincd` or `gvpe`. These tools create a mesh VPN allowing all servers to communicate securely and privately. Your administration stations join this mesh VPN to get access to management and administration tasks on all your cloud servers.
83
84 -For `gvpe` we have developed a [simple provisioning tool](https://github.com/netdata/netdata-demo-site/tree/master/gvpe) you may find handy (it includes statically compiled `gvpe` binaries for Linux and FreeBSD, and also a script to compile `gvpe` on your Mac). We use this to create a management and administration LAN for all Netdata demo sites (spread all over the internet using multiple hosting providers).
84 +For `gvpe` we have developed a [simple provisioning tool](https://github.com/netdata/netdata-demo-site/tree/master/gvpe) you may find handy (it includes statically compiled `gvpe` binaries for Linux and FreeBSD, and also a script to compile `gvpe` on your macOS system). We use this to create a management and administration LAN for all Netdata demo sites (spread all over the internet using multiple hosting providers).
85
86 ---
87
docs/step-by-step/step-00.md
+2 -1
@@ -1,6 +1,7 @@
1 <!--
2 ---
3 title: "The step-by-step Netdata tutorial"
4 +date: 2020-03-31
5 custom_edit_url: https://github.com/netdata/netdata/edit/master/docs/step-by-step/step-00.md
6 ---
7 -->
@@ -21,7 +22,7 @@ If you have monitoring experience, or would rather get straight into configuring
22 straight into code and configurations with our [getting started guide](../getting-started.md).
23
24 > This tutorial contains instructions for Netdata installed on a Linux system. Many of the instructions will work on
24 -> other supported operating systems, like FreeBSD and MacOS, but we can't make any guarantees.
25 +> other supported operating systems, like FreeBSD and macOS, but we can't make any guarantees.
26
27 ## Where to go if you need help
28
docs/step-by-step/step-04.md
+2 -1
@@ -1,6 +1,7 @@
1 <!--
2 ---
3 title: "Step 4. The basics of configuring Netdata"
4 +date: 2020-03-31
5 custom_edit_url: https://github.com/netdata/netdata/edit/master/docs/step-by-step/step-04.md
6 ---
7 -->
@@ -61,7 +62,7 @@ an example file to your Netdata config directory and then allow you to edit it b
62 > change permanent](https://stackoverflow.com/questions/13046624/how-to-permanently-export-a-variable-in-linux).
63
64 Let's give it a shot. Navigate to your Netdata config directory. To use `edit-config` on `netdata.conf`, you need to
64 -have permissions to edit the file. On Linux/MacOS systems, you can usually use `sudo` to elevate your permissions.
65 +have permissions to edit the file. On Linux/macOS systems, you can usually use `sudo` to elevate your permissions.
66
67 ```bash
68 cd /etc/netdata # Replace this path with your Netdata config directory, if different as found in the steps above
docs/tutorials/collect-unbound-metrics.md
+2 -1
@@ -1,6 +1,7 @@
1 <!--
2 ---
3 title: "Monitor Unbound DNS servers with Netdata"
4 +date: 2020-03-31
5 custom_edit_url: https://github.com/netdata/netdata/edit/master/docs/tutorials/collect-unbound-metrics.md
6 ---
7 -->
@@ -11,7 +12,7 @@ custom_edit_url: https://github.com/netdata/netdata/edit/master/docs/tutorials/c
12 Labs. In v1.19 of Netdata, we release a completely refactored collector for collecting real-time metrics from Unbound
13 servers and displaying them in Netdata dashboards.
14
14 -Unbound runs on FreeBSD, OpenBSD, NetBSD, MacOS, Linux, and Windows, and supports DNS-over-TLS, which ensures that DNS
15 +Unbound runs on FreeBSD, OpenBSD, NetBSD, macOS, Linux, and Windows, and supports DNS-over-TLS, which ensures that DNS
16 queries and answers are all encrypted with TLS. In theory, that should reduce the risk of eavesdropping or
17 man-in-the-middle attacks when communicating to DNS servers.
18
docs/what-is-netdata.md
+2 -1
@@ -1,6 +1,7 @@
1 <!--
2 ---
3 title: "What is Netdata?"
4 +date: 2020-03-31
5 custom_edit_url: https://github.com/netdata/netdata/edit/master/docs/what-is-netdata.md
6 ---
7 -->
@@ -19,7 +20,7 @@ Netdata provides **unparalleled insights**, **in real-time**, of everything happ
20
21 _Netdata is **fast** and **efficient**, designed to permanently run on all systems (**physical** & **virtual** servers, **containers**, **IoT** devices), without disrupting their core function._
22
22 -Netdata is **free, open-source software** and it currently runs on **Linux**, **FreeBSD**, and **MacOS**.
23 +Netdata is **free, open-source software** and it currently runs on **Linux**, **FreeBSD**, and **macOS**.
24
25 ---
26
exporting/aws_kinesis/aws_kinesis.c
+27 -9
@@ -75,9 +75,23 @@ void aws_kinesis_connector_worker(void *instance_p)
75 uv_mutex_lock(&instance->mutex);
76 uv_cond_wait(&instance->cond_var, &instance->mutex);
77
78 + // reset the monitoring chart counters
79 + stats->received_bytes =
80 + stats->sent_bytes =
81 + stats->sent_metrics =
82 + stats->lost_metrics =
83 + stats->receptions =
84 + stats->transmission_successes =
85 + stats->transmission_failures =
86 + stats->data_lost_events =
87 + stats->lost_bytes =
88 + stats->reconnects = 0;
89 +
90 BUFFER *buffer = (BUFFER *)instance->buffer;
91 size_t buffer_len = buffer_strlen(buffer);
92
93 + stats->buffered_bytes = buffer_len;
94 +
95 size_t sent = 0;
96
97 while (sent < buffer_len) {
@@ -115,7 +129,7 @@ void aws_kinesis_connector_worker(void *instance_p)
129 connector_specific_data, connector_specific_config->stream_name, partition_key, first_char, record_len);
130
131 sent += record_len;
118 - stats->chart_transmission_successes++;
132 + stats->transmission_successes++;
133
134 size_t sent_bytes = 0, lost_bytes = 0;
135
@@ -127,30 +141,34 @@ void aws_kinesis_connector_worker(void *instance_p)
141 "EXPORTING: failed to write data to database backend '%s'. Willing to write %zu bytes, wrote %zu bytes.",
142 instance->config.destination, sent_bytes, sent_bytes - lost_bytes);
143
130 - stats->chart_transmission_failures++;
131 - stats->chart_data_lost_events++;
132 - stats->chart_lost_bytes += lost_bytes;
144 + stats->transmission_failures++;
145 + stats->data_lost_events++;
146 + stats->lost_bytes += lost_bytes;
147
148 // estimate the number of lost metrics
135 - stats->chart_lost_metrics += (collected_number)(
136 - stats->chart_buffered_metrics *
149 + stats->lost_metrics += (collected_number)(
150 + stats->buffered_metrics *
151 (buffer_len && (lost_bytes > buffer_len) ? (double)lost_bytes / buffer_len : 1));
152
153 break;
154 } else {
141 - stats->chart_receptions++;
155 + stats->receptions++;
156 }
157
158 if (unlikely(netdata_exit))
159 break;
160 }
161
148 - stats->chart_sent_bytes += sent;
162 + stats->sent_bytes += sent;
163 if (likely(sent == buffer_len))
150 - stats->chart_sent_metrics = stats->chart_buffered_metrics;
164 + stats->sent_metrics = stats->buffered_metrics;
165
166 buffer_flush(buffer);
167
168 + send_internal_metrics(instance);
169 +
170 + stats->buffered_metrics = 0;
171 +
172 uv_mutex_unlock(&instance->mutex);
173
174 #ifdef UNIT_TESTING
exporting/exporting_engine.c
+6 -4
@@ -35,6 +35,11 @@ void *exporting_main(void *ptr)
35 goto cleanup;
36 }
37
38 + RRDSET *st_main_rusage = NULL;
39 + RRDDIM *rd_main_user = NULL;
40 + RRDDIM *rd_main_system = NULL;
41 + create_main_rusage_chart(&st_main_rusage, &rd_main_user, &rd_main_system);
42 +
43 usec_t step_ut = localhost->rrd_update_every * USEC_PER_SEC;
44 heartbeat_t hb;
45 heartbeat_init(&hb);
@@ -55,10 +60,7 @@ void *exporting_main(void *ptr)
60 break;
61 }
62
58 - if (send_internal_metrics(engine) != 0) {
59 - error("EXPORTING: cannot send metrics for the operation of exporting engine");
60 - break;
61 - }
63 + send_main_rusage(st_main_rusage, rd_main_user, rd_main_system);
64
65 #ifdef UNIT_TESTING
66 break;
exporting/exporting_engine.h
+60 -17
@@ -14,10 +14,10 @@
14 extern struct config exporting_config;
15
16 #define EXPORTING_UPDATE_EVERY_OPTION_NAME "update every"
17 -#define EXPORTING_UPDATE_EVERY_DEFAULT 10
17 +#define EXPORTING_UPDATE_EVERY_DEFAULT 10
18
19 typedef enum exporting_options {
20 - EXPORTING_OPTION_NONE = 0,
20 + EXPORTING_OPTION_NON = 0,
21
22 EXPORTING_SOURCE_DATA_AS_COLLECTED = (1 << 0),
23 EXPORTING_SOURCE_DATA_AVERAGE = (1 << 1),
@@ -42,10 +42,22 @@ typedef enum exporting_options {
42 (instance->config.options & EXPORTING_OPTION_SEND_AUTOMATIC_LABELS && \
43 label->label_source != LABEL_SOURCE_NETDATA_CONF))
44
45 +typedef enum exporting_connector_types {
46 + EXPORTING_CONNECTOR_TYPE_UNKNOWN, // Invalid type
47 + EXPORTING_CONNECTOR_TYPE_GRAPHITE, // Send plain text to Graphite
48 + EXPORTING_CONNECTOR_TYPE_OPENTSDB_USING_TELNET, // Send data to OpenTSDB using telnet API
49 + EXPORTING_CONNECTOR_TYPE_OPENTSDB_USING_HTTP, // Send data to OpenTSDB using HTTP API
50 + EXPORTING_CONNECTOR_TYPE_JSON, // Stores the data using JSON.
51 + EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE, // The user selected to use Prometheus backend
52 + EXPORTING_CONNECTOR_TYPE_KINESIS, // Send message to AWS Kinesis
53 + EXPORTING_CONNECTOR_TYPE_MONGODB, // Send data to MongoDB collection
54 + EXPORTING_CONNECTOR_TYPE_NUM // Number of backend types
55 +} EXPORTING_CONNECTOR_TYPE;
56 +
57 struct engine;
58
59 struct instance_config {
48 - BACKEND_TYPE type;
60 + EXPORTING_CONNECTOR_TYPE type;
61
62 const char *name;
63 const char *destination;
@@ -87,18 +99,42 @@ struct engine_config {
99 };
100
101 struct stats {
90 - collected_number chart_buffered_metrics;
91 - collected_number chart_lost_metrics;
92 - collected_number chart_sent_metrics;
93 - collected_number chart_buffered_bytes;
94 - collected_number chart_received_bytes;
95 - collected_number chart_sent_bytes;
96 - collected_number chart_receptions;
97 - collected_number chart_transmission_successes;
98 - collected_number chart_transmission_failures;
99 - collected_number chart_data_lost_events;
100 - collected_number chart_lost_bytes;
101 - collected_number chart_reconnects;
102 + collected_number buffered_metrics;
103 + collected_number lost_metrics;
104 + collected_number sent_metrics;
105 + collected_number buffered_bytes;
106 + collected_number lost_bytes;
107 + collected_number sent_bytes;
108 + collected_number received_bytes;
109 + collected_number transmission_successes;
110 + collected_number data_lost_events;
111 + collected_number reconnects;
112 + collected_number transmission_failures;
113 + collected_number receptions;
114 +
115 + int initialized;
116 +
117 + RRDSET *st_metrics;
118 + RRDDIM *rd_buffered_metrics;
119 + RRDDIM *rd_lost_metrics;
120 + RRDDIM *rd_sent_metrics;
121 +
122 + RRDSET *st_bytes;
123 + RRDDIM *rd_buffered_bytes;
124 + RRDDIM *rd_lost_bytes;
125 + RRDDIM *rd_sent_bytes;
126 + RRDDIM *rd_received_bytes;
127 +
128 + RRDSET *st_ops;
129 + RRDDIM *rd_transmission_successes;
130 + RRDDIM *rd_data_lost_events;
131 + RRDDIM *rd_reconnects;
132 + RRDDIM *rd_transmission_failures;
133 + RRDDIM *rd_receptions;
134 +
135 + RRDSET *st_rusage;
136 + RRDDIM *rd_user;
137 + RRDDIM *rd_system;
138 };
139
140 struct instance {
@@ -150,10 +186,12 @@ struct engine {
186 struct instance *instance_root;
187 };
188
189 +extern struct instance *prometheus_exporter_instance;
190 +
191 void *exporting_main(void *ptr);
192
193 struct engine *read_exporting_config();
156 -BACKEND_TYPE exporting_select_type(const char *type);
194 +EXPORTING_CONNECTOR_TYPE exporting_select_type(const char *type);
195
196 int init_connectors(struct engine *engine);
197
@@ -179,12 +217,17 @@ int end_chart_formatting(struct engine *engine, RRDSET *st);
217 int end_host_formatting(struct engine *engine, RRDHOST *host);
218 int end_batch_formatting(struct engine *engine);
219 int flush_host_labels(struct instance *instance, RRDHOST *host);
220 +int simple_connector_update_buffered_bytes(struct instance *instance);
221
222 int exporting_discard_response(BUFFER *buffer, struct instance *instance);
223 void simple_connector_receive_response(int *sock, struct instance *instance);
224 void simple_connector_send_buffer(int *sock, int *failures, struct instance *instance);
225 void simple_connector_worker(void *instance_p);
226
188 -int send_internal_metrics(struct engine *engine);
227 +void create_main_rusage_chart(RRDSET **st_rusage, RRDDIM **rd_user, RRDDIM **rd_system);
228 +void send_main_rusage(RRDSET *st_rusage, RRDDIM *rd_user, RRDDIM *rd_system);
229 +void send_internal_metrics(struct instance *instance);
230 +
231 +#include "exporting/prometheus/prometheus.h"
232
233 #endif /* NETDATA_EXPORTING_ENGINE_H */
exporting/graphite/graphite.c
+1 -1
@@ -27,7 +27,7 @@ int init_graphite_instance(struct instance *instance)
27
28 instance->end_chart_formatting = NULL;
29 instance->end_host_formatting = flush_host_labels;
30 - instance->end_batch_formatting = NULL;
30 + instance->end_batch_formatting = simple_connector_update_buffered_bytes;
31
32 instance->send_header = NULL;
33 instance->check_response = exporting_discard_response;
exporting/init_connectors.c
+8 -8
@@ -32,35 +32,35 @@ int init_connectors(struct engine *engine)
32 instance->after = engine->now;
33
34 switch (instance->config.type) {
35 - case BACKEND_TYPE_GRAPHITE:
35 + case EXPORTING_CONNECTOR_TYPE_GRAPHITE:
36 if (init_graphite_instance(instance) != 0)
37 return 1;
38 break;
39 - case BACKEND_TYPE_JSON:
39 + case EXPORTING_CONNECTOR_TYPE_JSON:
40 if (init_json_instance(instance) != 0)
41 return 1;
42 break;
43 - case BACKEND_TYPE_OPENTSDB_USING_TELNET:
43 + case EXPORTING_CONNECTOR_TYPE_OPENTSDB_USING_TELNET:
44 if (init_opentsdb_telnet_instance(instance) != 0)
45 return 1;
46 break;
47 - case BACKEND_TYPE_OPENTSDB_USING_HTTP:
47 + case EXPORTING_CONNECTOR_TYPE_OPENTSDB_USING_HTTP:
48 if (init_opentsdb_http_instance(instance) != 0)
49 return 1;
50 break;
51 - case BACKEND_TYPE_PROMETHEUS_REMOTE_WRITE:
51 + case EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE:
52 #if ENABLE_PROMETHEUS_REMOTE_WRITE
53 if (init_prometheus_remote_write_instance(instance) != 0)
54 return 1;
55 #endif
56 break;
57 - case BACKEND_TYPE_KINESIS:
57 + case EXPORTING_CONNECTOR_TYPE_KINESIS:
58 #if HAVE_KINESIS
59 if (init_aws_kinesis_instance(instance) != 0)
60 return 1;
61 #endif
62 break;
63 - case BACKEND_TYPE_MONGODB:
63 + case EXPORTING_CONNECTOR_TYPE_MONGODB:
64 #if HAVE_MONGOC
65 if (init_mongodb_instance(instance) != 0)
66 return 1;
@@ -77,7 +77,7 @@ int init_connectors(struct engine *engine)
77 error("EXPORTING: cannot create tread worker. uv_thread_create(): %s", uv_strerror(error));
78 return 1;
79 }
80 - char threadname[NETDATA_THREAD_NAME_MAX+1];
80 + char threadname[NETDATA_THREAD_NAME_MAX + 1];
81 snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "EXPORTING-%zu", instance->index);
82 uv_thread_set_name_np(instance->thread, threadname);
83 }
exporting/json/json.c
+1 -1
@@ -27,7 +27,7 @@ int init_json_instance(struct instance *instance)
27
28 instance->end_chart_formatting = NULL;
29 instance->end_host_formatting = flush_host_labels;
30 - instance->end_batch_formatting = NULL;
30 + instance->end_batch_formatting = simple_connector_update_buffered_bytes;
31
32 instance->send_header = NULL;
33 instance->check_response = exporting_discard_response;
exporting/mongodb/mongodb.c
+48 -12
@@ -183,8 +183,10 @@ int format_batch_mongodb(struct instance *instance)
183 // ring buffer is full, reuse the oldest element
184 connector_specific_data->first_buffer = connector_specific_data->first_buffer->next;
185 free_bson(insert, connector_specific_data->last_buffer->documents_inserted);
186 + connector_specific_data->total_documents_inserted -= connector_specific_data->last_buffer->documents_inserted;
187 + stats->buffered_bytes -= connector_specific_data->last_buffer->buffered_bytes;
188 }
187 - insert = callocz((size_t)stats->chart_buffered_metrics, sizeof(bson_t *));
189 + insert = callocz((size_t)stats->buffered_metrics, sizeof(bson_t *));
190 connector_specific_data->last_buffer->insert = insert;
191
192 BUFFER *buffer = (BUFFER *)instance->buffer;
@@ -193,7 +195,7 @@ int format_batch_mongodb(struct instance *instance)
195
196 size_t documents_inserted = 0;
197
196 - while (*end && documents_inserted <= (size_t)stats->chart_buffered_metrics) {
198 + while (*end && documents_inserted <= (size_t)stats->buffered_metrics) {
199 while (*end && *end != '\n')
200 end++;
201
@@ -208,7 +210,8 @@ int format_batch_mongodb(struct instance *instance)
210 insert[documents_inserted] = bson_new_from_json((const uint8_t *)start, -1, &bson_error);
211
212 if (unlikely(!insert[documents_inserted])) {
211 - error("EXPORTING: %s", bson_error.message);
213 + error(
214 + "EXPORTING: Failed creating a BSON document from a JSON string \"%s\" : %s", start, bson_error.message);
215 free_bson(insert, documents_inserted);
216 return 1;
217 }
@@ -218,8 +221,16 @@ int format_batch_mongodb(struct instance *instance)
221 documents_inserted++;
222 }
223
224 + stats->buffered_bytes += connector_specific_data->last_buffer->buffered_bytes = buffer_strlen(buffer);
225 +
226 buffer_flush(buffer);
227
228 + // The stats->buffered_metrics is used in the MongoDB batch formatting as a variable for the number
229 + // of metrics, added in the current iteration, so we are clearing it here. We will use the
230 + // connector_specific_data->total_documents_inserted in the worker to show the statistics.
231 + stats->buffered_metrics = 0;
232 + connector_specific_data->total_documents_inserted += documents_inserted;
233 +
234 connector_specific_data->last_buffer->documents_inserted = documents_inserted;
235 connector_specific_data->last_buffer = connector_specific_data->last_buffer->next;
236
@@ -246,11 +257,25 @@ void mongodb_connector_worker(void *instance_p)
257 uv_mutex_lock(&instance->mutex);
258 uv_cond_wait(&instance->cond_var, &instance->mutex);
259
260 + // reset the monitoring chart counters
261 + stats->received_bytes =
262 + stats->sent_bytes =
263 + stats->sent_metrics =
264 + stats->lost_metrics =
265 + stats->receptions =
266 + stats->transmission_successes =
267 + stats->transmission_failures =
268 + stats->data_lost_events =
269 + stats->lost_bytes =
270 + stats->reconnects = 0;
271 +
272 bson_t **insert = connector_specific_data->first_buffer->insert;
273 size_t documents_inserted = connector_specific_data->first_buffer->documents_inserted;
274 + size_t buffered_bytes = connector_specific_data->first_buffer->buffered_bytes;
275
276 connector_specific_data->first_buffer->insert = NULL;
277 connector_specific_data->first_buffer->documents_inserted = 0;
278 + connector_specific_data->first_buffer->buffered_bytes = 0;
279 connector_specific_data->first_buffer = connector_specific_data->first_buffer->next;
280
281 uv_mutex_unlock(&instance->mutex);
@@ -279,9 +304,10 @@ void mongodb_connector_worker(void *instance_p)
304 NULL,
305 NULL,
306 &bson_error))) {
282 - stats->chart_sent_bytes += data_size;
283 - stats->chart_transmission_successes++;
284 - stats->chart_receptions++;
307 + stats->sent_metrics = documents_inserted;
308 + stats->sent_bytes += data_size;
309 + stats->transmission_successes++;
310 + stats->receptions++;
311 } else {
312 // oops! we couldn't send (all or some of the) data
313 error("EXPORTING: %s", bson_error.message);
@@ -290,10 +316,10 @@ void mongodb_connector_worker(void *instance_p)
316 "Willing to write %zu bytes, wrote %zu bytes.",
317 instance->config.destination, data_size, 0UL);
318
293 - stats->chart_transmission_failures++;
294 - stats->chart_data_lost_events++;
295 - stats->chart_lost_bytes += data_size;
296 - stats->chart_lost_metrics += stats->chart_buffered_metrics;
319 + stats->transmission_failures++;
320 + stats->data_lost_events++;
321 + stats->lost_bytes += buffered_bytes;
322 + stats->lost_metrics += documents_inserted;
323 }
324
325 free_bson(insert, documents_inserted);
@@ -301,8 +327,18 @@ void mongodb_connector_worker(void *instance_p)
327 if (unlikely(netdata_exit))
328 break;
329
304 - stats->chart_sent_bytes += data_size;
305 - stats->chart_sent_metrics = stats->chart_buffered_metrics;
330 + uv_mutex_lock(&instance->mutex);
331 +
332 + stats->buffered_metrics = connector_specific_data->total_documents_inserted;
333 +
334 + send_internal_metrics(instance);
335 +
336 + connector_specific_data->total_documents_inserted -= documents_inserted;
337 +
338 + stats->buffered_metrics = 0;
339 + stats->buffered_bytes -= buffered_bytes;
340 +
341 + uv_mutex_unlock(&instance->mutex);
342
343 #ifdef UNIT_TESTING
344 break;
exporting/mongodb/mongodb.h
+3
@@ -10,6 +10,7 @@
10 struct bson_buffer {
11 bson_t **insert;
12 size_t documents_inserted;
13 + size_t buffered_bytes;
14
15 struct bson_buffer *next;
16 };
@@ -18,6 +19,8 @@ struct mongodb_specific_data {
19 mongoc_client_t *client;
20 mongoc_collection_t *collection;
21
22 + size_t total_documents_inserted;
23 +
24 bson_t **current_insert;
25 struct bson_buffer *first_buffer;
26 struct bson_buffer *last_buffer;
exporting/opentsdb/opentsdb.c
+2 -2
@@ -27,7 +27,7 @@ int init_opentsdb_telnet_instance(struct instance *instance)
27
28 instance->end_chart_formatting = NULL;
29 instance->end_host_formatting = flush_host_labels;
30 - instance->end_batch_formatting = NULL;
30 + instance->end_batch_formatting = simple_connector_update_buffered_bytes;
31
32 instance->send_header = NULL;
33 instance->check_response = exporting_discard_response;
@@ -68,7 +68,7 @@ int init_opentsdb_http_instance(struct instance *instance)
68
69 instance->end_chart_formatting = NULL;
70 instance->end_host_formatting = flush_host_labels;
71 - instance->end_batch_formatting = NULL;
71 + instance->end_batch_formatting = simple_connector_update_buffered_bytes;
72
73 instance->send_header = NULL;
74 instance->check_response = exporting_discard_response;
exporting/process_data.c
+15 -2
@@ -206,7 +206,7 @@ int start_host_formatting(struct engine *engine, RRDHOST *host)
206 * Start chart formatting for every connector instance's buffer
207 *
208 * @param engine an engine data structure.
209 - * @param a chart.
209 + * @param st a chart.
210 * @return Returns 0 on success, 1 on failure.
211 */
212 int start_chart_formatting(struct engine *engine, RRDSET *st)
@@ -242,7 +242,7 @@ int metric_formatting(struct engine *engine, RRDDIM *rd)
242 error("EXPORTING: cannot format metric for %s", instance->config.name);
243 return 1;
244 }
245 - instance->stats.chart_buffered_metrics++;
245 + instance->stats.buffered_metrics++;
246 }
247 }
248
@@ -389,6 +389,19 @@ int flush_host_labels(struct instance *instance, RRDHOST *host)
389 return 0;
390 }
391
392 +/**
393 + * Update stats for buffered bytes
394 + *
395 + * @param instance an instance data structure.
396 + * @return Always returns 0.
397 + */
398 +int simple_connector_update_buffered_bytes(struct instance *instance)
399 +{
400 + instance->stats.buffered_bytes = (collected_number)buffer_strlen((BUFFER *)(instance->buffer));
401 +
402 + return 0;
403 +}
404 +
405 /**
406 * Notify workers
407 *
exporting/prometheus/prometheus.c
+217 -73
@@ -7,10 +7,16 @@
7 // PROMETHEUS
8 // /api/v1/allmetrics?format=prometheus and /api/v1/allmetrics?format=prometheus_all_hosts
9
10 +/**
11 + * Check if a chart can be sent to an external databese
12 + *
13 + * @param instance an instance data structure.
14 + * @param st a chart.
15 + * @return Returns 1 if the chart can be sent, 0 otherwise.
16 + */
17 inline int can_send_rrdset(struct instance *instance, RRDSET *st)
18 {
19 RRDHOST *host = st->rrdhost;
13 - (void)host;
20
21 if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_BACKEND_IGNORE)))
22 return 0;
@@ -24,7 +30,7 @@ inline int can_send_rrdset(struct instance *instance, RRDSET *st)
30 rrdset_flag_set(st, RRDSET_FLAG_BACKEND_IGNORE);
31 debug(
32 D_BACKEND,
27 - "BACKEND: not sending chart '%s' of host '%s', because it is disabled for backends.",
33 + "EXPORTING: not sending chart '%s' of host '%s', because it is disabled for exporting.",
34 st->id,
35 host->hostname);
36 return 0;
@@ -34,7 +40,7 @@ inline int can_send_rrdset(struct instance *instance, RRDSET *st)
40 if (unlikely(!rrdset_is_available_for_backends(st))) {
41 debug(
42 D_BACKEND,
37 - "BACKEND: not sending chart '%s' of host '%s', because it is not available for backends.",
43 + "EXPORTING: not sending chart '%s' of host '%s', because it is not available for exporting.",
44 st->id,
45 host->hostname);
46 return 0;
@@ -42,10 +48,10 @@ inline int can_send_rrdset(struct instance *instance, RRDSET *st)
48
49 if (unlikely(
50 st->rrd_memory_mode == RRD_MEMORY_MODE_NONE &&
45 - !(BACKEND_OPTIONS_DATA_SOURCE(instance->config.options) == BACKEND_SOURCE_DATA_AS_COLLECTED))) {
51 + !(EXPORTING_OPTIONS_DATA_SOURCE(instance->config.options) == EXPORTING_SOURCE_DATA_AS_COLLECTED))) {
52 debug(
53 D_BACKEND,
48 - "BACKEND: not sending chart '%s' of host '%s' because its memory mode is '%s' and the backend requires database access.",
54 + "EXPORTING: not sending chart '%s' of host '%s' because its memory mode is '%s' and the exporting connector requires database access.",
55 st->id,
56 host->hostname,
57 rrd_memory_mode_name(host->rrd_memory_mode));
@@ -63,8 +69,19 @@ static struct prometheus_server {
69 struct prometheus_server *next;
70 } *prometheus_server_root = NULL;
71
72 +/**
73 + * Get the last time when a Prometheus server scraped the Netdata Prometheus exporter.
74 + *
75 + * @param server the name of the Prometheus server.
76 + * @param host a data collecting host.
77 + * @param now actual time.
78 + * @return Returns the last time when the server accessed Netdata, or 0 if it is the first occurrence.
79 + */
80 static inline time_t prometheus_server_last_access(const char *server, RRDHOST *host, time_t now)
81 {
82 +#ifdef UNIT_TESTING
83 + return 0;
84 +#endif
85 static netdata_mutex_t prometheus_server_root_mutex = NETDATA_MUTEX_INITIALIZER;
86
87 uint32_t hash = simple_hash(server);
@@ -93,6 +110,14 @@ static inline time_t prometheus_server_last_access(const char *server, RRDHOST *
110 return 0;
111 }
112
113 +/**
114 + * Copy and sanitize name.
115 + *
116 + * @param d a destination string.
117 + * @param s a source sting.
118 + * @param usable the number of characters to copy.
119 + * @return Returns the length of the copied string.
120 + */
121 inline size_t prometheus_name_copy(char *d, const char *s, size_t usable)
122 {
123 size_t n;
@@ -110,6 +135,14 @@ inline size_t prometheus_name_copy(char *d, const char *s, size_t usable)
135 return n;
136 }
137
138 +/**
139 + * Copy and sanitize label.
140 + *
141 + * @param d a destination string.
142 + * @param s a source sting.
143 + * @param usable the number of characters to copy.
144 + * @return Returns the length of the copied string.
145 + */
146 inline size_t prometheus_label_copy(char *d, const char *s, size_t usable)
147 {
148 size_t n;
@@ -131,6 +164,15 @@ inline size_t prometheus_label_copy(char *d, const char *s, size_t usable)
164 return n;
165 }
166
167 +/**
168 + * Copy and sanitize units.
169 + *
170 + * @param d a destination string.
171 + * @param s a source sting.
172 + * @param usable the number of characters to copy.
173 + * @param showoldunits set this flag to 1 to show old (before v1.12) units.
174 + * @return Returns the destination string.
175 + */
176 inline char *prometheus_units_copy(char *d, const char *s, size_t usable, int showoldunits)
177 {
178 const char *sorig = s;
@@ -203,6 +245,43 @@ inline char *prometheus_units_copy(char *d, const char *s, size_t usable, int sh
245 return ret;
246 }
247
248 +/**
249 + * Format host labels for the Prometheus exporter
250 + *
251 + * @param instance an instance data structure.
252 + * @param host a data collecting host.
253 + */
254 +void format_host_labels_prometheus(struct instance *instance, RRDHOST *host)
255 +{
256 + if (unlikely(!sending_labels_configured(instance)))
257 + return;
258 +
259 + if (!instance->labels)
260 + instance->labels = buffer_create(1024);
261 +
262 + int count = 0;
263 + rrdhost_check_rdlock(host);
264 + netdata_rwlock_rdlock(&host->labels_rwlock);
265 + for (struct label *label = host->labels; label; label = label->next) {
266 + if (!should_send_label(instance, label))
267 + continue;
268 +
269 + char key[PROMETHEUS_ELEMENT_MAX + 1];
270 + char value[PROMETHEUS_ELEMENT_MAX + 1];
271 +
272 + prometheus_name_copy(key, label->key, PROMETHEUS_ELEMENT_MAX);
273 + prometheus_label_copy(value, label->value, PROMETHEUS_ELEMENT_MAX);
274 +
275 + if (*key && *value) {
276 + if (count > 0)
277 + buffer_strcat(instance->labels, ",");
278 + buffer_sprintf(instance->labels, "%s=\"%s\"", key, value);
279 + count++;
280 + }
281 + }
282 + netdata_rwlock_unlock(&host->labels_rwlock);
283 +}
284 +
285 struct host_variables_callback_options {
286 RRDHOST *host;
287 BUFFER *wb;
@@ -215,6 +294,13 @@ struct host_variables_callback_options {
294 char name[PROMETHEUS_VARIABLE_MAX + 1];
295 };
296
297 +/**
298 + * Print host variables.
299 + *
300 + * @param rv a variable.
301 + * @param data callback options.
302 + * @return Returns 1 if the chart can be sent, 0 otherwise.
303 + */
304 static int print_host_variables(RRDVAR *rv, void *data)
305 {
306 struct host_variables_callback_options *opts = data;
@@ -274,14 +360,23 @@ static int print_host_variables(RRDVAR *rv, void *data)
360 return 0;
361 }
362
363 +/**
364 + * Write metrics in Prometheus format to a buffer.
365 + *
366 + * @param instance an instance data structure.
367 + * @param host a data collecting host.
368 + * @param wb the buffer to fill with metrics.
369 + * @param prefix a prefix for every metric.
370 + * @param exporting_options options to configure what data is exported.
371 + * @param allhosts set to 1 if host instance should be in the output for tags.
372 + * @param output_options options to configure the format of the output.
373 + */
374 static void rrd_stats_api_v1_charts_allmetrics_prometheus(
375 struct instance *instance,
376 RRDHOST *host,
377 BUFFER *wb,
378 const char *prefix,
379 EXPORTING_OPTIONS exporting_options,
283 - time_t after,
284 - time_t before,
380 int allhosts,
381 PROMETHEUS_OUTPUT_OPTIONS output_options)
382 {
@@ -290,31 +385,33 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
385 char hostname[PROMETHEUS_ELEMENT_MAX + 1];
386 prometheus_label_copy(hostname, host->hostname, PROMETHEUS_ELEMENT_MAX);
387
388 + format_host_labels_prometheus(instance, host);
389 +
390 + if (output_options & PROMETHEUS_OUTPUT_TIMESTAMPS)
391 + buffer_sprintf(
392 + wb,
393 + "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1 %llu\n",
394 + hostname,
395 + host->program_name,
396 + host->program_version,
397 + now_realtime_usec() / USEC_PER_MS);
398 + else
399 + buffer_sprintf(
400 + wb,
401 + "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1\n",
402 + hostname,
403 + host->program_name,
404 + host->program_version);
405 +
406 char labels[PROMETHEUS_LABELS_MAX + 1] = "";
407 if (allhosts) {
295 - if (output_options & PROMETHEUS_OUTPUT_TIMESTAMPS)
296 - buffer_sprintf(
297 - wb,
298 - "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1 %llu\n",
299 - hostname,
300 - host->program_name,
301 - host->program_version,
302 - now_realtime_usec() / USEC_PER_MS);
303 - else
304 - buffer_sprintf(
305 - wb,
306 - "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1\n",
307 - hostname,
308 - host->program_name,
309 - host->program_version);
310 -
311 - if (host->tags && *(host->tags)) {
408 + if (instance->labels && buffer_tostring(instance->labels)) {
409 if (output_options & PROMETHEUS_OUTPUT_TIMESTAMPS) {
410 buffer_sprintf(
411 wb,
412 "netdata_host_tags_info{instance=\"%s\",%s} 1 %llu\n",
413 hostname,
317 - host->tags,
414 + buffer_tostring(instance->labels),
415 now_realtime_usec() / USEC_PER_MS);
416
417 // deprecated, exists only for compatibility with older queries
@@ -322,50 +419,46 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
419 wb,
420 "netdata_host_tags{instance=\"%s\",%s} 1 %llu\n",
421 hostname,
325 - host->tags,
422 + buffer_tostring(instance->labels),
423 now_realtime_usec() / USEC_PER_MS);
424 } else {
328 - buffer_sprintf(wb, "netdata_host_tags_info{instance=\"%s\",%s} 1\n", hostname, host->tags);
425 + buffer_sprintf(
426 + wb, "netdata_host_tags_info{instance=\"%s\",%s} 1\n", hostname, buffer_tostring(instance->labels));
427
428 // deprecated, exists only for compatibility with older queries
331 - buffer_sprintf(wb, "netdata_host_tags{instance=\"%s\",%s} 1\n", hostname, host->tags);
429 + buffer_sprintf(
430 + wb, "netdata_host_tags{instance=\"%s\",%s} 1\n", hostname, buffer_tostring(instance->labels));
431 }
432 }
433
434 snprintfz(labels, PROMETHEUS_LABELS_MAX, ",instance=\"%s\"", hostname);
435 } else {
337 - if (output_options & PROMETHEUS_OUTPUT_TIMESTAMPS)
338 - buffer_sprintf(
339 - wb,
340 - "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1 %llu\n",
341 - hostname,
342 - host->program_name,
343 - host->program_version,
344 - now_realtime_usec() / USEC_PER_MS);
345 - else
346 - buffer_sprintf(
347 - wb,
348 - "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1\n",
349 - hostname,
350 - host->program_name,
351 - host->program_version);
352 -
353 - if (host->tags && *(host->tags)) {
436 + if (instance->labels && buffer_tostring(instance->labels)) {
437 if (output_options & PROMETHEUS_OUTPUT_TIMESTAMPS) {
438 buffer_sprintf(
356 - wb, "netdata_host_tags_info{%s} 1 %llu\n", host->tags, now_realtime_usec() / USEC_PER_MS);
439 + wb,
440 + "netdata_host_tags_info{%s} 1 %llu\n",
441 + buffer_tostring(instance->labels),
442 + now_realtime_usec() / USEC_PER_MS);
443
444 // deprecated, exists only for compatibility with older queries
359 - buffer_sprintf(wb, "netdata_host_tags{%s} 1 %llu\n", host->tags, now_realtime_usec() / USEC_PER_MS);
445 + buffer_sprintf(
446 + wb,
447 + "netdata_host_tags{%s} 1 %llu\n",
448 + buffer_tostring(instance->labels),
449 + now_realtime_usec() / USEC_PER_MS);
450 } else {
361 - buffer_sprintf(wb, "netdata_host_tags_info{%s} 1\n", host->tags);
451 + buffer_sprintf(wb, "netdata_host_tags_info{%s} 1\n", buffer_tostring(instance->labels));
452
453 // deprecated, exists only for compatibility with older queries
364 - buffer_sprintf(wb, "netdata_host_tags{%s} 1\n", host->tags);
454 + buffer_sprintf(wb, "netdata_host_tags{%s} 1\n", buffer_tostring(instance->labels));
455 }
456 }
457 }
458
459 + if (instance->labels)
460 + buffer_flush(instance->labels);
461 +
462 // send custom variables set for the host
463 if (output_options & PROMETHEUS_OUTPUT_VARIABLES) {
464 struct host_variables_callback_options opts = { .host = host,
@@ -383,20 +476,20 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
476 RRDSET *st;
477 rrdset_foreach_read(st, host)
478 {
386 - char chart[PROMETHEUS_ELEMENT_MAX + 1];
387 - char context[PROMETHEUS_ELEMENT_MAX + 1];
388 - char family[PROMETHEUS_ELEMENT_MAX + 1];
389 -
390 - prometheus_label_copy(
391 - chart, (output_options & PROMETHEUS_OUTPUT_NAMES && st->name) ? st->name : st->id, PROMETHEUS_ELEMENT_MAX);
392 - prometheus_label_copy(family, st->family, PROMETHEUS_ELEMENT_MAX);
393 - prometheus_name_copy(context, st->context, PROMETHEUS_ELEMENT_MAX);
479
480 if (likely(can_send_rrdset(instance, st))) {
481 rrdset_rdlock(st);
482
483 + char chart[PROMETHEUS_ELEMENT_MAX + 1];
484 + char context[PROMETHEUS_ELEMENT_MAX + 1];
485 + char family[PROMETHEUS_ELEMENT_MAX + 1];
486 char units[PROMETHEUS_ELEMENT_MAX + 1] = "";
487
488 + prometheus_label_copy(
489 + chart, (output_options & PROMETHEUS_OUTPUT_NAMES && st->name) ? st->name : st->id, PROMETHEUS_ELEMENT_MAX);
490 + prometheus_label_copy(family, st->family, PROMETHEUS_ELEMENT_MAX);
491 + prometheus_name_copy(context, st->context, PROMETHEUS_ELEMENT_MAX);
492 +
493 int as_collected = (EXPORTING_OPTIONS_DATA_SOURCE(exporting_options) == EXPORTING_SOURCE_DATA_AS_COLLECTED);
494 int homogeneous = 1;
495 if (as_collected) {
@@ -433,7 +526,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
526 if (as_collected) {
527 // we need as-collected / raw data
528
436 - if (unlikely(rd->last_collected_time.tv_sec < after))
529 + if (unlikely(rd->last_collected_time.tv_sec < instance->after))
530 continue;
531
532 const char *t = "gauge", *h = "gives";
@@ -562,8 +655,9 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
655 } else {
656 // we need average or sum of the data
657
565 - time_t first_t = after, last_t = before;
566 - calculated_number value = exporting_calculate_value_from_stored_data(instance, rd, &last_t);
658 + time_t first_time = instance->after;
659 + time_t last_time = instance->before;
660 + calculated_number value = exporting_calculate_value_from_stored_data(instance, rd, &last_time);
661
662 if (!isnan(value) && !isinf(value)) {
663 if (EXPORTING_OPTIONS_DATA_SOURCE(exporting_options) == EXPORTING_SOURCE_DATA_AVERAGE)
@@ -586,8 +680,8 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
680 suffix,
681 (output_options & PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id,
682 st->units,
589 - (unsigned long long)first_t,
590 - (unsigned long long)last_t);
683 + (unsigned long long)first_time,
684 + (unsigned long long)last_time);
685
686 if (unlikely(output_options & PROMETHEUS_OUTPUT_TYPES))
687 buffer_sprintf(wb, "# COMMENT TYPE %s_%s%s%s gauge\n", prefix, context, units, suffix);
@@ -606,7 +700,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
700 dimension,
701 labels,
702 value,
609 - last_t * MSEC_PER_SEC);
703 + last_time * MSEC_PER_SEC);
704 else
705 buffer_sprintf(
706 wb,
@@ -633,6 +727,18 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
727 rrdhost_unlock(host);
728 }
729
730 +/**
731 + * Get the last time time when a server accessed Netdata. Write information about an API request to a buffer.
732 + *
733 + * @param instance an instance data structure.
734 + * @param host a data collecting host.
735 + * @param wb the buffer to write to.
736 + * @param exporting_options options to configure what data is exported.
737 + * @param server the name of a Prometheus server..
738 + * @param now actual time.
739 + * @param output_options options to configure the format of the output.
740 + * @return Returns the last time when the server accessed Netdata.
741 + */
742 static inline time_t prometheus_preparation(
743 struct instance *instance,
744 RRDHOST *host,
@@ -649,13 +755,13 @@ static inline time_t prometheus_preparation(
755
756 int first_seen = 0;
757 if (!after) {
652 - after = now - instance->engine->config.update_every;
758 + after = now - instance->config.update_every;
759 first_seen = 1;
760 }
761
762 if (after > now) {
763 // oops! this should never happen
658 - after = now - instance->engine->config.update_every;
764 + after = now - instance->config.update_every;
765 }
766
767 if (output_options & PROMETHEUS_OUTPUT_HELP) {
@@ -685,8 +791,17 @@ static inline time_t prometheus_preparation(
791 return after;
792 }
793
794 +/**
795 + * Write metrics and auxiliary information for one host to a buffer.
796 + *
797 + * @param host a data collecting host.
798 + * @param wb the buffer to write to.
799 + * @param server the name of a Prometheus server.
800 + * @param prefix a prefix for every metric.
801 + * @param exporting_options options to configure what data is exported.
802 + * @param output_options options to configure the format of the output.
803 + */
804 void rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(
689 - struct instance *instance,
805 RRDHOST *host,
806 BUFFER *wb,
807 const char *server,
@@ -694,17 +809,36 @@ void rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(
809 EXPORTING_OPTIONS exporting_options,
810 PROMETHEUS_OUTPUT_OPTIONS output_options)
811 {
697 - time_t before = now_realtime_sec();
812 + if (unlikely(!prometheus_exporter_instance))
813 + return;
814 +
815 + prometheus_exporter_instance->before = now_realtime_sec();
816
817 // we start at the point we had stopped before
700 - time_t after = prometheus_preparation(instance, host, wb, exporting_options, server, before, output_options);
818 + prometheus_exporter_instance->after = prometheus_preparation(
819 + prometheus_exporter_instance,
820 + host,
821 + wb,
822 + exporting_options,
823 + server,
824 + prometheus_exporter_instance->before,
825 + output_options);
826
827 rrd_stats_api_v1_charts_allmetrics_prometheus(
703 - instance, host, wb, prefix, exporting_options, after, before, 0, output_options);
828 + prometheus_exporter_instance, host, wb, prefix, exporting_options, 0, output_options);
829 }
830
831 +/**
832 + * Write metrics and auxiliary information for all hosts to a buffer.
833 + *
834 + * @param host a data collecting host.
835 + * @param wb the buffer to write to.
836 + * @param server the name of a Prometheus server.
837 + * @param prefix a prefix for every metric.
838 + * @param exporting_options options to configure what data is exported.
839 + * @param output_options options to configure the format of the output.
840 + */
841 void rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(
707 - struct instance *instance,
842 RRDHOST *host,
843 BUFFER *wb,
844 const char *server,
@@ -712,16 +846,26 @@ void rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(
846 EXPORTING_OPTIONS exporting_options,
847 PROMETHEUS_OUTPUT_OPTIONS output_options)
848 {
715 - time_t before = now_realtime_sec();
849 + if (unlikely(!prometheus_exporter_instance))
850 + return;
851 +
852 + prometheus_exporter_instance->before = now_realtime_sec();
853
854 // we start at the point we had stopped before
718 - time_t after = prometheus_preparation(instance, host, wb, exporting_options, server, before, output_options);
855 + prometheus_exporter_instance->after = prometheus_preparation(
856 + prometheus_exporter_instance,
857 + host,
858 + wb,
859 + exporting_options,
860 + server,
861 + prometheus_exporter_instance->before,
862 + output_options);
863
864 rrd_rdlock();
865 rrdhost_foreach_read(host)
866 {
867 rrd_stats_api_v1_charts_allmetrics_prometheus(
724 - instance, host, wb, prefix, exporting_options, after, before, 1, output_options);
868 + prometheus_exporter_instance, host, wb, prefix, exporting_options, 1, output_options);
869 }
870 rrd_unlock();
871 }
exporting/prometheus/prometheus.h
+4 -2
@@ -23,10 +23,10 @@ typedef enum prometheus_output_flags {
23 } PROMETHEUS_OUTPUT_OPTIONS;
24
25 extern void rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(
26 - struct instance *instance, RRDHOST *host, BUFFER *wb, const char *server, const char *prefix,
26 + RRDHOST *host, BUFFER *wb, const char *server, const char *prefix,
27 EXPORTING_OPTIONS exporting_options, PROMETHEUS_OUTPUT_OPTIONS output_options);
28 extern void rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(
29 - struct instance *instance, RRDHOST *host, BUFFER *wb, const char *server, const char *prefix,
29 + RRDHOST *host, BUFFER *wb, const char *server, const char *prefix,
30 EXPORTING_OPTIONS exporting_options, PROMETHEUS_OUTPUT_OPTIONS output_options);
31
32 int can_send_rrdset(struct instance *instance, RRDSET *st);
@@ -34,4 +34,6 @@ size_t prometheus_name_copy(char *d, const char *s, size_t usable);
34 size_t prometheus_label_copy(char *d, const char *s, size_t usable);
35 char *prometheus_units_copy(char *d, const char *s, size_t usable, int showoldunits);
36
37 +void format_host_labels_prometheus(struct instance *instance, RRDHOST *host);
38 +
39 #endif //NETDATA_EXPORTING_PROMETHEUS_H
exporting/prometheus/remote_write/remote_write.c
+1 -1
@@ -314,7 +314,7 @@ int format_batch_prometheus_remote_write(struct instance *instance)
314 return 1;
315 }
316 buffer->len = data_size;
317 - instance->stats.chart_buffered_bytes = (collected_number)buffer_strlen(buffer);
317 + instance->stats.buffered_bytes = (collected_number)buffer_strlen(buffer);
318
319 return 0;
320 }
exporting/read_config.c
+99 -84
@@ -2,18 +2,19 @@
2
3 #include "exporting_engine.h"
4
5 -struct config exporting_config = {.first_section = NULL,
6 - .last_section = NULL,
7 - .mutex = NETDATA_MUTEX_INITIALIZER,
8 - .index = {.avl_tree = {.root = NULL, .compar = appconfig_section_compare},
9 - .rwlock = AVL_LOCK_INITIALIZER}};
5 +struct config exporting_config = { .first_section = NULL,
6 + .last_section = NULL,
7 + .mutex = NETDATA_MUTEX_INITIALIZER,
8 + .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
9 + .rwlock = AVL_LOCK_INITIALIZER } };
10
11 +struct instance *prometheus_exporter_instance = NULL;
12
13 static _CONNECTOR_INSTANCE *find_instance(const char *section)
14 {
15 _CONNECTOR_INSTANCE *local_ci;
16
16 - local_ci = add_connector_instance(NULL, NULL); // Get root section
17 + local_ci = add_connector_instance(NULL, NULL); // Get root section
18 if (unlikely(!local_ci))
19 return local_ci;
20
@@ -38,12 +39,10 @@ char *expconfig_get(struct config *root, const char *section, const char *name,
39 local_ci = find_instance(section);
40
41 if (!local_ci)
41 - return NULL; // TODO: Check if it is meaningful to return default_value
42 + return NULL; // TODO: Check if it is meaningful to return default_value
43
44 return appconfig_get(
44 - root,
45 - local_ci->instance_name,
46 - name,
45 + root, local_ci->instance_name, name,
46 appconfig_get(
47 root, local_ci->connector_name, name, appconfig_get(root, CONFIG_SECTION_EXPORTING, name, default_value)));
48 }
@@ -58,16 +57,12 @@ int expconfig_get_boolean(struct config *root, const char *section, const char *
57 local_ci = find_instance(section);
58
59 if (!local_ci)
61 - return 0; // TODO: Check if it is meaningful to return default_value
60 + return 0; // TODO: Check if it is meaningful to return default_value
61
62 return appconfig_get_boolean(
64 - root,
65 - local_ci->instance_name,
66 - name,
63 + root, local_ci->instance_name, name,
64 appconfig_get_boolean(
68 - root,
69 - local_ci->connector_name,
70 - name,
65 + root, local_ci->connector_name, name,
66 appconfig_get_boolean(root, CONFIG_SECTION_EXPORTING, name, default_value)));
67 }
68
@@ -81,16 +76,12 @@ long long expconfig_get_number(struct config *root, const char *section, const c
76 local_ci = find_instance(section);
77
78 if (!local_ci)
84 - return 0; // TODO: Check if it is meaningful to return default_value
79 + return 0; // TODO: Check if it is meaningful to return default_value
80
81 return appconfig_get_number(
87 - root,
88 - local_ci->instance_name,
89 - name,
82 + root, local_ci->instance_name, name,
83 appconfig_get_number(
91 - root,
92 - local_ci->connector_name,
93 - name,
84 + root, local_ci->connector_name, name,
85 appconfig_get_number(root, CONFIG_SECTION_EXPORTING, name, default_value)));
86 }
87
@@ -108,7 +99,7 @@ int get_connector_instance(struct connector_instance *target_ci)
99 static _CONNECTOR_INSTANCE *local_ci = NULL;
100 _CONNECTOR_INSTANCE *global_connector_instance;
101
111 - global_connector_instance = find_instance(NULL); // Fetch head of instances
102 + global_connector_instance = find_instance(NULL); // Fetch head of instances
103
104 if (unlikely(!global_connector_instance))
105 return 0;
@@ -140,40 +131,39 @@ int get_connector_instance(struct connector_instance *target_ci)
131 *
132 * @return It returns the connector id.
133 */
143 -BACKEND_TYPE exporting_select_type(const char *type)
134 +EXPORTING_CONNECTOR_TYPE exporting_select_type(const char *type)
135 {
136 if (!strcmp(type, "graphite") || !strcmp(type, "graphite:plaintext")) {
146 - return BACKEND_TYPE_GRAPHITE;
137 + return EXPORTING_CONNECTOR_TYPE_GRAPHITE;
138 } else if (!strcmp(type, "opentsdb") || !strcmp(type, "opentsdb:telnet")) {
148 - return BACKEND_TYPE_OPENTSDB_USING_TELNET;
139 + return EXPORTING_CONNECTOR_TYPE_OPENTSDB_USING_TELNET;
140 } else if (!strcmp(type, "opentsdb:http") || !strcmp(type, "opentsdb:https")) {
150 - return BACKEND_TYPE_OPENTSDB_USING_HTTP;
141 + return EXPORTING_CONNECTOR_TYPE_OPENTSDB_USING_HTTP;
142 } else if (!strcmp(type, "json") || !strcmp(type, "json:plaintext")) {
152 - return BACKEND_TYPE_JSON;
143 + return EXPORTING_CONNECTOR_TYPE_JSON;
144 } else if (!strcmp(type, "prometheus_remote_write")) {
154 - return BACKEND_TYPE_PROMETHEUS_REMOTE_WRITE;
145 + return EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE;
146 } else if (!strcmp(type, "kinesis") || !strcmp(type, "kinesis:plaintext")) {
156 - return BACKEND_TYPE_KINESIS;
147 + return EXPORTING_CONNECTOR_TYPE_KINESIS;
148 } else if (!strcmp(type, "mongodb") || !strcmp(type, "mongodb:plaintext"))
158 - return BACKEND_TYPE_MONGODB;
149 + return EXPORTING_CONNECTOR_TYPE_MONGODB;
150
160 - return BACKEND_TYPE_UNKNOWN;
151 + return EXPORTING_CONNECTOR_TYPE_UNKNOWN;
152 }
153
163 -EXPORTING_OPTIONS exporting_parse_data_source(const char *data_source, EXPORTING_OPTIONS exporting_options) {
164 - if(!strcmp(data_source, "raw") || !strcmp(data_source, "as collected") || !strcmp(data_source, "as-collected") || !strcmp(data_source, "as_collected") || !strcmp(data_source, "ascollected")) {
154 +EXPORTING_OPTIONS exporting_parse_data_source(const char *data_source, EXPORTING_OPTIONS exporting_options)
155 +{
156 + if (!strcmp(data_source, "raw") || !strcmp(data_source, "as collected") || !strcmp(data_source, "as-collected") ||
157 + !strcmp(data_source, "as_collected") || !strcmp(data_source, "ascollected")) {
158 exporting_options |= EXPORTING_SOURCE_DATA_AS_COLLECTED;
159 exporting_options &= ~(EXPORTING_OPTIONS_SOURCE_BITS ^ EXPORTING_SOURCE_DATA_AS_COLLECTED);
167 - }
168 - else if(!strcmp(data_source, "average")) {
160 + } else if (!strcmp(data_source, "average")) {
161 exporting_options |= EXPORTING_SOURCE_DATA_AVERAGE;
162 exporting_options &= ~(EXPORTING_OPTIONS_SOURCE_BITS ^ EXPORTING_SOURCE_DATA_AVERAGE);
171 - }
172 - else if(!strcmp(data_source, "sum") || !strcmp(data_source, "volume")) {
163 + } else if (!strcmp(data_source, "sum") || !strcmp(data_source, "volume")) {
164 exporting_options |= EXPORTING_SOURCE_DATA_SUM;
165 exporting_options &= ~(EXPORTING_OPTIONS_SOURCE_BITS ^ EXPORTING_SOURCE_DATA_SUM);
175 - }
176 - else {
166 + } else {
167 error("EXPORTING: invalid data data_source method '%s'.", data_source);
168 }
169
@@ -195,7 +185,7 @@ struct engine *read_exporting_config()
185 static struct engine *engine = NULL;
186 struct connector_instance_list {
187 struct connector_instance local_ci;
198 - BACKEND_TYPE backend_type;
188 + EXPORTING_CONNECTOR_TYPE backend_type;
189
190 struct connector_instance_list *next;
191 };
@@ -220,6 +210,46 @@ struct engine *read_exporting_config()
210
211 freez(filename);
212
213 +#define prometheus_config_get(name, value) \
214 + appconfig_get( \
215 + &exporting_config, CONFIG_SECTION_PROMETHEUS, name, \
216 + appconfig_get(&exporting_config, CONFIG_SECTION_EXPORTING, name, value))
217 +#define prometheus_config_get_number(name, value) \
218 + appconfig_get_number( \
219 + &exporting_config, CONFIG_SECTION_PROMETHEUS, name, \
220 + appconfig_get_number(&exporting_config, CONFIG_SECTION_EXPORTING, name, value))
221 +#define prometheus_config_get_boolean(name, value) \
222 + appconfig_get_boolean( \
223 + &exporting_config, CONFIG_SECTION_PROMETHEUS, name, \
224 + appconfig_get_boolean(&exporting_config, CONFIG_SECTION_EXPORTING, name, value))
225 +
226 + if (!prometheus_exporter_instance) {
227 + prometheus_exporter_instance = callocz(1, sizeof(struct instance));
228 +
229 + prometheus_exporter_instance->config.update_every =
230 + prometheus_config_get_number(EXPORTING_UPDATE_EVERY_OPTION_NAME, EXPORTING_UPDATE_EVERY_DEFAULT);
231 +
232 + if (prometheus_config_get_boolean("send names instead of ids", CONFIG_BOOLEAN_YES))
233 + prometheus_exporter_instance->config.options |= EXPORTING_OPTION_SEND_NAMES;
234 + else
235 + prometheus_exporter_instance->config.options &= ~EXPORTING_OPTION_SEND_NAMES;
236 +
237 + if (prometheus_config_get_boolean("send configured labels", CONFIG_BOOLEAN_YES))
238 + prometheus_exporter_instance->config.options |= EXPORTING_OPTION_SEND_CONFIGURED_LABELS;
239 + else
240 + prometheus_exporter_instance->config.options &= ~EXPORTING_OPTION_SEND_CONFIGURED_LABELS;
241 +
242 + if (prometheus_config_get_boolean("send automatic labels", CONFIG_BOOLEAN_NO))
243 + prometheus_exporter_instance->config.options |= EXPORTING_OPTION_SEND_AUTOMATIC_LABELS;
244 + else
245 + prometheus_exporter_instance->config.options &= ~EXPORTING_OPTION_SEND_AUTOMATIC_LABELS;
246 +
247 + prometheus_exporter_instance->config.charts_pattern =
248 + simple_pattern_create(prometheus_config_get("send charts matching", "*"), NULL, SIMPLE_PATTERN_EXACT);
249 + prometheus_exporter_instance->config.hosts_pattern = simple_pattern_create(
250 + prometheus_config_get("send hosts matching", "localhost *"), NULL, SIMPLE_PATTERN_EXACT);
251 + }
252 +
253 // TODO: change BACKEND to EXPORTING
254 while (get_connector_instance(&local_ci)) {
255 info("Processing connector instance (%s)", local_ci.instance_name);
@@ -227,8 +257,7 @@ struct engine *read_exporting_config()
257 if (exporter_get_boolean(local_ci.instance_name, "enabled", 0)) {
258 info(
259 "Instance (%s) on connector (%s) is enabled and scheduled for activation",
230 - local_ci.instance_name,
231 - local_ci.connector_name);
260 + local_ci.instance_name, local_ci.connector_name);
261
262 tmp_ci_list = (struct connector_instance_list *)callocz(1, sizeof(struct connector_instance_list));
263 memcpy(&tmp_ci_list->local_ci, &local_ci, sizeof(local_ci));
@@ -252,8 +281,8 @@ struct engine *read_exporting_config()
281 engine->config.hostname =
282 strdupz(exporter_get(CONFIG_SECTION_EXPORTING, "hostname", netdata_configured_hostname));
283 engine->config.prefix = strdupz(exporter_get(CONFIG_SECTION_EXPORTING, "prefix", "netdata"));
255 - engine->config.update_every =
256 - exporter_get_number(CONFIG_SECTION_EXPORTING, EXPORTING_UPDATE_EVERY_OPTION_NAME, EXPORTING_UPDATE_EVERY_DEFAULT);
284 + engine->config.update_every = exporter_get_number(
285 + CONFIG_SECTION_EXPORTING, EXPORTING_UPDATE_EVERY_OPTION_NAME, EXPORTING_UPDATE_EVERY_DEFAULT);
286 }
287
288 while (tmp_ci_list) {
@@ -262,27 +291,27 @@ struct engine *read_exporting_config()
291
292 info("Instance %s on %s", tmp_ci_list->local_ci.instance_name, tmp_ci_list->local_ci.connector_name);
293
265 - if (tmp_ci_list->backend_type == BACKEND_TYPE_UNKNOWN) {
294 + if (tmp_ci_list->backend_type == EXPORTING_CONNECTOR_TYPE_UNKNOWN) {
295 error("Unknown exporting connector type");
296 goto next_connector_instance;
297 }
298
299 #ifndef ENABLE_PROMETHEUS_REMOTE_WRITE
271 - if (tmp_ci_list->backend_type == BACKEND_TYPE_PROMETHEUS_REMOTE_WRITE) {
300 + if (tmp_ci_list->backend_type == EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE) {
301 error("Prometheus Remote Write support isn't compiled");
302 goto next_connector_instance;
303 }
304 #endif
305
306 #ifndef HAVE_KINESIS
278 - if (tmp_ci_list->backend_type == BACKEND_TYPE_KINESIS) {
307 + if (tmp_ci_list->backend_type == EXPORTING_CONNECTOR_TYPE_KINESIS) {
308 error("AWS Kinesis support isn't compiled");
309 goto next_connector_instance;
310 }
311 #endif
312
313 #ifndef HAVE_MONGOC
285 - if (tmp_ci_list->backend_type == BACKEND_TYPE_MONGODB) {
314 + if (tmp_ci_list->backend_type == EXPORTING_CONNECTOR_TYPE_MONGODB) {
315 error("MongoDB support isn't compiled");
316 goto next_connector_instance;
317 }
@@ -299,41 +328,31 @@ struct engine *read_exporting_config()
328
329 tmp_instance->config.name = strdupz(tmp_ci_list->local_ci.instance_name);
330
302 - tmp_instance->config.destination =
303 - strdupz(exporter_get(instance_name, "destination", "localhost"));
331 + tmp_instance->config.destination = strdupz(exporter_get(instance_name, "destination", "localhost"));
332
333 tmp_instance->config.update_every =
334 exporter_get_number(instance_name, EXPORTING_UPDATE_EVERY_OPTION_NAME, EXPORTING_UPDATE_EVERY_DEFAULT);
335
308 - tmp_instance->config.buffer_on_failures =
309 - exporter_get_number(instance_name, "buffer on failures", 10);
336 + tmp_instance->config.buffer_on_failures = exporter_get_number(instance_name, "buffer on failures", 10);
337
311 - tmp_instance->config.timeoutms =
312 - exporter_get_number(instance_name, "timeout ms", 10000);
338 + tmp_instance->config.timeoutms = exporter_get_number(instance_name, "timeout ms", 10000);
339
314 - tmp_instance->config.charts_pattern = simple_pattern_create(
315 - exporter_get(instance_name, "send charts matching", "*"),
316 - NULL,
317 - SIMPLE_PATTERN_EXACT);
340 + tmp_instance->config.charts_pattern =
341 + simple_pattern_create(exporter_get(instance_name, "send charts matching", "*"), NULL, SIMPLE_PATTERN_EXACT);
342
343 tmp_instance->config.hosts_pattern = simple_pattern_create(
320 - exporter_get(instance_name, "send hosts matching", "localhost *"),
321 - NULL,
322 - SIMPLE_PATTERN_EXACT);
344 + exporter_get(instance_name, "send hosts matching", "localhost *"), NULL, SIMPLE_PATTERN_EXACT);
345
324 - char *data_source =
325 - exporter_get(instance_name, "data source", "average");
346 + char *data_source = exporter_get(instance_name, "data source", "average");
347
348 tmp_instance->config.options = exporting_parse_data_source(data_source, tmp_instance->config.options);
349
329 - if (exporter_get_boolean(
330 - instance_name, "send configured labels", CONFIG_BOOLEAN_YES))
350 + if (exporter_get_boolean(instance_name, "send configured labels", CONFIG_BOOLEAN_YES))
351 tmp_instance->config.options |= EXPORTING_OPTION_SEND_CONFIGURED_LABELS;
352 else
353 tmp_instance->config.options &= ~EXPORTING_OPTION_SEND_CONFIGURED_LABELS;
354
335 - if (exporter_get_boolean(
336 - instance_name, "send automatic labels", CONFIG_BOOLEAN_NO))
355 + if (exporter_get_boolean(instance_name, "send automatic labels", CONFIG_BOOLEAN_NO))
356 tmp_instance->config.options |= EXPORTING_OPTION_SEND_AUTOMATIC_LABELS;
357 else
358 tmp_instance->config.options &= ~EXPORTING_OPTION_SEND_AUTOMATIC_LABELS;
@@ -343,33 +362,30 @@ struct engine *read_exporting_config()
362 else
363 tmp_instance->config.options &= ~EXPORTING_OPTION_SEND_NAMES;
364
346 - if (tmp_instance->config.type == BACKEND_TYPE_PROMETHEUS_REMOTE_WRITE) {
365 + if (tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE) {
366 struct prometheus_remote_write_specific_config *connector_specific_config =
367 callocz(1, sizeof(struct prometheus_remote_write_specific_config));
368
369 tmp_instance->config.connector_specific_config = connector_specific_config;
370
352 - connector_specific_config->remote_write_path = strdupz(exporter_get(
353 - instance_name, "remote write URL path", "/receive"));
371 + connector_specific_config->remote_write_path =
372 + strdupz(exporter_get(instance_name, "remote write URL path", "/receive"));
373 }
374
356 - if (tmp_instance->config.type == BACKEND_TYPE_KINESIS) {
375 + if (tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_KINESIS) {
376 struct aws_kinesis_specific_config *connector_specific_config =
377 callocz(1, sizeof(struct aws_kinesis_specific_config));
378
379 tmp_instance->config.connector_specific_config = connector_specific_config;
380
362 - connector_specific_config->stream_name = strdupz(exporter_get(
363 - instance_name, "stream name", "netdata"));
381 + connector_specific_config->stream_name = strdupz(exporter_get(instance_name, "stream name", "netdata"));
382
365 - connector_specific_config->auth_key_id = strdupz(exporter_get(
366 - instance_name, "aws_access_key_id", ""));
383 + connector_specific_config->auth_key_id = strdupz(exporter_get(instance_name, "aws_access_key_id", ""));
384
368 - connector_specific_config->secure_key = strdupz(exporter_get(
369 - instance_name, "aws_secret_access_key", ""));
385 + connector_specific_config->secure_key = strdupz(exporter_get(instance_name, "aws_secret_access_key", ""));
386 }
387
372 - if (tmp_instance->config.type == BACKEND_TYPE_MONGODB) {
388 + if (tmp_instance->config.type == EXPORTING_CONNECTOR_TYPE_MONGODB) {
389 struct mongodb_specific_config *connector_specific_config =
390 callocz(1, sizeof(struct mongodb_specific_config));
391
@@ -393,14 +409,13 @@ struct engine *read_exporting_config()
409 #endif
410
411 if (unlikely(!exporting_config_exists) && !engine->config.hostname) {
396 - engine->config.hostname =
397 - strdupz(config_get(instance_name, "hostname", netdata_configured_hostname));
412 + engine->config.hostname = strdupz(config_get(instance_name, "hostname", netdata_configured_hostname));
413 engine->config.prefix = strdupz(config_get(instance_name, "prefix", "netdata"));
414 engine->config.update_every =
415 config_get_number(instance_name, EXPORTING_UPDATE_EVERY_OPTION_NAME, EXPORTING_UPDATE_EVERY_DEFAULT);
416 }
417
403 -next_connector_instance:
418 + next_connector_instance:
419 tmp_ci_list1 = tmp_ci_list->next;
420 freez(tmp_ci_list);
421 tmp_ci_list = tmp_ci_list1;
exporting/send_data.c
+41 -9
@@ -57,8 +57,8 @@ void simple_connector_receive_response(int *sock, struct instance *instance)
57 if (likely(r > 0)) {
58 // we received some data
59 response->len += r;
60 - stats->chart_received_bytes += r;
61 - stats->chart_receptions++;
60 + stats->received_bytes += r;
61 + stats->receptions++;
62 } else if (r == 0) {
63 error("EXPORTING: '%s' closed the socket", instance->config.destination);
64 close(*sock);
@@ -109,9 +109,9 @@ void simple_connector_send_buffer(int *sock, int *failures, struct instance *ins
109
110 if(written != -1 && (size_t)written == len) {
111 // we sent the data successfully
112 - stats->chart_transmission_successes++;
113 - stats->chart_sent_bytes += written;
114 - stats->chart_sent_metrics = stats->chart_buffered_metrics;
112 + stats->transmission_successes++;
113 + stats->sent_bytes += written;
114 + stats->sent_metrics = stats->buffered_metrics;
115
116 // reset the failures count
117 *failures = 0;
@@ -126,10 +126,10 @@ void simple_connector_send_buffer(int *sock, int *failures, struct instance *ins
126 instance->config.destination,
127 len,
128 written);
129 - stats->chart_transmission_failures++;
129 + stats->transmission_failures++;
130
131 if(written != -1)
132 - stats->chart_sent_bytes += written;
132 + stats->sent_bytes += written;
133
134 // increment the counter we check for data loss
135 (*failures)++;
@@ -160,6 +160,19 @@ void simple_connector_worker(void *instance_p)
160 int failures = 0;
161
162 while(!netdata_exit) {
163 +
164 + // reset the monitoring chart counters
165 + stats->received_bytes =
166 + stats->sent_bytes =
167 + stats->sent_metrics =
168 + stats->lost_metrics =
169 + stats->receptions =
170 + stats->transmission_successes =
171 + stats->transmission_failures =
172 + stats->data_lost_events =
173 + stats->lost_bytes =
174 + stats->reconnects = 0;
175 +
176 // ------------------------------------------------------------------------
177 // if we are connected, receive a response, without blocking
178
@@ -179,7 +192,7 @@ void simple_connector_worker(void *instance_p)
192 &reconnects,
193 NULL,
194 0);
182 - stats->chart_reconnects += reconnects;
195 + stats->reconnects += reconnects;
196 }
197
198 if(unlikely(netdata_exit)) break;
@@ -194,12 +207,31 @@ void simple_connector_worker(void *instance_p)
207 simple_connector_send_buffer(&sock, &failures, instance);
208 } else {
209 error("EXPORTING: failed to update '%s'", instance->config.destination);
197 - stats->chart_transmission_failures++;
210 + stats->transmission_failures++;
211
212 // increment the counter we check for data loss
213 failures++;
214 }
215
216 + BUFFER *buffer = instance->buffer;
217 +
218 + if (failures > instance->config.buffer_on_failures) {
219 + stats->lost_bytes += buffer_strlen(buffer);
220 + error(
221 + "EXPORTING: connector instance %s reached %d exporting failures. "
222 + "Flushing buffers to protect this host - this results in data loss on server '%s'",
223 + instance->config.name, failures, instance->config.destination);
224 + buffer_flush(buffer);
225 + failures = 0;
226 + stats->data_lost_events++;
227 + stats->lost_metrics = stats->buffered_metrics;
228 + }
229 +
230 + send_internal_metrics(instance);
231 +
232 + if(likely(buffer_strlen(buffer) == 0))
233 + stats->buffered_metrics = 0;
234 +
235 uv_mutex_unlock(&instance->mutex);
236
237 #ifdef UNIT_TESTING
exporting/send_internal_metrics.c
+160 -6
@@ -3,16 +3,170 @@
3 #include "exporting_engine.h"
4
5 /**
6 - * Send internal metrics
6 + * Create a chart for the main exporting thread CPU usage
7 + *
8 + * @param st_rusage the thead CPU usage chart
9 + * @param rd_user a dimension for user CPU usage
10 + * @param rd_system a dimension for system CPU usage
11 + */
12 +void create_main_rusage_chart(RRDSET **st_rusage, RRDDIM **rd_user, RRDDIM **rd_system)
13 +{
14 + if (*st_rusage && *rd_user && *rd_system)
15 + return;
16 +
17 + *st_rusage = rrdset_create_localhost(
18 + "netdata", "exporting_main_thread_cpu", NULL, "exporting", NULL, "Netdata Main Exporting Thread CPU Usage",
19 + "milliseconds/s", "exporting", NULL, 130600, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
20 +
21 + *rd_user = rrddim_add(*st_rusage, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
22 + *rd_system = rrddim_add(*st_rusage, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
23 +}
24 +
25 +/**
26 + * Send the main exporting thread CPU usage
27 + *
28 + * @param st_rusage a thead CPU usage chart
29 + * @param rd_user a dimension for user CPU usage
30 + * @param rd_system a dimension for system CPU usage
31 + */
32 +void send_main_rusage(RRDSET *st_rusage, RRDDIM *rd_user, RRDDIM *rd_system)
33 +{
34 + struct rusage thread;
35 + getrusage(RUSAGE_THREAD, &thread);
36 +
37 + if (likely(st_rusage->counter_done))
38 + rrdset_next(st_rusage);
39 +
40 + rrddim_set_by_pointer(st_rusage, rd_user, thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
41 + rrddim_set_by_pointer(st_rusage, rd_system, thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
42 +
43 + rrdset_done(st_rusage);
44 +}
45 +
46 +/**
47 + * Send internal metrics for an instance
48 *
49 * Send performance metrics for the operation of exporting engine itself to the Netdata database.
50 *
10 - * @param engine an engine data structure.
11 - * @return Returns 0 on success, 1 on failure.
51 + * @param instance an instance data structure.
52 */
13 -int send_internal_metrics(struct engine *engine)
53 +void send_internal_metrics(struct instance *instance)
54 {
15 - (void)engine;
55 + struct stats *stats = &instance->stats;
56 +
57 + // ------------------------------------------------------------------------
58 + // create charts for monitoring the exporting operations
59 +
60 + if (!stats->initialized) {
61 + char id[RRD_ID_LENGTH_MAX + 1];
62 + BUFFER *family = buffer_create(0);
63 +
64 + buffer_sprintf(family, "exporting_%s", instance->config.name);
65 +
66 + snprintf(id, RRD_ID_LENGTH_MAX, "exporting_%s_metrics", instance->config.name);
67 + netdata_fix_chart_id(id);
68 +
69 + stats->st_metrics = rrdset_create_localhost(
70 + "netdata", id, NULL, buffer_tostring(family), NULL, "Netdata Buffered Metrics", "metrics", "exporting", NULL,
71 + 130610, instance->config.update_every, RRDSET_TYPE_LINE);
72 +
73 + stats->rd_buffered_metrics = rrddim_add(stats->st_metrics, "buffered", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
74 + stats->rd_lost_metrics = rrddim_add(stats->st_metrics, "lost", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
75 + stats->rd_sent_metrics = rrddim_add(stats->st_metrics, "sent", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
76 +
77 + // ------------------------------------------------------------------------
78 +
79 + snprintf(id, RRD_ID_LENGTH_MAX, "exporting_%s_bytes", instance->config.name);
80 + netdata_fix_chart_id(id);
81 +
82 + stats->st_bytes = rrdset_create_localhost(
83 + "netdata", id, NULL, buffer_tostring(family), NULL, "Netdata Exporting Data Size", "KiB", "exporting", NULL,
84 + 130620, instance->config.update_every, RRDSET_TYPE_AREA);
85 +
86 + stats->rd_buffered_bytes = rrddim_add(stats->st_bytes, "buffered", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
87 + stats->rd_lost_bytes = rrddim_add(stats->st_bytes, "lost", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
88 + stats->rd_sent_bytes = rrddim_add(stats->st_bytes, "sent", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
89 + stats->rd_received_bytes = rrddim_add(stats->st_bytes, "received", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
90 +
91 + // ------------------------------------------------------------------------
92 +
93 + snprintf(id, RRD_ID_LENGTH_MAX, "exporting_%s_ops", instance->config.name);
94 + netdata_fix_chart_id(id);
95 +
96 + stats->st_ops = rrdset_create_localhost(
97 + "netdata", id, NULL, buffer_tostring(family), NULL, "Netdata Exporting Operations", "operations", "exporting",
98 + NULL, 130630, instance->config.update_every, RRDSET_TYPE_LINE);
99 +
100 + stats->rd_transmission_successes = rrddim_add(stats->st_ops, "write", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
101 + stats->rd_data_lost_events = rrddim_add(stats->st_ops, "discard", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
102 + stats->rd_reconnects = rrddim_add(stats->st_ops, "reconnect", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
103 + stats->rd_transmission_failures = rrddim_add(stats->st_ops, "failure", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
104 + stats->rd_receptions = rrddim_add(stats->st_ops, "read", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
105 +
106 + // ------------------------------------------------------------------------
107 +
108 + snprintf(id, RRD_ID_LENGTH_MAX, "exporting_%s_thread_cpu", instance->config.name);
109 + netdata_fix_chart_id(id);
110 +
111 + stats->st_rusage = rrdset_create_localhost(
112 + "netdata", id, NULL, buffer_tostring(family), NULL, "Netdata Exporting Instance Thread CPU Usage",
113 + "milliseconds/s", "exporting", NULL, 130640, instance->config.update_every, RRDSET_TYPE_STACKED);
114 +
115 + stats->rd_user = rrddim_add(stats->st_rusage, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
116 + stats->rd_system = rrddim_add(stats->st_rusage, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
117 +
118 + buffer_free(family);
119 +
120 + stats->initialized = 1;
121 + }
122 +
123 + // ------------------------------------------------------------------------
124 + // update the monitoring charts
125 +
126 + if (likely(stats->st_metrics->counter_done))
127 + rrdset_next(stats->st_metrics);
128 +
129 + rrddim_set_by_pointer(stats->st_metrics, stats->rd_buffered_metrics, stats->buffered_metrics);
130 + rrddim_set_by_pointer(stats->st_metrics, stats->rd_lost_metrics, stats->lost_metrics);
131 + rrddim_set_by_pointer(stats->st_metrics, stats->rd_sent_metrics, stats->sent_metrics);
132 +
133 + rrdset_done(stats->st_metrics);
134 +
135 + // ------------------------------------------------------------------------
136 +
137 + if (likely(stats->st_bytes->counter_done))
138 + rrdset_next(stats->st_bytes);
139 +
140 + rrddim_set_by_pointer(stats->st_bytes, stats->rd_buffered_bytes, stats->buffered_bytes);
141 + rrddim_set_by_pointer(stats->st_bytes, stats->rd_lost_bytes, stats->lost_bytes);
142 + rrddim_set_by_pointer(stats->st_bytes, stats->rd_sent_bytes, stats->sent_bytes);
143 + rrddim_set_by_pointer(stats->st_bytes, stats->rd_received_bytes, stats->received_bytes);
144 +
145 + rrdset_done(stats->st_bytes);
146 +
147 + // ------------------------------------------------------------------------
148 +
149 + if (likely(stats->st_ops->counter_done))
150 + rrdset_next(stats->st_ops);
151 +
152 + rrddim_set_by_pointer(stats->st_ops, stats->rd_transmission_successes, stats->transmission_successes);
153 + rrddim_set_by_pointer(stats->st_ops, stats->rd_data_lost_events, stats->data_lost_events);
154 + rrddim_set_by_pointer(stats->st_ops, stats->rd_reconnects, stats->reconnects);
155 + rrddim_set_by_pointer(stats->st_ops, stats->rd_transmission_failures, stats->transmission_failures);
156 + rrddim_set_by_pointer(stats->st_ops, stats->rd_receptions, stats->receptions);
157 +
158 + rrdset_done(stats->st_ops);
159 +
160 + // ------------------------------------------------------------------------
161 +
162 + struct rusage thread;
163 + getrusage(RUSAGE_THREAD, &thread);
164 +
165 + if (likely(stats->st_rusage->counter_done))
166 + rrdset_next(stats->st_rusage);
167 +
168 + rrddim_set_by_pointer(stats->st_rusage, stats->rd_user, thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
169 + rrddim_set_by_pointer(stats->st_rusage, stats->rd_system, thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
170
17 - return 0;
171 + rrdset_done(stats->st_rusage);
172 }
exporting/tests/exporting_doubles.c
+19 -3
@@ -20,7 +20,7 @@ struct engine *__mock_read_exporting_config()
20 engine->instance_root = calloc(1, sizeof(struct instance));
21 struct instance *instance = engine->instance_root;
22 instance->engine = engine;
23 - instance->config.type = BACKEND_TYPE_GRAPHITE;
23 + instance->config.type = EXPORTING_CONNECTOR_TYPE_GRAPHITE;
24 instance->config.name = strdupz("instance_name");
25 instance->config.destination = strdupz("localhost");
26 instance->config.update_every = 1;
@@ -82,10 +82,26 @@ int __wrap_notify_workers(struct engine *engine)
82 return mock_type(int);
83 }
84
85 -int __wrap_send_internal_metrics(struct engine *engine)
85 +void __wrap_create_main_rusage_chart(RRDSET **st_rusage, RRDDIM **rd_user, RRDDIM **rd_system)
86 {
87 function_called();
88 - check_expected_ptr(engine);
88 + check_expected_ptr(st_rusage);
89 + check_expected_ptr(rd_user);
90 + check_expected_ptr(rd_system);
91 +}
92 +
93 +void __wrap_send_main_rusage(RRDSET *st_rusage, RRDDIM *rd_user, RRDDIM *rd_system)
94 +{
95 + function_called();
96 + check_expected_ptr(st_rusage);
97 + check_expected_ptr(rd_user);
98 + check_expected_ptr(rd_system);
99 +}
100 +
101 +int __wrap_send_internal_metrics(struct instance *instance)
102 +{
103 + function_called();
104 + check_expected_ptr(instance);
105 return mock_type(int);
106 }
107
exporting/tests/exporting_fixtures.c
+32
@@ -127,3 +127,35 @@ int teardown_initialized_engine(void **state)
127
128 return 0;
129 }
130 +
131 +int setup_prometheus(void **state)
132 +{
133 + (void)state;
134 +
135 + prometheus_exporter_instance = calloc(1, sizeof(struct instance));
136 +
137 + setup_rrdhost();
138 +
139 + prometheus_exporter_instance->config.update_every = 10;
140 +
141 + prometheus_exporter_instance->config.options |=
142 + EXPORTING_OPTION_SEND_NAMES | EXPORTING_OPTION_SEND_CONFIGURED_LABELS | EXPORTING_OPTION_SEND_AUTOMATIC_LABELS;
143 +
144 + prometheus_exporter_instance->config.charts_pattern = simple_pattern_create("*", NULL, SIMPLE_PATTERN_EXACT);
145 + prometheus_exporter_instance->config.hosts_pattern = simple_pattern_create("*", NULL, SIMPLE_PATTERN_EXACT);
146 +
147 + return 0;
148 +}
149 +
150 +int teardown_prometheus(void **state)
151 +{
152 + (void)state;
153 +
154 + teardown_rrdhost();
155 +
156 + simple_pattern_free(prometheus_exporter_instance->config.charts_pattern);
157 + simple_pattern_free(prometheus_exporter_instance->config.hosts_pattern);
158 + free(prometheus_exporter_instance);
159 +
160 + return 0;
161 +}
exporting/tests/netdata_doubles.c
+86
@@ -85,6 +85,92 @@ void __rrd_check_rdlock(const char *file, const char *function, const unsigned l
85 (void)line;
86 }
87
88 +RRDSET *rrdset_create_custom(
89 + RRDHOST *host,
90 + const char *type,
91 + const char *id,
92 + const char *name,
93 + const char *family,
94 + const char *context,
95 + const char *title,
96 + const char *units,
97 + const char *plugin,
98 + const char *module,
99 + long priority,
100 + int update_every,
101 + RRDSET_TYPE chart_type,
102 + RRD_MEMORY_MODE memory_mode,
103 + long history_entries)
104 +{
105 + check_expected_ptr(host);
106 + check_expected_ptr(type);
107 + check_expected_ptr(id);
108 + check_expected_ptr(name);
109 + check_expected_ptr(family);
110 + check_expected_ptr(context);
111 + UNUSED(title);
112 + check_expected_ptr(units);
113 + check_expected_ptr(plugin);
114 + check_expected_ptr(module);
115 + check_expected(priority);
116 + check_expected(update_every);
117 + check_expected(chart_type);
118 + UNUSED(memory_mode);
119 + UNUSED(history_entries);
120 +
121 + function_called();
122 +
123 + return mock_ptr_type(RRDSET *);
124 +}
125 +
126 +void rrdset_next_usec(RRDSET *st, usec_t microseconds)
127 +{
128 + check_expected_ptr(st);
129 + UNUSED(microseconds);
130 +
131 + function_called();
132 +}
133 +
134 +void rrdset_done(RRDSET *st)
135 +{
136 + check_expected_ptr(st);
137 +
138 + function_called();
139 +}
140 +
141 +RRDDIM *rrddim_add_custom(
142 + RRDSET *st,
143 + const char *id,
144 + const char *name,
145 + collected_number multiplier,
146 + collected_number divisor,
147 + RRD_ALGORITHM algorithm,
148 + RRD_MEMORY_MODE memory_mode)
149 +{
150 + check_expected_ptr(st);
151 + UNUSED(id);
152 + check_expected_ptr(name);
153 + check_expected(multiplier);
154 + check_expected(divisor);
155 + check_expected(algorithm);
156 + UNUSED(memory_mode);
157 +
158 + function_called();
159 +
160 + return NULL;
161 +}
162 +
163 +collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value)
164 +{
165 + check_expected_ptr(st);
166 + UNUSED(rd);
167 + UNUSED(value);
168 +
169 + function_called();
170 +
171 + return 0;
172 +}
173 +
174 const char *rrd_memory_mode_name(RRD_MEMORY_MODE id)
175 {
176 (void)id;
exporting/tests/test_exporting_engine.c
+453 -18
@@ -44,6 +44,11 @@ static void test_exporting_engine(void **state)
44 expect_memory(__wrap_init_connectors, engine, engine, sizeof(struct engine));
45 will_return(__wrap_init_connectors, 0);
46
47 + expect_function_call(__wrap_create_main_rusage_chart);
48 + expect_not_value(__wrap_create_main_rusage_chart, st_rusage, NULL);
49 + expect_not_value(__wrap_create_main_rusage_chart, rd_user, NULL);
50 + expect_not_value(__wrap_create_main_rusage_chart, rd_system, NULL);
51 +
52 expect_function_call(__wrap_now_realtime_sec);
53 will_return(__wrap_now_realtime_sec, 2);
54
@@ -59,9 +64,10 @@ static void test_exporting_engine(void **state)
64 expect_memory(__wrap_notify_workers, engine, engine, sizeof(struct engine));
65 will_return(__wrap_notify_workers, 0);
66
62 - expect_function_call(__wrap_send_internal_metrics);
63 - expect_memory(__wrap_send_internal_metrics, engine, engine, sizeof(struct engine));
64 - will_return(__wrap_send_internal_metrics, 0);
67 + expect_function_call(__wrap_send_main_rusage);
68 + expect_value(__wrap_send_main_rusage, st_rusage, NULL);
69 + expect_value(__wrap_send_main_rusage, rd_user, NULL);
70 + expect_value(__wrap_send_main_rusage, rd_system, NULL);
71
72 expect_function_call(__wrap_info_int);
73
@@ -87,7 +93,7 @@ static void test_read_exporting_config(void **state)
93 assert_ptr_not_equal(instance, NULL);
94 assert_ptr_equal(instance->next, NULL);
95 assert_ptr_equal(instance->engine, engine);
90 - assert_int_equal(instance->config.type, BACKEND_TYPE_GRAPHITE);
96 + assert_int_equal(instance->config.type, EXPORTING_CONNECTOR_TYPE_GRAPHITE);
97 assert_string_equal(instance->config.destination, "localhost");
98 assert_int_equal(instance->config.update_every, 1);
99 assert_int_equal(instance->config.buffer_on_failures, 10);
@@ -122,7 +128,7 @@ static void test_init_connectors(void **state)
128 assert_ptr_equal(instance->metric_formatting, format_dimension_collected_graphite_plaintext);
129 assert_ptr_equal(instance->end_chart_formatting, NULL);
130 assert_ptr_equal(instance->end_host_formatting, flush_host_labels);
125 - assert_ptr_equal(instance->end_batch_formatting, NULL);
131 + assert_ptr_equal(instance->end_batch_formatting, simple_connector_update_buffered_bytes);
132
133 BUFFER *buffer = instance->buffer;
134 assert_ptr_not_equal(buffer, NULL);
@@ -384,7 +390,7 @@ static void test_prepare_buffers(void **state)
390
391 assert_int_equal(__real_prepare_buffers(engine), 0);
392
387 - assert_int_equal(instance->stats.chart_buffered_metrics, 1);
393 + assert_int_equal(instance->stats.buffered_metrics, 1);
394
395 // check with NULL functions
396 instance->start_batch_formatting = NULL;
@@ -573,8 +579,8 @@ static void test_simple_connector_receive_response(void **state)
579 log_line,
580 "EXPORTING: received 9 bytes from instance_name connector instance. Ignoring them. Sample: 'Test recv'");
581
576 - assert_int_equal(stats->chart_received_bytes, 9);
577 - assert_int_equal(stats->chart_receptions, 1);
582 + assert_int_equal(stats->received_bytes, 9);
583 + assert_int_equal(stats->receptions, 1);
584 assert_int_equal(sock, 1);
585 }
586
@@ -614,10 +620,10 @@ static void test_simple_connector_send_buffer(void **state)
620 simple_connector_send_buffer(&sock, &failures, instance);
621
622 assert_int_equal(failures, 0);
617 - assert_int_equal(stats->chart_transmission_successes, 1);
618 - assert_int_equal(stats->chart_sent_bytes, 84);
619 - assert_int_equal(stats->chart_sent_metrics, 1);
620 - assert_int_equal(stats->chart_transmission_failures, 0);
623 + assert_int_equal(stats->transmission_successes, 1);
624 + assert_int_equal(stats->sent_bytes, 84);
625 + assert_int_equal(stats->sent_metrics, 1);
626 + assert_int_equal(stats->transmission_failures, 0);
627
628 assert_int_equal(buffer_strlen(buffer), 0);
629
@@ -628,6 +634,7 @@ static void test_simple_connector_worker(void **state)
634 {
635 struct engine *engine = *state;
636 struct instance *instance = engine->instance_root;
637 + struct stats *stats = &instance->stats;
638 BUFFER *buffer = instance->buffer;
639
640 __real_mark_scheduled_instances(engine);
@@ -661,7 +668,24 @@ static void test_simple_connector_worker(void **state)
668 expect_value(__wrap_send, len, 84);
669 expect_value(__wrap_send, flags, MSG_NOSIGNAL);
670
671 + expect_function_call(__wrap_send_internal_metrics);
672 + expect_value(__wrap_send_internal_metrics, instance, instance);
673 + will_return(__wrap_send_internal_metrics, 0);
674 +
675 simple_connector_worker(instance);
676 +
677 + assert_int_equal(stats->buffered_metrics, 0);
678 + assert_int_equal(stats->buffered_bytes, 84);
679 + assert_int_equal(stats->received_bytes, 0);
680 + assert_int_equal(stats->sent_bytes, 84);
681 + assert_int_equal(stats->sent_metrics, 1);
682 + assert_int_equal(stats->lost_metrics, 0);
683 + assert_int_equal(stats->receptions, 0);
684 + assert_int_equal(stats->transmission_successes, 1);
685 + assert_int_equal(stats->transmission_failures, 0);
686 + assert_int_equal(stats->data_lost_events, 0);
687 + assert_int_equal(stats->lost_bytes, 0);
688 + assert_int_equal(stats->reconnects, 0);
689 }
690
691 static void test_sanitize_json_string(void **state)
@@ -761,6 +785,367 @@ static void test_flush_host_labels(void **state)
785 assert_int_equal(buffer_strlen(instance->labels), 0);
786 }
787
788 +static void test_create_main_rusage_chart(void **state)
789 +{
790 + UNUSED(state);
791 +
792 + RRDSET *st_rusage = calloc(1, sizeof(RRDSET));
793 + RRDDIM *rd_user = NULL;
794 + RRDDIM *rd_system = NULL;
795 +
796 + expect_function_call(rrdset_create_custom);
797 + expect_value(rrdset_create_custom, host, localhost);
798 + expect_string(rrdset_create_custom, type, "netdata");
799 + expect_string(rrdset_create_custom, id, "exporting_main_thread_cpu");
800 + expect_value(rrdset_create_custom, name, NULL);
801 + expect_string(rrdset_create_custom, family, "exporting");
802 + expect_value(rrdset_create_custom, context, NULL);
803 + expect_string(rrdset_create_custom, units, "milliseconds/s");
804 + expect_string(rrdset_create_custom, plugin, "exporting");
805 + expect_value(rrdset_create_custom, module, NULL);
806 + expect_value(rrdset_create_custom, priority, 130600);
807 + expect_value(rrdset_create_custom, update_every, localhost->rrd_update_every);
808 + expect_value(rrdset_create_custom, chart_type, RRDSET_TYPE_STACKED);
809 + will_return(rrdset_create_custom, st_rusage);
810 +
811 + expect_function_calls(rrddim_add_custom, 2);
812 + expect_value_count(rrddim_add_custom, st, st_rusage, 2);
813 + expect_value_count(rrddim_add_custom, name, NULL, 2);
814 + expect_value_count(rrddim_add_custom, multiplier, 1, 2);
815 + expect_value_count(rrddim_add_custom, divisor, 1000, 2);
816 + expect_value_count(rrddim_add_custom, algorithm, RRD_ALGORITHM_INCREMENTAL, 2);
817 +
818 + __real_create_main_rusage_chart(&st_rusage, &rd_user, &rd_system);
819 +
820 + free(st_rusage);
821 +}
822 +
823 +static void test_send_main_rusage(void **state)
824 +{
825 + UNUSED(state);
826 +
827 + RRDSET *st_rusage = calloc(1, sizeof(RRDSET));
828 + st_rusage->counter_done = 1;
829 +
830 + expect_function_call(rrdset_next_usec);
831 + expect_value(rrdset_next_usec, st, st_rusage);
832 +
833 + expect_function_calls(rrddim_set_by_pointer, 2);
834 + expect_value_count(rrddim_set_by_pointer, st, st_rusage, 2);
835 +
836 + expect_function_call(rrdset_done);
837 + expect_value(rrdset_done, st, st_rusage);
838 +
839 + __real_send_main_rusage(st_rusage, NULL, NULL);
840 +
841 + free(st_rusage);
842 +}
843 +
844 +static void test_send_internal_metrics(void **state)
845 +{
846 + UNUSED(state);
847 +
848 + struct instance *instance = calloc(1, sizeof(struct instance));
849 + instance->config.name = (const char *)strdupz("test_instance");
850 + instance->config.update_every = 2;
851 +
852 + struct stats *stats = &instance->stats;
853 +
854 + stats->st_metrics = calloc(1, sizeof(RRDSET));
855 + stats->st_metrics->counter_done = 1;
856 + stats->st_bytes = calloc(1, sizeof(RRDSET));
857 + stats->st_bytes->counter_done = 1;
858 + stats->st_ops = calloc(1, sizeof(RRDSET));
859 + stats->st_ops->counter_done = 1;
860 + stats->st_rusage = calloc(1, sizeof(RRDSET));
861 + stats->st_rusage->counter_done = 1;
862 +
863 + // ------------------------------------------------------------------------
864 +
865 + expect_function_call(rrdset_create_custom);
866 + expect_value(rrdset_create_custom, host, localhost);
867 + expect_string(rrdset_create_custom, type, "netdata");
868 + expect_string(rrdset_create_custom, id, "exporting_test_instance_metrics");
869 + expect_value(rrdset_create_custom, name, NULL);
870 + expect_string(rrdset_create_custom, family, "exporting_test_instance");
871 + expect_value(rrdset_create_custom, context, NULL);
872 + expect_string(rrdset_create_custom, units, "metrics");
873 + expect_string(rrdset_create_custom, plugin, "exporting");
874 + expect_value(rrdset_create_custom, module, NULL);
875 + expect_value(rrdset_create_custom, priority, 130610);
876 + expect_value(rrdset_create_custom, update_every, 2);
877 + expect_value(rrdset_create_custom, chart_type, RRDSET_TYPE_LINE);
878 + will_return(rrdset_create_custom, stats->st_metrics);
879 +
880 + expect_function_calls(rrddim_add_custom, 3);
881 + expect_value_count(rrddim_add_custom, st, stats->st_metrics, 3);
882 + expect_value_count(rrddim_add_custom, name, NULL, 3);
883 + expect_value_count(rrddim_add_custom, multiplier, 1, 3);
884 + expect_value_count(rrddim_add_custom, divisor, 1, 3);
885 + expect_value_count(rrddim_add_custom, algorithm, RRD_ALGORITHM_ABSOLUTE, 3);
886 +
887 + // ------------------------------------------------------------------------
888 +
889 + expect_function_call(rrdset_create_custom);
890 + expect_value(rrdset_create_custom, host, localhost);
891 + expect_string(rrdset_create_custom, type, "netdata");
892 + expect_string(rrdset_create_custom, id, "exporting_test_instance_bytes");
893 + expect_value(rrdset_create_custom, name, NULL);
894 + expect_string(rrdset_create_custom, family, "exporting_test_instance");
895 + expect_value(rrdset_create_custom, context, NULL);
896 + expect_string(rrdset_create_custom, units, "KiB");
897 + expect_string(rrdset_create_custom, plugin, "exporting");
898 + expect_value(rrdset_create_custom, module, NULL);
899 + expect_value(rrdset_create_custom, priority, 130620);
900 + expect_value(rrdset_create_custom, update_every, 2);
901 + expect_value(rrdset_create_custom, chart_type, RRDSET_TYPE_AREA);
902 + will_return(rrdset_create_custom, stats->st_bytes);
903 +
904 + expect_function_calls(rrddim_add_custom, 4);
905 + expect_value_count(rrddim_add_custom, st, stats->st_bytes, 4);
906 + expect_value_count(rrddim_add_custom, name, NULL, 4);
907 + expect_value_count(rrddim_add_custom, multiplier, 1, 4);
908 + expect_value_count(rrddim_add_custom, divisor, 1024, 4);
909 + expect_value_count(rrddim_add_custom, algorithm, RRD_ALGORITHM_ABSOLUTE, 4);
910 +
911 + // ------------------------------------------------------------------------
912 +
913 + expect_function_call(rrdset_create_custom);
914 + expect_value(rrdset_create_custom, host, localhost);
915 + expect_string(rrdset_create_custom, type, "netdata");
916 + expect_string(rrdset_create_custom, id, "exporting_test_instance_ops");
917 + expect_value(rrdset_create_custom, name, NULL);
918 + expect_string(rrdset_create_custom, family, "exporting_test_instance");
919 + expect_value(rrdset_create_custom, context, NULL);
920 + expect_string(rrdset_create_custom, units, "operations");
921 + expect_string(rrdset_create_custom, plugin, "exporting");
922 + expect_value(rrdset_create_custom, module, NULL);
923 + expect_value(rrdset_create_custom, priority, 130630);
924 + expect_value(rrdset_create_custom, update_every, 2);
925 + expect_value(rrdset_create_custom, chart_type, RRDSET_TYPE_LINE);
926 + will_return(rrdset_create_custom, stats->st_ops);
927 +
928 + expect_function_calls(rrddim_add_custom, 5);
929 + expect_value_count(rrddim_add_custom, st, stats->st_ops, 5);
930 + expect_value_count(rrddim_add_custom, name, NULL, 5);
931 + expect_value_count(rrddim_add_custom, multiplier, 1, 5);
932 + expect_value_count(rrddim_add_custom, divisor, 1, 5);
933 + expect_value_count(rrddim_add_custom, algorithm, RRD_ALGORITHM_ABSOLUTE, 5);
934 +
935 + // ------------------------------------------------------------------------
936 +
937 + expect_function_call(rrdset_create_custom);
938 + expect_value(rrdset_create_custom, host, localhost);
939 + expect_string(rrdset_create_custom, type, "netdata");
940 + expect_string(rrdset_create_custom, id, "exporting_test_instance_thread_cpu");
941 + expect_value(rrdset_create_custom, name, NULL);
942 + expect_string(rrdset_create_custom, family, "exporting_test_instance");
943 + expect_value(rrdset_create_custom, context, NULL);
944 + expect_string(rrdset_create_custom, units, "milliseconds/s");
945 + expect_string(rrdset_create_custom, plugin, "exporting");
946 + expect_value(rrdset_create_custom, module, NULL);
947 + expect_value(rrdset_create_custom, priority, 130640);
948 + expect_value(rrdset_create_custom, update_every, 2);
949 + expect_value(rrdset_create_custom, chart_type, RRDSET_TYPE_STACKED);
950 + will_return(rrdset_create_custom, stats->st_rusage);
951 +
952 + expect_function_calls(rrddim_add_custom, 2);
953 + expect_value_count(rrddim_add_custom, st, stats->st_rusage, 2);
954 + expect_value_count(rrddim_add_custom, name, NULL, 2);
955 + expect_value_count(rrddim_add_custom, multiplier, 1, 2);
956 + expect_value_count(rrddim_add_custom, divisor, 1000, 2);
957 + expect_value_count(rrddim_add_custom, algorithm, RRD_ALGORITHM_INCREMENTAL, 2);
958 +
959 + // ------------------------------------------------------------------------
960 +
961 + expect_function_call(rrdset_next_usec);
962 + expect_value(rrdset_next_usec, st, stats->st_metrics);
963 +
964 + expect_function_calls(rrddim_set_by_pointer, 3);
965 + expect_value_count(rrddim_set_by_pointer, st, stats->st_metrics, 3);
966 +
967 + expect_function_call(rrdset_done);
968 + expect_value(rrdset_done, st, stats->st_metrics);
969 +
970 + // ------------------------------------------------------------------------
971 +
972 + expect_function_call(rrdset_next_usec);
973 + expect_value(rrdset_next_usec, st, stats->st_bytes);
974 +
975 + expect_function_calls(rrddim_set_by_pointer, 4);
976 + expect_value_count(rrddim_set_by_pointer, st, stats->st_bytes, 4);
977 +
978 + expect_function_call(rrdset_done);
979 + expect_value(rrdset_done, st, stats->st_bytes);
980 +
981 + // ------------------------------------------------------------------------
982 +
983 + expect_function_call(rrdset_next_usec);
984 + expect_value(rrdset_next_usec, st, stats->st_ops);
985 +
986 + expect_function_calls(rrddim_set_by_pointer, 5);
987 + expect_value_count(rrddim_set_by_pointer, st, stats->st_ops, 5);
988 +
989 + expect_function_call(rrdset_done);
990 + expect_value(rrdset_done, st, stats->st_ops);
991 +
992 + // ------------------------------------------------------------------------
993 +
994 + expect_function_call(rrdset_next_usec);
995 + expect_value(rrdset_next_usec, st, stats->st_rusage);
996 +
997 + expect_function_calls(rrddim_set_by_pointer, 2);
998 + expect_value_count(rrddim_set_by_pointer, st, stats->st_rusage, 2);
999 +
1000 + expect_function_call(rrdset_done);
1001 + expect_value(rrdset_done, st, stats->st_rusage);
1002 +
1003 + // ------------------------------------------------------------------------
1004 +
1005 + __real_send_internal_metrics(instance);
1006 +
1007 + free(stats->st_metrics);
1008 + free(stats->st_bytes);
1009 + free(stats->st_ops);
1010 + free(stats->st_rusage);
1011 + free((void *)instance->config.name);
1012 + free(instance);
1013 +}
1014 +
1015 +static void test_can_send_rrdset(void **state)
1016 +{
1017 + (void)*state;
1018 +
1019 + assert_int_equal(can_send_rrdset(prometheus_exporter_instance, localhost->rrdset_root), 1);
1020 +
1021 + rrdset_flag_set(localhost->rrdset_root, RRDSET_FLAG_BACKEND_IGNORE);
1022 + assert_int_equal(can_send_rrdset(prometheus_exporter_instance, localhost->rrdset_root), 0);
1023 + rrdset_flag_clear(localhost->rrdset_root, RRDSET_FLAG_BACKEND_IGNORE);
1024 +
1025 + // TODO: test with a denying simple pattern
1026 +
1027 + rrdset_flag_set(localhost->rrdset_root, RRDSET_FLAG_OBSOLETE);
1028 + assert_int_equal(can_send_rrdset(prometheus_exporter_instance, localhost->rrdset_root), 0);
1029 + rrdset_flag_clear(localhost->rrdset_root, RRDSET_FLAG_OBSOLETE);
1030 +
1031 + localhost->rrdset_root->rrd_memory_mode = RRD_MEMORY_MODE_NONE;
1032 + prometheus_exporter_instance->config.options |= EXPORTING_SOURCE_DATA_AVERAGE;
1033 + assert_int_equal(can_send_rrdset(prometheus_exporter_instance, localhost->rrdset_root), 0);
1034 +}
1035 +
1036 +static void test_prometheus_name_copy(void **state)
1037 +{
1038 + (void)*state;
1039 +
1040 + char destination_name[PROMETHEUS_ELEMENT_MAX + 1];
1041 + assert_int_equal(prometheus_name_copy(destination_name, "test-name", PROMETHEUS_ELEMENT_MAX), 9);
1042 +
1043 + assert_string_equal(destination_name, "test_name");
1044 +}
1045 +
1046 +static void test_prometheus_label_copy(void **state)
1047 +{
1048 + (void)*state;
1049 +
1050 + char destination_name[PROMETHEUS_ELEMENT_MAX + 1];
1051 + assert_int_equal(prometheus_label_copy(destination_name, "test\"\\\nlabel", PROMETHEUS_ELEMENT_MAX), 15);
1052 +
1053 + assert_string_equal(destination_name, "test\\\"\\\\\\\nlabel");
1054 +}
1055 +
1056 +static void test_prometheus_units_copy(void **state)
1057 +{
1058 + (void)*state;
1059 +
1060 + char destination_name[PROMETHEUS_ELEMENT_MAX + 1];
1061 + assert_string_equal(prometheus_units_copy(destination_name, "test-units", PROMETHEUS_ELEMENT_MAX, 0), "_test_units");
1062 + assert_string_equal(destination_name, "_test_units");
1063 +
1064 + assert_string_equal(prometheus_units_copy(destination_name, "%", PROMETHEUS_ELEMENT_MAX, 0), "_percent");
1065 + assert_string_equal(prometheus_units_copy(destination_name, "test-units/s", PROMETHEUS_ELEMENT_MAX, 0), "_test_units_persec");
1066 +
1067 + assert_string_equal(prometheus_units_copy(destination_name, "KiB", PROMETHEUS_ELEMENT_MAX, 1), "_KB");
1068 +}
1069 +
1070 +static void test_format_host_labels_prometheus(void **state)
1071 +{
1072 + struct engine *engine = *state;
1073 + struct instance *instance = engine->instance_root;
1074 +
1075 + instance->config.options |= EXPORTING_OPTION_SEND_CONFIGURED_LABELS;
1076 + instance->config.options |= EXPORTING_OPTION_SEND_AUTOMATIC_LABELS;
1077 +
1078 + format_host_labels_prometheus(instance, localhost);
1079 + assert_string_equal(buffer_tostring(instance->labels), "key1=\"netdata\",key2=\"value2\"");
1080 +}
1081 +
1082 +static void rrd_stats_api_v1_charts_allmetrics_prometheus(void **state)
1083 +{
1084 + (void)state;
1085 +
1086 + BUFFER *buffer = buffer_create(0);
1087 +
1088 + localhost->hostname = strdupz("test_hostname");
1089 + localhost->rrdset_root->family = strdupz("test_family");
1090 + localhost->rrdset_root->context = strdupz("test_context");
1091 +
1092 + expect_function_call(__wrap_now_realtime_sec);
1093 + will_return(__wrap_now_realtime_sec, 2);
1094 +
1095 + expect_function_call(__wrap_exporting_calculate_value_from_stored_data);
1096 + will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_EXISTS));
1097 +
1098 + rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(localhost, buffer, "test_server", "test_prefix", 0, 0);
1099 +
1100 + assert_string_equal(
1101 + buffer_tostring(buffer),
1102 + "netdata_info{instance=\"test_hostname\",application=\"(null)\",version=\"(null)\"} 1\n"
1103 + "netdata_host_tags_info{key1=\"value1\",key2=\"value2\"} 1\n"
1104 + "netdata_host_tags{key1=\"value1\",key2=\"value2\"} 1\n"
1105 + "test_prefix_test_context{chart=\"chart_id\",family=\"test_family\",dimension=\"dimension_id\"} 690565856.0000000\n");
1106 +
1107 + buffer_flush(buffer);
1108 +
1109 + expect_function_call(__wrap_now_realtime_sec);
1110 + will_return(__wrap_now_realtime_sec, 2);
1111 +
1112 + expect_function_call(__wrap_exporting_calculate_value_from_stored_data);
1113 + will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_EXISTS));
1114 +
1115 + rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(
1116 + localhost, buffer, "test_server", "test_prefix", 0, PROMETHEUS_OUTPUT_NAMES | PROMETHEUS_OUTPUT_TYPES);
1117 +
1118 + assert_string_equal(
1119 + buffer_tostring(buffer),
1120 + "netdata_info{instance=\"test_hostname\",application=\"(null)\",version=\"(null)\"} 1\n"
1121 + "netdata_host_tags_info{key1=\"value1\",key2=\"value2\"} 1\n"
1122 + "netdata_host_tags{key1=\"value1\",key2=\"value2\"} 1\n"
1123 + "# COMMENT TYPE test_prefix_test_context gauge\n"
1124 + "test_prefix_test_context{chart=\"chart_name\",family=\"test_family\",dimension=\"dimension_name\"} 690565856.0000000\n");
1125 +
1126 + buffer_flush(buffer);
1127 +
1128 + expect_function_call(__wrap_now_realtime_sec);
1129 + will_return(__wrap_now_realtime_sec, 2);
1130 +
1131 + expect_function_call(__wrap_exporting_calculate_value_from_stored_data);
1132 + will_return(__wrap_exporting_calculate_value_from_stored_data, pack_storage_number(27, SN_EXISTS));
1133 +
1134 + rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(localhost, buffer, "test_server", "test_prefix", 0, 0);
1135 +
1136 + assert_string_equal(
1137 + buffer_tostring(buffer),
1138 + "netdata_info{instance=\"test_hostname\",application=\"(null)\",version=\"(null)\"} 1\n"
1139 + "netdata_host_tags_info{instance=\"test_hostname\",key1=\"value1\",key2=\"value2\"} 1\n"
1140 + "netdata_host_tags{instance=\"test_hostname\",key1=\"value1\",key2=\"value2\"} 1\n"
1141 + "test_prefix_test_context{chart=\"chart_id\",family=\"test_family\",dimension=\"dimension_id\",instance=\"test_hostname\"} 690565856.0000000\n");
1142 +
1143 + free(localhost->rrdset_root->context);
1144 + free(localhost->rrdset_root->family);
1145 + free(localhost->hostname);
1146 + buffer_free(buffer);
1147 +}
1148 +
1149 #if ENABLE_PROMETHEUS_REMOTE_WRITE
1150 static void test_init_prometheus_remote_write_instance(void **state)
1151 {
@@ -1014,6 +1399,7 @@ static void test_aws_kinesis_connector_worker(void **state)
1399 {
1400 struct engine *engine = *state;
1401 struct instance *instance = engine->instance_root;
1402 + struct stats *stats = &instance->stats;
1403 BUFFER *buffer = instance->buffer;
1404
1405 __real_mark_scheduled_instances(engine);
@@ -1059,8 +1445,25 @@ static void test_aws_kinesis_connector_worker(void **state)
1445 expect_not_value(__wrap_kinesis_get_result, lost_bytes, NULL);
1446 will_return(__wrap_kinesis_get_result, 0);
1447
1448 + expect_function_call(__wrap_send_internal_metrics);
1449 + expect_value(__wrap_send_internal_metrics, instance, instance);
1450 + will_return(__wrap_send_internal_metrics, 0);
1451 +
1452 aws_kinesis_connector_worker(instance);
1453
1454 + assert_int_equal(stats->buffered_metrics, 0);
1455 + assert_int_equal(stats->buffered_bytes, 84);
1456 + assert_int_equal(stats->received_bytes, 0);
1457 + assert_int_equal(stats->sent_bytes, 84);
1458 + assert_int_equal(stats->sent_metrics, 1);
1459 + assert_int_equal(stats->lost_metrics, 0);
1460 + assert_int_equal(stats->receptions, 1);
1461 + assert_int_equal(stats->transmission_successes, 1);
1462 + assert_int_equal(stats->transmission_failures, 0);
1463 + assert_int_equal(stats->data_lost_events, 0);
1464 + assert_int_equal(stats->lost_bytes, 0);
1465 + assert_int_equal(stats->reconnects, 0);
1466 +
1467 free(connector_specific_config->stream_name);
1468 free(connector_specific_config->auth_key_id);
1469 free(connector_specific_config->secure_key);
@@ -1170,7 +1573,7 @@ static void test_format_batch_mongodb(void **state)
1573 BUFFER *buffer = buffer_create(0);
1574 buffer_sprintf(buffer, "{ \"metric\": \"test_metric\" }\n");
1575 instance->buffer = buffer;
1173 - stats->chart_buffered_metrics = 1;
1576 + stats->buffered_metrics = 1;
1577
1578 assert_int_equal(format_batch_mongodb(instance), 0);
1579
@@ -1221,6 +1624,10 @@ static void test_mongodb_connector_worker(void **state)
1624 expect_not_value(__wrap_mongoc_collection_insert_many, error, NULL);
1625 will_return(__wrap_mongoc_collection_insert_many, true);
1626
1627 + expect_function_call(__wrap_send_internal_metrics);
1628 + expect_value(__wrap_send_internal_metrics, instance, instance);
1629 + will_return(__wrap_send_internal_metrics, 0);
1630 +
1631 mongodb_connector_worker(instance);
1632
1633 assert_ptr_equal(connector_specific_data->first_buffer->insert, NULL);
@@ -1228,11 +1635,18 @@ static void test_mongodb_connector_worker(void **state)
1635 assert_ptr_equal(connector_specific_data->first_buffer, connector_specific_data->first_buffer->next);
1636
1637 struct stats *stats = &instance->stats;
1231 - assert_int_equal(stats->chart_sent_bytes, 60);
1232 - assert_int_equal(stats->chart_transmission_successes, 1);
1233 - assert_int_equal(stats->chart_receptions, 1);
1234 - assert_int_equal(stats->chart_sent_bytes, 60);
1235 - assert_int_equal(stats->chart_sent_metrics, 0);
1638 + assert_int_equal(stats->buffered_metrics, 0);
1639 + assert_int_equal(stats->buffered_bytes, 0);
1640 + assert_int_equal(stats->received_bytes, 0);
1641 + assert_int_equal(stats->sent_bytes, 30);
1642 + assert_int_equal(stats->sent_metrics, 1);
1643 + assert_int_equal(stats->lost_metrics, 0);
1644 + assert_int_equal(stats->receptions, 1);
1645 + assert_int_equal(stats->transmission_successes, 1);
1646 + assert_int_equal(stats->transmission_failures, 0);
1647 + assert_int_equal(stats->data_lost_events, 0);
1648 + assert_int_equal(stats->lost_bytes, 0);
1649 + assert_int_equal(stats->reconnects, 0);
1650
1651 free(connector_specific_config->database);
1652 free(connector_specific_config->collection);
@@ -1311,6 +1725,27 @@ int main(void)
1725 int test_res = cmocka_run_group_tests_name("exporting_engine", tests, NULL, NULL) +
1726 cmocka_run_group_tests_name("labels_in_exporting_engine", label_tests, NULL, NULL);
1727
1728 + const struct CMUnitTest internal_metrics_tests[] = {
1729 + cmocka_unit_test(test_create_main_rusage_chart),
1730 + cmocka_unit_test(test_send_main_rusage),
1731 + cmocka_unit_test(test_send_internal_metrics),
1732 + };
1733 +
1734 + test_res += cmocka_run_group_tests_name("internal_metrics", internal_metrics_tests, NULL, NULL);
1735 +
1736 + const struct CMUnitTest prometheus_web_api_tests[] = {
1737 + cmocka_unit_test_setup_teardown(test_can_send_rrdset, setup_prometheus, teardown_prometheus),
1738 + cmocka_unit_test_setup_teardown(test_prometheus_name_copy, setup_prometheus, teardown_prometheus),
1739 + cmocka_unit_test_setup_teardown(test_prometheus_label_copy, setup_prometheus, teardown_prometheus),
1740 + cmocka_unit_test_setup_teardown(test_prometheus_units_copy, setup_prometheus, teardown_prometheus),
1741 + cmocka_unit_test_setup_teardown(
1742 + test_format_host_labels_prometheus, setup_configured_engine, teardown_configured_engine),
1743 + cmocka_unit_test_setup_teardown(
1744 + rrd_stats_api_v1_charts_allmetrics_prometheus, setup_prometheus, teardown_prometheus),
1745 + };
1746 +
1747 + test_res += cmocka_run_group_tests_name("prometheus_web_api", prometheus_web_api_tests, NULL, NULL);
1748 +
1749 #if ENABLE_PROMETHEUS_REMOTE_WRITE
1750 const struct CMUnitTest prometheus_remote_write_tests[] = {
1751 cmocka_unit_test_setup_teardown(
exporting/tests/test_exporting_engine.h
+10 -1
@@ -91,7 +91,14 @@ int __wrap_prepare_buffers(struct engine *engine);
91
92 int __wrap_notify_workers(struct engine *engine);
93
94 -int __wrap_send_internal_metrics(struct engine *engine);
94 +void __real_create_main_rusage_chart(RRDSET **st_rusage, RRDDIM **rd_user, RRDDIM **rd_system);
95 +void __wrap_create_main_rusage_chart(RRDSET **st_rusage, RRDDIM **rd_user, RRDDIM **rd_system);
96 +
97 +void __real_send_main_rusage(RRDSET *st_rusage, RRDDIM *rd_user, RRDDIM *rd_system);
98 +void __wrap_send_main_rusage(RRDSET *st_rusage, RRDDIM *rd_user, RRDDIM *rd_system);
99 +
100 +int __real_send_internal_metrics(struct instance *instance);
101 +int __wrap_send_internal_metrics(struct instance *instance);
102
103 int __real_rrdhost_is_exportable(struct instance *instance, RRDHOST *host);
104 int __wrap_rrdhost_is_exportable(struct instance *instance, RRDHOST *host);
@@ -166,6 +173,8 @@ int setup_rrdhost();
173 int teardown_rrdhost();
174 int setup_initialized_engine(void **state);
175 int teardown_initialized_engine(void **state);
176 +int setup_prometheus(void **state);
177 +int teardown_prometheus(void **state);
178
179 void init_connectors_in_tests(struct engine *engine);
180
health/REFERENCE.md
+2 -1
@@ -1,6 +1,7 @@
1 <!--
2 ---
3 title: "Health configuration reference"
4 +date: 2020-03-31
5 custom_edit_url: https://github.com/netdata/netdata/edit/master/health/REFERENCE.md
6 ---
7 -->
@@ -136,7 +137,7 @@ If you create a template using the `disk.io` context, it will apply an alarm to
137 The alarm or template will be used only if the operating system of the host matches this list specified in `os`. The
138 value is a space-separated list.
139
139 -The following example enables the entity on Linux, FreeBSD, and MacOS, but no other operating systems.
140 +The following example enables the entity on Linux, FreeBSD, and macOS, but no other operating systems.
141
142 ```yaml
143 os: linux freebsd macos
health/notifications/alarm-notify.sh.in
+81 -3
@@ -35,6 +35,7 @@
35 # - Microsoft Team notification by @tioumen
36 # - RocketChat notifications by @Hermsi1337 #3777
37 # - Google Hangouts Chat notifications by @EnzoAkira and @hendrikhofstadt
38 +# - Dynatrace Event by @illumine
39
40 # -----------------------------------------------------------------------------
41 # testing notifications
@@ -170,6 +171,7 @@ awssns
171 rocketchat
172 sms
173 hangouts
174 +dynatrace
175 "
176
177 # -----------------------------------------------------------------------------
@@ -366,6 +368,16 @@ IRC_NETWORK=
368 # hangouts configs
369 declare -A HANGOUTS_WEBHOOK_URI
370
371 +# dynatrace configs
372 +DYNATRACE_SPACE=
373 +DYNATRACE_SERVER=
374 +DYNATRACE_TOKEN=
375 +DYNATRACE_TAG_VALUE=
376 +DYNATRACE_ANNOTATION_TYPE=
377 +DYNATRACE_EVENT=
378 +SEND_DYNATRACE=
379 +
380 +
381 # load the stock and user configuration files
382 # these will overwrite the variables above
383
@@ -503,6 +515,14 @@ filter_recipient_by_criticality() {
515 #shellcheck disable=SC2153
516 { [ -z "${FLEEP_SERVER}" ] || [ -z "${FLEEP_SENDER}" ]; } && SEND_FLEEP="NO"
517
518 +# check dynatrace
519 +{ [ -z "${DYNATRACE_SPACE}" ] ||
520 + [ -z "${DYNATRACE_SERVER}" ] ||
521 + [ -z "${DYNATRACE_TOKEN}" ] ||
522 + [ -z "${DYNATRACE_TAG_VALUE}" ] ||
523 + [ -z "${DYNATRACE_EVENT}" ]; } && SEND_DYNATRACE="NO"
524 +
525 +
526 if [ "${SEND_PUSHOVER}" = "YES" ] ||
527 [ "${SEND_SLACK}" = "YES" ] ||
528 [ "${SEND_ROCKETCHAT}" = "YES" ] ||
@@ -521,7 +541,8 @@ if [ "${SEND_PUSHOVER}" = "YES" ] ||
541 [ "${SEND_PROWL}" = "YES" ] ||
542 [ "${SEND_HANGOUTS}" = "YES" ] ||
543 [ "${SEND_CUSTOM}" = "YES" ] ||
524 - [ "${SEND_MSTEAM}" = "YES" ]; then
544 + [ "${SEND_MSTEAM}" = "YES" ] ||
545 + [ "${SEND_DYNATRACE}" = "YES" ]; then
546 # if we need curl, check for the curl command
547 if [ -z "${curl}" ]; then
548 curl="$(command -v curl 2>/dev/null)"
@@ -547,6 +568,7 @@ if [ "${SEND_PUSHOVER}" = "YES" ] ||
568 SEND_PROWL="NO"
569 SEND_HANGOUTS="NO"
570 SEND_CUSTOM="NO"
571 + SEND_DYNATRACE="NO"
572 fi
573 fi
574
@@ -673,7 +695,9 @@ for method in "${SEND_EMAIL}" \
695 "${SEND_AWSSNS}" \
696 "${SEND_SYSLOG}" \
697 "${SEND_SMS}" \
676 - "${SEND_MSTEAM}"; do
698 + "${SEND_MSTEAM}" \
699 + "${SEND_DYNATRACE}"; do
700 +
701 if [ "${method}" == "YES" ]; then
702 proceed=1
703 break
@@ -1887,6 +1911,53 @@ EOF
1911
1912 return 1
1913 }
1914 +# -----------------------------------------------------------------------------
1915 +# Dynatrace sender
1916 +send_dynatrace() {
1917 + [ "${SEND_DYNATRACE}" != "YES" ] && return 1
1918 +
1919 + local dynatrace_url="${DYNATRACE_SERVER}/e/${DYNATRACE_SPACE}/api/v1/events"
1920 + local description="NetData Notification for: ${host} ${chart}.${name} is ${status}"
1921 + local payload=""
1922 +
1923 + payload=$(cat <<EOF
1924 +{
1925 + "title": "NetData Alarm from ${host}",
1926 + "source" : "${DYNATRACE_ANNOTATION_TYPE}",
1927 + "description" : "${description}",
1928 + "eventType": "${DYNATRACE_EVENT}",
1929 + "attachRules":{
1930 + "tagRule":[{
1931 + "meTypes":["HOST"],
1932 + "tags":["${DYNATRACE_TAG_VALUE}"]
1933 + }]
1934 + },
1935 + "customProperties":{
1936 + "description": "${description}"
1937 + }
1938 +}
1939 +EOF
1940 +)
1941 +
1942 + # echo ${payload}
1943 +
1944 + httpcode=$(docurl -X POST -H "Authorization: Api-token ${DYNATRACE_TOKEN}" -H "Content-Type: application/json" -d "${payload}" ${dynatrace_url})
1945 + ret=$?
1946 +
1947 +
1948 + if [ ${ret} -eq 0 ]; then
1949 + if [ "${httpcode}" = "200" ]; then
1950 + info "sent ${DYNATRACE_EVENT} to ${DYNATRACE_SERVER}"
1951 + return 0
1952 + else
1953 + warning "Dynatrace ${DYNATRACE_SERVER} responded ${httpcode} notification for: ${host} ${chart}.${name} is ${status} was not sent!"
1954 + return 1
1955 + fi
1956 + else
1957 + error "failed to sent ${DYNATRACE_EVENT} notification for: ${host} ${chart}.${name} is ${status} to ${DYNATRACE_SERVER} with error code ${ret}."
1958 + return 1
1959 + fi
1960 +}
1961
1962 # -----------------------------------------------------------------------------
1963 # prepare the content of the notification
@@ -2391,6 +2462,12 @@ fi
2462
2463 SENT_EMAIL=$?
2464
2465 +# -----------------------------------------------------------------------------
2466 +# send the EVENT to Dynatrace
2467 +send_dynatrace "${host}" "${chart}" "${name}" "${status}"
2468 +SENT_DYNATRACE=$?
2469 +
2470 +
2471 # -----------------------------------------------------------------------------
2472 # let netdata know
2473 for state in "${SENT_EMAIL}" \
@@ -2416,7 +2493,8 @@ for state in "${SENT_EMAIL}" \
2493 "${SENT_AWSSNS}" \
2494 "${SENT_SYSLOG}" \
2495 "${SENT_SMS}" \
2419 - "${SENT_MSTEAM}"; do
2496 + "${SENT_MSTEAM}" \
2497 + "${SENT_DYNATRACE}"; do
2498 if [ "${state}" -eq 0 ]; then
2499 # we sent something
2500 exit 0
health/notifications/dynatrace/Makefile.inc new
+12
@@ -0,0 +1,12 @@
1 +# SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +# THIS IS NOT A COMPLETE Makefile
4 +# IT IS INCLUDED BY ITS PARENT'S Makefile.am
5 +# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT
6 +
7 +# install these files
8 +dist_noinst_DATA += \
9 + dynatrace/README.md \
10 + dynatrace/Makefile.inc \
11 + $(NULL)
12 +
health/notifications/dynatrace/README.md new
+36
@@ -0,0 +1,36 @@
1 +<!--
2 +---
3 +title: "Dynatrace"
4 +custom_edit_url: https://github.com/netdata/netdata/edit/master/health/notifications/dynatrace/README.md
5 +---
6 +-->
7 +
8 +# Dynatrace
9 +
10 +Dynatrace allows you to receive notifications using their Events REST API.
11 +
12 +See [the Dynatrace documentation](https://www.dynatrace.com/support/help/extend-dynatrace/dynatrace-api/environment-api/events/post-event/) about POSTing an event in the Events API for more details.
13 +
14 +
15 +
16 +You need:
17 +
18 +1. Dynatrace Server. You can use the same on all your Netdata servers but make sure the server is network visible from your Netdata hosts.
19 +The Dynatrace server should be with protocol prefixed (`http://` or `https://`). For example: `https://monitor.example.com`
20 +This is a required parameter.
21 +2. API Token. Generate a secure access API token that enables access to your Dynatrace monitoring data via the REST-based API.
22 +Generate a Dynatrace API authentication token. On your Dynatrace server, go to **Settings** --> **Integration** --> **Dynatrace API** --> **Generate token**.
23 +See [Dynatrace API - Authentication](https://www.dynatrace.com/support/help/extend-dynatrace/dynatrace-api/basics/dynatrace-api-authentication/) for more details.
24 +This is a required parameter.
25 +3. API Space. This is the URL part of the page you have access in order to generate the API Token. For example, for my generated API Token the URL is:
26 +https://monitor.illumineit.com/e/2a93fe0e-4cd5-469a-9d0d-1a064235cfce/#settings/integration/apikeys;gf=all
27 +In that case, my space is _2a93fe0e-4cd5-469a-9d0d-1a064235cfce_
28 +This is a required parameter.
29 +4. Generate a Server Tag. On your Dynatrace Server, go to **Settings** --> **Tags** --> **Manually applied tags** and create the Tag.
30 +The Netdata alarm is sent as a Dynatrace Event to be correlated with all those hosts tagged with this Tag you have created.
31 +This is a required parameter.
32 +5. Specify the Dynatrace event. This can be one of `CUSTOM_INFO`, `CUSTOM_ANNOTATION`, `CUSTOM_CONFIGURATION`, and `CUSTOM_DEPLOYMENT`.
33 +The default value is `CUSTOM_INFO`.
34 +This is a required parameter.
35 +6. Specify the annotation type. This is the source of the Dynatrace event. Put whatever it fits you, for example,
36 +_Netdata Alarm_, which is also the default value.
health/notifications/health_alarm_notify.conf
+43 -1
@@ -229,6 +229,43 @@ DEFAULT_RECIPIENT_EMAIL="root"
229 # to not send HTML but Plain Text only emails.
230 #EMAIL_PLAINTEXT_ONLY="YES"
231
232 +#------------------------------------------------------------------------------
233 +# Dynatrace global notification options
234 +#------------------------------------------------------------------------------
235 +# enable/disable sending Dynatrace notifications
236 +SEND_DYNATRACE="YES"
237 +
238 +# The Dynatrace server with protocol prefix (http:// or https://), example https://monitor.illumineit.com
239 +# Required
240 +DYNATRACE_SERVER=""
241 +
242 +# Generate a Dynatrace API authentication token
243 +# Read https://www.dynatrace.com/support/help/extend-dynatrace/dynatrace-api/basics/dynatrace-api-authentication/
244 +# On Dynatrace server goto Settings --> Integration --> Dynatrace API --> Generate token
245 +# Required
246 +DYNATRACE_TOKEN=""
247 +
248 +# Beware: Space is taken from dynatrace URL from browser when you create the TOKEN
249 +# Required
250 +DYNATRACE_SPACE=""
251 +
252 +# Generate a Server Tag. On the Dynatrace Server go to Settings --> Tags --> Manually applied tags create the Tag
253 +# The NetData alarm will be sent as a Dynatrace Event to be correlated with all those hosts tagged with this Tag
254 +# you created.
255 +# Required
256 +DYNATRACE_TAG_VALUE=""
257 +
258 +# Change this to what you want
259 +DYNATRACE_ANNOTATION_TYPE="NetData Alarm"
260 +
261 +# This can be CUSTOM_INFO, CUSTOM_ANNOTATION, CUSTOM_CONFIGURATION, CUSTOM_DEPLOYMENT
262 +# Applying default value
263 +# Required
264 +DYNATRACE_EVENT="CUSTOM_INFO"
265 +
266 +
267 +DEFAULT_RECIPIENT_DYNATRACE=""
268 +
269 #------------------------------------------------------------------------------
270 # hangouts (google hangouts chat) global notification options
271
@@ -873,6 +910,7 @@ role_recipients_msteam[sysadmin]="${DEFAULT_RECIPIENT_MSTEAM}"
910
911 role_recipients_rocketchat[sysadmin]="${DEFAULT_RECIPIENT_ROCKETCHAT}"
912
913 +role_recipients_dynatrace[sysadmin]="${DEFAULT_RECIPIENT_DYNATRACE}"
914 # -----------------------------------------------------------------------------
915 # DNS related alarms
916
@@ -922,6 +960,7 @@ role_recipients_rocketchat[domainadmin]="${DEFAULT_RECIPIENT_ROCKETCHAT}"
960
961 role_recipients_sms[domainadmin]="${DEFAULT_RECIPIENT_SMS}"
962
963 +role_recipients_dynatrace[domainadmin]="${DEFAULT_RECIPIENT_DYNATRACE}"
964 # -----------------------------------------------------------------------------
965 # database servers alarms
966 # mysql, redis, memcached, postgres, etc
@@ -972,6 +1011,7 @@ role_recipients_rocketchat[dba]="${DEFAULT_RECIPIENT_ROCKETCHAT}"
1011
1012 role_recipients_sms[dba]="${DEFAULT_RECIPIENT_SMS}"
1013
1014 +role_recipients_dynatrace[dba]="${DEFAULT_RECIPIENT_DYNATRACE}"
1015 # -----------------------------------------------------------------------------
1016 # web servers alarms
1017 # apache, nginx, lighttpd, etc
@@ -1022,6 +1062,7 @@ role_recipients_rocketchat[webmaster]="${DEFAULT_RECIPIENT_ROCKETCHAT}"
1062
1063 role_recipients_sms[webmaster]="${DEFAULT_RECIPIENT_SMS}"
1064
1065 +role_recipients_dynatrace[webmaster]="${DEFAULT_RECIPIENT_DYNATRACE}"
1066 # -----------------------------------------------------------------------------
1067 # proxy servers alarms
1068 # squid, etc
@@ -1072,7 +1113,7 @@ role_recipients_rocketchat[proxyadmin]="${DEFAULT_RECIPIENT_ROCKETCHAT}"
1113
1114 role_recipients_sms[proxyadmin]="${DEFAULT_RECIPIENT_SMS}"
1115
1075 -
1116 +role_recipients_dynatrace[proxyadmin]="${DEFAULT_RECIPIENT_DYNATRACE}"
1117 # -----------------------------------------------------------------------------
1118 # peripheral devices
1119 # UPS, photovoltaics, etc
@@ -1121,3 +1162,4 @@ role_recipients_rocketchat[sitemgr]="${DEFAULT_RECIPIENT_ROCKETCHAT}"
1162
1163 role_recipients_sms[sitemgr]="${DEFAULT_RECIPIENT_SMS}"
1164
1165 +role_recipients_dynatrace[sitemgr]="${DEFAULT_RECIPIENT_DYNATRACE}"
\ No newline at end of file
libnetdata/config/appconfig.c
+2 -1
@@ -547,7 +547,8 @@ int appconfig_load(struct config *root, char *filename, int overwrite_used, cons
547 s++;
548
549 if (is_exporter_config) {
550 - global_exporting_section = !(strcmp(s, CONFIG_SECTION_EXPORTING));
550 + global_exporting_section =
551 + !(strcmp(s, CONFIG_SECTION_EXPORTING)) || !(strcmp(s, CONFIG_SECTION_PROMETHEUS));
552 if (unlikely(!global_exporting_section)) {
553 int rc;
554 rc = is_valid_connector(s, 0);
libnetdata/config/appconfig.h
+13 -12
@@ -82,18 +82,19 @@
82
83 #define CONFIG_FILENAME "netdata.conf"
84
85 -#define CONFIG_SECTION_GLOBAL "global"
86 -#define CONFIG_SECTION_WEB "web"
87 -#define CONFIG_SECTION_STATSD "statsd"
88 -#define CONFIG_SECTION_PLUGINS "plugins"
89 -#define CONFIG_SECTION_CLOUD "cloud"
90 -#define CONFIG_SECTION_REGISTRY "registry"
91 -#define CONFIG_SECTION_HEALTH "health"
92 -#define CONFIG_SECTION_BACKEND "backend"
93 -#define CONFIG_SECTION_STREAM "stream"
94 -#define CONFIG_SECTION_EXPORTING "exporting:global"
95 -#define CONFIG_SECTION_HOST_LABEL "host labels"
96 -#define EXPORTING_CONF "exporting.conf"
85 +#define CONFIG_SECTION_GLOBAL "global"
86 +#define CONFIG_SECTION_WEB "web"
87 +#define CONFIG_SECTION_STATSD "statsd"
88 +#define CONFIG_SECTION_PLUGINS "plugins"
89 +#define CONFIG_SECTION_CLOUD "cloud"
90 +#define CONFIG_SECTION_REGISTRY "registry"
91 +#define CONFIG_SECTION_HEALTH "health"
92 +#define CONFIG_SECTION_BACKEND "backend"
93 +#define CONFIG_SECTION_STREAM "stream"
94 +#define CONFIG_SECTION_EXPORTING "exporting:global"
95 +#define CONFIG_SECTION_PROMETHEUS "prometheus:exporter"
96 +#define CONFIG_SECTION_HOST_LABEL "host labels"
97 +#define EXPORTING_CONF "exporting.conf"
98
99 // these are used to limit the configuration names and values lengths
100 // they are not enforced by config.c functions (they will strdup() all strings, no matter of their length)
packaging/installer/install-required-packages.sh
+4 -2
@@ -192,7 +192,7 @@ get_os_release() {
192 eval "$(grep -E "^(NAME|ID|ID_LIKE|VERSION|VERSION_ID)=" "${os_release_file}")"
193 for x in "${ID}" ${ID_LIKE}; do
194 case "${x,,}" in
195 - alpine | arch | centos | debian | fedora | gentoo | sabayon | rhel | ubuntu | suse | opensuse-leap | sles | clear-linux-os)
195 + alpine | arch | centos | clear-linux-os | debian | fedora | gentoo | manjaro | opensuse-leap | rhel | sabayon | sles | suse | ubuntu)
196 distribution="${x}"
197 version="${VERSION_ID}"
198 codename="${VERSION}"
@@ -1047,7 +1047,9 @@ declare -A pkg_zip=(
1047 )
1048
1049 validate_package_trees() {
1050 - validate_tree_${tree}
1050 + if type -t validate_tree_${tree} > /dev/null; then
1051 + validate_tree_${tree}
1052 + fi
1053 }
1054
1055 validate_installed_package() {
packaging/installer/methods/macos.md
+1 -1
@@ -75,7 +75,7 @@ sudo ./netdata-installer.sh --install /usr/local
75 > Your Netdata configuration directory will be at `/usr/local/netdata/`, and your stock configuration directory will
76 > be at **`/usr/local/lib/netdata/conf.d/`.**
77 >
78 -> The installer will also install a startup plist to start Netdata when your Mac boots.
78 +> The installer will also install a startup plist to start Netdata when your macOS system boots.
79
80 ## What's next?
81
packaging/maintainers/README.md
+3 -2
@@ -1,6 +1,7 @@
1 <!--
2 ---
3 title: "Package Maintainers"
4 +date: 2020-03-31
5 custom_edit_url: https://github.com/netdata/netdata/edit/master/packaging/maintainers/README.md
6 ---
7 -->
@@ -36,11 +37,11 @@ This page tracks the package maintainers for Netdata, for various operating syst
37
38 ---
39
39 -## MacOS
40 +## macOS
41
42 | System | URL | Core Developer | Package Maintainer
43 |:-:|:-:|:-:|:-:|
43 -| MacOS Homebrew Formula|[link](https://github.com/Homebrew/homebrew-core/blob/master/Formula/netdata.rb)|@vlvkobal|@rickard-von-essen
44 +| macOS Homebrew Formula|[link](https://github.com/Homebrew/homebrew-core/blob/master/Formula/netdata.rb)|@vlvkobal|@rickard-von-essen
45
46 ---
47