@cryptotaxi247 / netdata-1 / commits / 77781d033

Prometheus remote write backend (#6062)

* Add Prometheus remote write backend prototype * Fix autotools issues * Send HTTP POST request * Add parameters to HTTP header * Discard HTTP responce 200 * Update CMake build configuration * Fix Codacy issue * Check for C++ binary * Fix compilation without remote write backend * Add options to the installer script * Fix configure script warning * Fix make dist * Downgrade to ByteSize for better compatibility * Integrate remote write more tightly into the existing backends code * Cleanup * Fix build error * Parse host tags * Fix Codacy issue * Fix counters for buffered data * Rename preprocessor symbol * Better error handling * Cleanup * Update the documentation

Vladimir Kobal committed Jun 7, 2019 at 11:48 UTC 77781d033da95d91e00970572e0abf95946907af
20 files changed +732 -34
.gitignore
+4
@@ -59,6 +59,10 @@ xenstat.plugin
59 cgroup-network
60 !cgroup-network/
61
62 +# protoc generated files
63 +*.pb.cc
64 +*.pb.h
65 +
66 # installation artifacts
67 packaging/installer/.environment.sh
68 *.tar.*
CMakeLists.txt
+50 -1
@@ -241,6 +241,27 @@ find_library(HAVE_KINESIS aws-cpp-sdk-kinesis)
241 # later we use:
242 # ${HAVE_KINESIS}
243
244 +
245 +# -----------------------------------------------------------------------------
246 +# Detect libprotobuf
247 +
248 +pkg_check_modules(PROTOBUF protobuf)
249 +# later we use:
250 +# ${PROTOBUF_LIBRARIES}
251 +# ${PROTOBUF_CFLAGS_OTHER}
252 +# ${PROTOBUF_INCLUDE_DIRS}
253 +
254 +
255 +# -----------------------------------------------------------------------------
256 +# Detect libsnappy
257 +
258 +pkg_check_modules(SNAPPY snappy)
259 +# later we use:
260 +# ${SNAPPY_LIBRARIES}
261 +# ${SNAPPY_CFLAGS_OTHER}
262 +# ${SNAPPY_INCLUDE_DIRS}
263 +
264 +
265 # -----------------------------------------------------------------------------
266 # netdata files
267
@@ -547,6 +568,11 @@ set(KINESIS_BACKEND_FILES
568 backends/aws_kinesis/aws_kinesis_put_record.h
569 )
570
571 +set(PROMETHEUS_REMOTE_WRITE_BACKEND_FILES
572 + backends/prometheus/remote_write/remote_write.cc
573 + backends/prometheus/remote_write/remote_write.h
574 + )
575 +
576 set(DAEMON_FILES
577 daemon/common.c
578 daemon/common.h
@@ -611,6 +637,29 @@ ELSE()
637 message(STATUS "kinesis backend: disabled (requires AWS SDK for C++)")
638 ENDIF()
639
640 +# -----------------------------------------------------------------------------
641 +# prometheus remote write backend
642 +
643 +IF(PROTOBUF_LIBRARIES AND SNAPPY_LIBRARIES)
644 + SET(ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE True)
645 +ELSE()
646 + SET(ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE False)
647 +ENDIF()
648 +
649 +IF(ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE)
650 + message(STATUS "prometheus remote write backend: enabled")
651 +
652 + find_package(Protobuf REQUIRED)
653 + protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS backends/prometheus/remote_write/remote_write.proto)
654 +
655 + list(APPEND NETDATA_FILES ${PROMETHEUS_REMOTE_WRITE_BACKEND_FILES} ${PROTO_SRCS} ${PROTO_HDRS})
656 + list(APPEND NETDATA_COMMON_LIBRARIES ${PROTOBUF_LIBRARIES} ${SNAPPY_LIBRARIES})
657 + list(APPEND NETDATA_COMMON_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS} ${SNAPPY_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
658 + list(APPEND NETDATA_COMMON_CFLAGS ${PROTOBUF_CFLAGS_OTHER} ${SNAPPY_CFLAGS_OTHER})
659 +ELSE()
660 + message(STATUS "prometheus remote write backend: disabled (requires protobuf and snappy libraries)")
661 +ENDIF()
662 +
663 # -----------------------------------------------------------------------------
664 # netdata
665
@@ -648,7 +697,7 @@ ELSEIF(MACOS)
697
698 ENDIF()
699
651 -IF(ENABLE_BACKEND_KINESIS)
700 +IF(ENABLE_BACKEND_KINESIS OR ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE)
701 set_property(TARGET netdata PROPERTY CXX_STANDARD 11)
702 set_property(TARGET netdata PROPERTY CMAKE_CXX_STANDARD_REQUIRED ON)
703 ENDIF()
Makefile.am
+22 -2
@@ -441,6 +441,12 @@ KINESIS_BACKEND_FILES = \
441 backends/aws_kinesis/aws_kinesis_put_record.h \
442 $(NULL)
443
444 +PROMETHEUS_REMOTE_WRITE_BACKEND_FILES = \
445 + backends/prometheus/remote_write/remote_write.cc \
446 + backends/prometheus/remote_write/remote_write.h \
447 + backends/prometheus/remote_write/remote_write.proto \
448 + $(NULL)
449 +
450 DAEMON_FILES = \
451 daemon/common.c \
452 daemon/common.h \
@@ -505,14 +511,13 @@ NETDATA_COMMON_LIBS = \
511 $(OPTIONAL_JUDY_LIBS) \
512 $(OPTIONAL_SSL_LIBS) \
513 $(NULL)
508 -# TODO: Find more graceful way to add libs for AWS Kinesis
514
515 sbin_PROGRAMS += netdata
516 netdata_SOURCES = $(NETDATA_FILES)
517 netdata_LDADD = \
518 $(NETDATA_COMMON_LIBS) \
519 $(NULL)
515 -if ENABLE_BACKEND_KINESIS
520 +if ENABLE_CXX_LINKER
521 netdata_LINK = $(CXXLD) $(CXXFLAGS) $(LDFLAGS) -o $@
522 else
523 netdata_LINK = $(CCLD) $(CFLAGS) $(LDFLAGS) -o $@
@@ -575,3 +580,18 @@ if ENABLE_BACKEND_KINESIS
580 netdata_SOURCES += $(KINESIS_BACKEND_FILES)
581 netdata_LDADD += $(OPTIONAL_KINESIS_LIBS)
582 endif
583 +
584 +if ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE
585 + netdata_SOURCES += $(PROMETHEUS_REMOTE_WRITE_BACKEND_FILES)
586 + netdata_LDADD += $(OPTIONAL_PROMETHEUS_REMOTE_WRITE_LIBS)
587 + BUILT_SOURCES = \
588 + backends/prometheus/remote_write/remote_write.pb.cc \
589 + backends/prometheus/remote_write/remote_write.pb.h \
590 + $(NULL)
591 + nodist_netdata_SOURCES = $(BUILT_SOURCES)
592 +
593 +backends/prometheus/remote_write/remote_write.pb.cc \
594 +backends/prometheus/remote_write/remote_write.pb.h: backends/prometheus/remote_write/remote_write.proto
595 + $(PROTOC) --proto_path=$(srcdir) --cpp_out=$(builddir) $^
596 +
597 +endif
backends/README.md
+7 -1
@@ -32,6 +32,12 @@ X seconds (though, it can send them per second if you need it to).
32
33 - **prometheus** is described at [prometheus page](prometheus/) since it pulls data from netdata.
34
35 + - **prometheus remote write** (a binary snappy-compressed protocol buffer encoding over HTTP used by
36 + a lot of [storage providers](https://prometheus.io/docs/operating/integrations/#remote-endpoints-and-storage))
37 +
38 + metrics are labeled in the format, which is used by Netdata for the [plaintext prometheus protocol](prometheus/).
39 + Notes on using the remote write backend are [here](prometheus/remote_write/).
40 +
41 - **AWS Kinesis Data Streams**
42
43 metrics are sent to the service in `JSON` format.
@@ -70,7 +76,7 @@ of `netdata.conf` from your netdata):
76 ```
77 [backend]
78 enabled = yes | no
73 - type = graphite | opentsdb | json | kinesis
79 + type = graphite | opentsdb | json | prometheus_remote_write | kinesis
80 host tags = list of TAG=VALUE
81 destination = space separated list of [PROTOCOL:]HOST[:PORT] - the first working will be used, or a region for kinesis
82 data source = average | sum | as collected
backends/backends.c
+123 -21
@@ -260,6 +260,12 @@ void *backends_main(void *ptr) {
260 char *kinesis_auth_key_id = NULL, *kinesis_secure_key = NULL, *kinesis_stream_name = NULL;
261 #endif
262
263 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
264 + int do_prometheus_remote_write = 0;
265 + BUFFER *http_request_header = buffer_create(1);
266 +#endif
267 +
268 +
269 // ------------------------------------------------------------------------
270 // collect configuration options
271
@@ -285,6 +291,10 @@ void *backends_main(void *ptr) {
291 charts_pattern = simple_pattern_create(config_get(CONFIG_SECTION_BACKEND, "send charts matching", "*"), NULL, SIMPLE_PATTERN_EXACT);
292 hosts_pattern = simple_pattern_create(config_get(CONFIG_SECTION_BACKEND, "send hosts matching", "localhost *"), NULL, SIMPLE_PATTERN_EXACT);
293
294 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
295 + const char *remote_write_path = config_get(CONFIG_SECTION_BACKEND, "remote write URL path", "/receive");
296 +#endif
297 +
298 // ------------------------------------------------------------------------
299 // validate configuration options
300 // and prepare for sending data to our backend
@@ -337,9 +347,8 @@ void *backends_main(void *ptr) {
347 backend_request_formatter = format_dimension_stored_json_plaintext;
348
349 }
340 -#if HAVE_KINESIS
350 else if (!strcmp(type, "kinesis") || !strcmp(type, "kinesis:plaintext")) {
342 -
351 +#if HAVE_KINESIS
352 do_kinesis = 1;
353
354 if(unlikely(read_kinesis_conf(netdata_configured_user_config_dir, &kinesis_auth_key_id, &kinesis_secure_key, &kinesis_stream_name))) {
@@ -354,15 +363,31 @@ void *backends_main(void *ptr) {
363 backend_request_formatter = format_dimension_collected_json_plaintext;
364 else
365 backend_request_formatter = format_dimension_stored_json_plaintext;
366 +#else
367 + error("AWS Kinesis support isn't compiled");
368 +#endif /* HAVE_KINESIS */
369 + }
370 + else if (!strcmp(type, "prometheus_remote_write")) {
371 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
372 + do_prometheus_remote_write = 1;
373
374 + backend_response_checker = process_prometheus_remote_write_response;
375 +
376 + init_write_request();
377 +#else
378 + error("Prometheus remote write support isn't compiled");
379 +#endif /* ENABLE_PROMETHEUS_REMOTE_WRITE */
380 }
359 -#endif /* HAVE_KINESIS */
381 else {
382 error("BACKEND: Unknown backend type '%s'", type);
383 goto cleanup;
384 }
385
386 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
387 + if((backend_request_formatter == NULL && !do_prometheus_remote_write) || backend_response_checker == NULL) {
388 +#else
389 if(backend_request_formatter == NULL || backend_response_checker == NULL) {
390 +#endif
391 error("BACKEND: backend is misconfigured - disabling it.");
392 goto cleanup;
393 }
@@ -451,6 +476,9 @@ void *backends_main(void *ptr) {
476 size_t count_charts_total = 0;
477 size_t count_dims_total = 0;
478
479 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
480 + clear_write_request();
481 +#endif
482 rrd_rdlock();
483 RRDHOST *host;
484 rrdhost_foreach_read(host) {
@@ -478,26 +506,45 @@ void *backends_main(void *ptr) {
506
507 const char *__hostname = (host == localhost)?hostname:host->hostname;
508
481 - RRDSET *st;
482 - rrdset_foreach_read(st, host) {
483 - if(likely(backends_can_send_rrdset(global_backend_options, st))) {
484 - rrdset_rdlock(st);
485 -
486 - count_charts++;
487 -
488 - RRDDIM *rd;
489 - rrddim_foreach_read(rd, st) {
490 - if (likely(rd->last_collected_time.tv_sec >= after)) {
491 - chart_buffered_metrics += backend_request_formatter(b, global_backend_prefix, host, __hostname, st, rd, after, before, global_backend_options);
492 - count_dims++;
493 - }
494 - else {
495 - debug(D_BACKEND, "BACKEND: not sending dimension '%s' of chart '%s' from host '%s', its last data collection (%lu) is not within our timeframe (%lu to %lu)", rd->id, st->id, __hostname, (unsigned long)rd->last_collected_time.tv_sec, (unsigned long)after, (unsigned long)before);
496 - count_dims_skipped++;
509 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
510 + if(do_prometheus_remote_write) {
511 + rrd_stats_remote_write_allmetrics_prometheus(
512 + host
513 + , __hostname
514 + , global_backend_prefix
515 + , global_backend_options
516 + , after
517 + , before
518 + , &count_charts
519 + , &count_dims
520 + , &count_dims_skipped
521 + );
522 + chart_buffered_metrics += count_dims;
523 + }
524 + else
525 +#endif
526 + {
527 + RRDSET *st;
528 + rrdset_foreach_read(st, host) {
529 + if(likely(backends_can_send_rrdset(global_backend_options, st))) {
530 + rrdset_rdlock(st);
531 +
532 + count_charts++;
533 +
534 + RRDDIM *rd;
535 + rrddim_foreach_read(rd, st) {
536 + if (likely(rd->last_collected_time.tv_sec >= after)) {
537 + chart_buffered_metrics += backend_request_formatter(b, global_backend_prefix, host, __hostname, st, rd, after, before, global_backend_options);
538 + count_dims++;
539 + }
540 + else {
541 + debug(D_BACKEND, "BACKEND: not sending dimension '%s' of chart '%s' from host '%s', its last data collection (%lu) is not within our timeframe (%lu to %lu)", rd->id, st->id, __hostname, (unsigned long)rd->last_collected_time.tv_sec, (unsigned long)after, (unsigned long)before);
542 + count_dims_skipped++;
543 + }
544 }
498 - }
545
500 - rrdset_unlock(st);
546 + rrdset_unlock(st);
547 + }
548 }
549 }
550
@@ -672,6 +719,43 @@ void *backends_main(void *ptr) {
719 flags += MSG_NOSIGNAL;
720 #endif
721
722 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
723 + if(do_prometheus_remote_write) {
724 + size_t data_size = get_write_request_size();
725 +
726 + if(unlikely(!data_size)) {
727 + error("BACKEND: write request size is out of range");
728 + continue;
729 + }
730 +
731 + buffer_flush(b);
732 + buffer_need_bytes(b, data_size);
733 + if(unlikely(pack_write_request(b->buffer, &data_size))) {
734 + error("BACKEND: cannot pack write request");
735 + continue;
736 + }
737 + b->len = data_size;
738 + chart_buffered_bytes = (collected_number)buffer_strlen(b);
739 +
740 + buffer_flush(http_request_header);
741 + buffer_sprintf(http_request_header,
742 + "POST %s HTTP/1.1\r\n"
743 + "Host: %s\r\n"
744 + "Accept: */*\r\n"
745 + "Content-Length: %zu\r\n"
746 + "Content-Type: application/x-www-form-urlencoded\r\n\r\n",
747 + remote_write_path,
748 + hostname,
749 + data_size
750 + );
751 +
752 + len = buffer_strlen(http_request_header);
753 + send(sock, buffer_tostring(http_request_header), len, flags);
754 +
755 + len = data_size;
756 + }
757 +#endif
758 +
759 ssize_t written = send(sock, buffer_tostring(b), len, flags);
760 // chart_backend_latency += now_monotonic_usec() - start_ut;
761 if(written != -1 && (size_t)written == len) {
@@ -711,6 +795,16 @@ void *backends_main(void *ptr) {
795 }
796 }
797
798 +
799 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
800 + if(failures) {
801 + (void) buffer_on_failures;
802 + failures = 0;
803 + chart_lost_bytes = chart_buffered_bytes = get_write_request_size(); // estimated write request size
804 + chart_data_lost_events++;
805 + chart_lost_metrics = chart_buffered_metrics;
806 + }
807 +#else
808 if(failures > buffer_on_failures) {
809 // too bad! we are going to lose data
810 chart_lost_bytes += buffer_strlen(b);
@@ -720,6 +814,7 @@ void *backends_main(void *ptr) {
814 chart_data_lost_events++;
815 chart_lost_metrics = chart_buffered_metrics;
816 }
817 +#endif /* ENABLE_PROMETHEUS_REMOTE_WRITE */
818
819 if(unlikely(netdata_exit)) break;
820
@@ -775,6 +870,13 @@ cleanup:
870 }
871 #endif
872
873 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
874 + if(do_prometheus_remote_write) {
875 + buffer_free(http_request_header);
876 + protocol_buffers_shutdown();
877 + }
878 +#endif
879 +
880 if(sock != -1)
881 close(sock);
882
backends/backends.h
+4
@@ -53,4 +53,8 @@ extern int discard_response(BUFFER *b, const char *backend);
53 #include "backends/aws_kinesis/aws_kinesis.h"
54 #endif
55
56 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
57 +#include "backends/prometheus/remote_write/remote_write.h"
58 +#endif
59 +
60 #endif /* NETDATA_BACKENDS_H */
backends/prometheus/Makefile.am
+4
@@ -3,6 +3,10 @@
3 AUTOMAKE_OPTIONS = subdir-objects
4 MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
5
6 +SUBDIRS = \
7 + remote_write \
8 + $(NULL)
9 +
10 dist_noinst_DATA = \
11 README.md \
12 $(NULL)
backends/prometheus/backend_prometheus.c
+197 -1
@@ -153,6 +153,8 @@ static inline char *prometheus_units_copy(char *d, const char *s, size_t usable,
153 #define PROMETHEUS_LABELS_MAX 1024
154 #define PROMETHEUS_VARIABLE_MAX 256
155
156 +#define PROMETHEUS_LABELS_MAX_NUMBER 128
157 +
158 struct host_variables_callback_options {
159 RRDHOST *host;
160 BUFFER *wb;
@@ -307,7 +309,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER
309 int as_collected = (BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AS_COLLECTED);
310 int homogeneous = 1;
311 if(as_collected) {
310 - if(rrdset_flag_check(st, RRDSET_FLAG_HOMEGENEOUS_CHECK))
312 + if(rrdset_flag_check(st, RRDSET_FLAG_HOMOGENEOUS_CHECK))
313 rrdset_update_heterogeneous_flag(st);
314
315 if(rrdset_flag_check(st, RRDSET_FLAG_HETEROGENEOUS))
@@ -537,6 +539,177 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER
539 rrdhost_unlock(host);
540 }
541
542 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
543 +inline static void remote_write_split_words(char *str, char **words, int max_words) {
544 + char *s = str;
545 + int i = 0;
546 +
547 + while(*s && i < max_words - 1) {
548 + while(*s && isspace(*s)) s++; // skip spaces to the begining of a tag name
549 +
550 + if(*s)
551 + words[i] = s;
552 +
553 + while(*s && !isspace(*s) && *s != '=') s++; // find the end of the tag name
554 +
555 + if(*s != '=') {
556 + words[i] = NULL;
557 + break;
558 + }
559 + *s = '\0';
560 + s++;
561 + i++;
562 +
563 + while(*s && isspace(*s)) s++; // skip spaces to the begining of a tag value
564 +
565 + if(*s && *s == '"') s++; // strip an opening quote
566 + if(*s)
567 + words[i] = s;
568 +
569 + while(*s && !isspace(*s) && *s != ',') s++; // find the end of the tag value
570 +
571 + if(*s && *s != ',') {
572 + words[i] = NULL;
573 + break;
574 + }
575 + if(s != words[i] && *(s - 1) == '"') *(s - 1) = '\0'; // strip a closing quote
576 + if(*s != '\0') {
577 + *s = '\0';
578 + s++;
579 + i++;
580 + }
581 + }
582 +}
583 +
584 +void rrd_stats_remote_write_allmetrics_prometheus(
585 + RRDHOST *host
586 + , const char *__hostname
587 + , const char *prefix
588 + , BACKEND_OPTIONS backend_options
589 + , time_t after
590 + , time_t before
591 + , size_t *count_charts
592 + , size_t *count_dims
593 + , size_t *count_dims_skipped
594 +) {
595 + char hostname[PROMETHEUS_ELEMENT_MAX + 1];
596 + prometheus_label_copy(hostname, __hostname, PROMETHEUS_ELEMENT_MAX);
597 +
598 + add_host_info("netdata_info", hostname, host->program_name, host->program_version, now_realtime_usec() / USEC_PER_MS);
599 +
600 + if(host->tags && *(host->tags)) {
601 + char tags[PROMETHEUS_LABELS_MAX + 1];
602 + strncpy(tags, host->tags, PROMETHEUS_LABELS_MAX);
603 + char *words[PROMETHEUS_LABELS_MAX_NUMBER] = {NULL};
604 + int i;
605 +
606 + remote_write_split_words(tags, words, PROMETHEUS_LABELS_MAX_NUMBER);
607 +
608 + add_host_info("netdata_host_tags_info", hostname, NULL, NULL, now_realtime_usec() / USEC_PER_MS);
609 +
610 + for(i = 0; words[i] != NULL && words[i + 1] != NULL && (i + 1) < PROMETHEUS_LABELS_MAX_NUMBER; i += 2) {
611 + add_tag(words[i], words[i + 1]);
612 + }
613 + }
614 +
615 + // for each chart
616 + RRDSET *st;
617 + rrdset_foreach_read(st, host) {
618 + char chart[PROMETHEUS_ELEMENT_MAX + 1];
619 + char context[PROMETHEUS_ELEMENT_MAX + 1];
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);
626 +
627 + if(likely(backends_can_send_rrdset(backend_options, st))) {
628 + rrdset_rdlock(st);
629 +
630 + (*count_charts)++;
631 +
632 + int as_collected = (BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AS_COLLECTED);
633 + int homogeneous = 1;
634 + if(as_collected) {
635 + if(rrdset_flag_check(st, RRDSET_FLAG_HOMOGENEOUS_CHECK))
636 + rrdset_update_heterogeneous_flag(st);
637 +
638 + if(rrdset_flag_check(st, RRDSET_FLAG_HETEROGENEOUS))
639 + homogeneous = 0;
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);
644 + }
645 +
646 + // for each dimension
647 + RRDDIM *rd;
648 + rrddim_foreach_read(rd, st) {
649 + if(rd->collections_counter && !rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)) {
650 + char name[PROMETHEUS_LABELS_MAX + 1];
651 + char dimension[PROMETHEUS_ELEMENT_MAX + 1];
652 + char *suffix = "";
653 +
654 + if (as_collected) {
655 + // we need as-collected / raw data
656 +
657 + if(unlikely(rd->last_collected_time.tv_sec < after)) {
658 + debug(D_BACKEND, "BACKEND: not sending dimension '%s' of chart '%s' from host '%s', its last data collection (%lu) is not within our timeframe (%lu to %lu)", rd->id, st->id, __hostname, (unsigned long)rd->last_collected_time.tv_sec, (unsigned long)after, (unsigned long)before);
659 + (*count_dims_skipped)++;
660 + continue;
661 + }
662 +
663 + if(homogeneous) {
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);
668 + snprintf(name, PROMETHEUS_LABELS_MAX, "%s_%s%s", prefix, context, suffix);
669 +
670 + add_metric(name, chart, family, dimension, hostname, rd->last_collected_value, timeval_msec(&rd->last_collected_time));
671 + (*count_dims)++;
672 + }
673 + else {
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);
678 + snprintf(name, PROMETHEUS_LABELS_MAX, "%s_%s_%s%s", prefix, context, dimension, suffix);
679 +
680 + add_metric(name, chart, family, NULL, hostname, rd->last_collected_value, timeval_msec(&rd->last_collected_time));
681 + (*count_dims)++;
682 + }
683 + }
684 + else {
685 + // we need average or sum of the data
686 +
687 + time_t first_t = after, last_t = before;
688 + calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, backend_options, &first_t, &last_t);
689 +
690 + if(!isnan(value) && !isinf(value)) {
691 +
692 + if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AVERAGE)
693 + suffix = "_average";
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);
698 + snprintf(name, PROMETHEUS_LABELS_MAX, "%s_%s%s%s", prefix, context, units, suffix);
699 +
700 + add_metric(name, chart, family, dimension, hostname, rd->last_collected_value, timeval_msec(&rd->last_collected_time));
701 + (*count_dims)++;
702 + }
703 + }
704 + }
705 + }
706 +
707 + rrdset_unlock(st);
708 + }
709 + }
710 +}
711 +#endif /* ENABLE_PROMETHEUS_REMOTE_WRITE */
712 +
713 static inline time_t prometheus_preparation(RRDHOST *host, BUFFER *wb, BACKEND_OPTIONS backend_options, const char *server, time_t now, PROMETHEUS_OUTPUT_OPTIONS output_options) {
714 if(!server || !*server) server = "default";
715
@@ -599,3 +772,26 @@ void rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(RRDHOST *host, BUFF
772 }
773 rrd_unlock();
774 }
775 +
776 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
777 +int process_prometheus_remote_write_response(BUFFER *b) {
778 + if(unlikely(!b)) return 1;
779 +
780 + const char *s = buffer_tostring(b);
781 + int len = buffer_strlen(b);
782 +
783 + // do nothing with HTTP response 200
784 +
785 + while(!isspace(*s) && len) {
786 + s++;
787 + len--;
788 + }
789 + s++;
790 + len--;
791 +
792 + if(likely(len > 4 && !strncmp(s, "200 ", 4)))
793 + return 0;
794 + else
795 + return discard_response(b, "prometheus remote write");
796 +}
797 +#endif
backends/prometheus/backend_prometheus.h
+15
@@ -19,4 +19,19 @@ typedef enum prometheus_output_flags {
19 extern void rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(RRDHOST *host, BUFFER *wb, const char *server, const char *prefix, BACKEND_OPTIONS backend_options, PROMETHEUS_OUTPUT_OPTIONS output_options);
20 extern void rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(RRDHOST *host, BUFFER *wb, const char *server, const char *prefix, BACKEND_OPTIONS backend_options, PROMETHEUS_OUTPUT_OPTIONS output_options);
21
22 +#if ENABLE_PROMETHEUS_REMOTE_WRITE
23 +extern void rrd_stats_remote_write_allmetrics_prometheus(
24 + RRDHOST *host
25 + , const char *__hostname
26 + , const char *prefix
27 + , BACKEND_OPTIONS backend_options
28 + , time_t after
29 + , time_t before
30 + , size_t *count_charts
31 + , size_t *count_dims
32 + , size_t *count_dims_skipped
33 +);
34 +extern int process_prometheus_remote_write_response(BUFFER *b);
35 +#endif
36 +
37 #endif //NETDATA_BACKEND_PROMETHEUS_H
backends/prometheus/remote_write/Makefile.am new
+14
@@ -0,0 +1,14 @@
1 +# SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +AUTOMAKE_OPTIONS = subdir-objects
4 +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
5 +
6 +CLEANFILES = \
7 + remote_write.pb.cc \
8 + remote_write.pb.h \
9 + $(NULL)
10 +
11 +dist_noinst_DATA = \
12 + remote_write.proto \
13 + README.md \
14 + $(NULL)
backends/prometheus/remote_write/README.md new
+30
@@ -0,0 +1,30 @@
1 +# Prometheus remote write backend
2 +
3 +## Prerequisites
4 +
5 +To use the prometheus remote write API with [storage providers](https://prometheus.io/docs/operating/integrations/#remote-endpoints-and-storage) [protobuf](https://developers.google.com/protocol-buffers/) and [snappy](https://github.com/google/snappy) libraries should be installed first. Next, netdata should be re-installed from the source. The installer will detect that the required libraries and utilities are now available.
6 +
7 +## Configuration
8 +
9 +An additional option in the backend configuration section is available for the remote write backend:
10 +
11 +```
12 +[backend]
13 + remote write URL path = /receive
14 +```
15 +
16 +The default value is `/receive`. `remote write URL path` is used to set an endpoint path for the remote write protocol. For example, if your endpoint is `http://example.domain:example_port/storage/read` you should set
17 +
18 +```
19 +[backend]
20 + destination = example.domain:example_port
21 + remote write URL path = /storage/read
22 +```
23 +
24 +`buffered` and `lost` dimensions in the Netdata Backend Data Size operation monitoring chart estimate uncompressed buffer size on failures.
25 +
26 +## Notes
27 +
28 +The remote write backend does not support `buffer on failures`
29 +
30 +[![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%2Fbackends%2Fprometheus%2Fremote_write%2FREADME&_u=MAC~&cid=5792dfd7-8dc4-476b-af31-da2fdb9f93d2&tid=UA-64295674-3)]()
backends/prometheus/remote_write/remote_write.cc new
+117
@@ -0,0 +1,117 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include <snappy.h>
4 +#include "remote_write.pb.h"
5 +#include "remote_write.h"
6 +
7 +using namespace prometheus;
8 +
9 +
10 +google::protobuf::Arena arena;
11 +WriteRequest *write_request;
12 +
13 +void init_write_request() {
14 + GOOGLE_PROTOBUF_VERIFY_VERSION;
15 + write_request = google::protobuf::Arena::CreateMessage<WriteRequest>(&arena);
16 +}
17 +
18 +void clear_write_request() {
19 + write_request->clear_timeseries();
20 +}
21 +
22 +void add_host_info(const char *name, const char *instance, const char *application, const char *version, const int64_t timestamp) {
23 + TimeSeries *timeseries;
24 + Sample *sample;
25 + Label *label;
26 +
27 + timeseries = write_request->add_timeseries();
28 +
29 + label = timeseries->add_labels();
30 + label->set_name("__name__");
31 + label->set_value(name);
32 +
33 + label = timeseries->add_labels();
34 + label->set_name("instance");
35 + label->set_value(instance);
36 +
37 + if(application) {
38 + label = timeseries->add_labels();
39 + label->set_name("application");
40 + label->set_value(application);
41 + }
42 +
43 + if(version) {
44 + label = timeseries->add_labels();
45 + label->set_name("version");
46 + label->set_value(version);
47 + }
48 +
49 + sample = timeseries->add_samples();
50 + sample->set_value(1);
51 + sample->set_timestamp(timestamp);
52 +}
53 +
54 +// adds tag to the last created timeseries
55 +void add_tag(char *tag, char *value) {
56 + TimeSeries *timeseries;
57 + Label *label;
58 +
59 + timeseries = write_request->mutable_timeseries(write_request->timeseries_size() - 1);
60 +
61 + label = timeseries->add_labels();
62 + label->set_name(tag);
63 + label->set_value(value);
64 +}
65 +
66 +void add_metric(const char *name, const char *chart, const char *family, const char *dimension, const char *instance, const double value, const int64_t timestamp) {
67 + TimeSeries *timeseries;
68 + Sample *sample;
69 + Label *label;
70 +
71 + timeseries = write_request->add_timeseries();
72 +
73 + label = timeseries->add_labels();
74 + label->set_name("__name__");
75 + label->set_value(name);
76 +
77 + label = timeseries->add_labels();
78 + label->set_name("chart");
79 + label->set_value(chart);
80 +
81 + label = timeseries->add_labels();
82 + label->set_name("family");
83 + label->set_value(family);
84 +
85 + if(dimension) {
86 + label = timeseries->add_labels();
87 + label->set_name("dimension");
88 + label->set_value(dimension);
89 + }
90 +
91 + label = timeseries->add_labels();
92 + label->set_name("instance");
93 + label->set_value(instance);
94 +
95 + sample = timeseries->add_samples();
96 + sample->set_value(value);
97 + sample->set_timestamp(timestamp);
98 +}
99 +
100 +size_t get_write_request_size(){
101 + size_t size = (size_t)snappy::MaxCompressedLength(write_request->ByteSize());
102 +
103 + return (size < INT_MAX)?size:0;
104 +}
105 +
106 +int pack_write_request(char *buffer, size_t *size) {
107 + std::string uncompressed_write_request;
108 + if(write_request->SerializeToString(&uncompressed_write_request) == false) return 1;
109 +
110 + snappy::RawCompress(uncompressed_write_request.data(), uncompressed_write_request.size(), buffer, size);
111 +
112 + return 0;
113 +}
114 +
115 +void protocol_buffers_shutdown() {
116 + google::protobuf::ShutdownProtobufLibrary();
117 +}
backends/prometheus/remote_write/remote_write.h new
+30
@@ -0,0 +1,30 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_BACKEND_PROMETHEUS_REMOTE_WRITE_H
4 +#define NETDATA_BACKEND_PROMETHEUS_REMOTE_WRITE_H
5 +
6 +#ifdef __cplusplus
7 +extern "C" {
8 +#endif
9 +
10 +void init_write_request();
11 +
12 +void clear_write_request();
13 +
14 +void add_host_info(const char *name, const char *instance, const char *application, const char *version, const int64_t timestamp);
15 +
16 +void add_tag(char *tag, char *value);
17 +
18 +void add_metric(const char *name, const char *chart, const char *family, const char *dimension, const char *instance, const double value, const int64_t timestamp);
19 +
20 +size_t get_write_request_size();
21 +
22 +int pack_write_request(char *buffer, size_t *size);
23 +
24 +void protocol_buffers_shutdown();
25 +
26 +#ifdef __cplusplus
27 +}
28 +#endif
29 +
30 +#endif //NETDATA_BACKEND_PROMETHEUS_REMOTE_WRITE_H
backends/prometheus/remote_write/remote_write.proto new
+29
@@ -0,0 +1,29 @@
1 +syntax = "proto3";
2 +package prometheus;
3 +
4 +option cc_enable_arenas = true;
5 +
6 +import "google/protobuf/descriptor.proto";
7 +
8 +message WriteRequest {
9 + repeated TimeSeries timeseries = 1 [(nullable) = false];
10 +}
11 +
12 +message TimeSeries {
13 + repeated Label labels = 1 [(nullable) = false];
14 + repeated Sample samples = 2 [(nullable) = false];
15 +}
16 +
17 +message Label {
18 + string name = 1;
19 + string value = 2;
20 +}
21 +
22 +message Sample {
23 + double value = 1;
24 + int64 timestamp = 2;
25 +}
26 +
27 +extend google.protobuf.FieldOptions {
28 + bool nullable = 65001;
29 +}
configure.ac
+71 -2
@@ -76,7 +76,12 @@ AC_ARG_ENABLE(
76 ,
77 [enable_backend_kinesis="detect"]
78 )
79 -
79 +AC_ARG_ENABLE(
80 + [backend-prometheus-remote-write],
81 + [AS_HELP_STRING([--enable-backend-prometheus-remote-write], [enable prometheus remote write backend @<:@default autodetect@:>@])],
82 + ,
83 + [enable_backend_prometheus_remote_write="detect"]
84 +)
85 AC_ARG_ENABLE(
86 [pedantic],
87 [AS_HELP_STRING([--enable-pedantic], [enable pedantic compiler warnings @<:@default disabled@:>@])],
@@ -791,6 +796,65 @@ AC_MSG_RESULT([${enable_backend_kinesis}])
796 AM_CONDITIONAL([ENABLE_BACKEND_KINESIS], [test "${enable_backend_kinesis}" = "yes"])
797
798
799 +# -----------------------------------------------------------------------------
800 +# Prometheus remote write backend - libprotobuf, libsnappy, protoc
801 +
802 +PKG_CHECK_MODULES(
803 + [PROTOBUF],
804 + [protobuf],
805 + [have_libprotobuf=yes],
806 + [have_libprotobuf=no]
807 +)
808 +
809 +PKG_CHECK_MODULES(
810 + [SNAPPY],
811 + [snappy],
812 + [have_libsnappy=yes],
813 + [have_libsnappy=no]
814 +)
815 +
816 +AC_PATH_PROG([PROTOC], [protoc], [no])
817 +AS_IF(
818 + [test x"${PROTOC}" == x"no"],
819 + [have_protoc=no],
820 + [have_protoc=yes]
821 +)
822 +
823 +AC_PATH_PROG([CXX_BINARY], [${CXX}], [no])
824 +AS_IF(
825 + [test x"${CXX_BINARY}" == x"no"],
826 + [have_CXX_compiler=no],
827 + [have_CXX_compiler=yes]
828 +)
829 +
830 +test "${enable_backend_prometheus_remote_write}" = "yes" -a "${have_libprotobuf}" != "yes" && \
831 + AC_MSG_ERROR([libprotobuf required but not found. try installing protobuf])
832 +
833 +test "${enable_backend_prometheus_remote_write}" = "yes" -a "${have_libsnappy}" != "yes" && \
834 + AC_MSG_ERROR([libsnappy required but not found. try installing snappy])
835 +
836 +test "${enable_backend_prometheus_remote_write}" = "yes" -a "${have_protoc}" != "yes" && \
837 + AC_MSG_ERROR([protoc compiler required but not found. try installing protobuf])
838 +
839 +test "${enable_backend_prometheus_remote_write}" = "yes" -a "${have_CXX_compiler}" != "yes" && \
840 + AC_MSG_ERROR([C++ compiler required but not found. try installing g++])
841 +
842 +AC_MSG_CHECKING([if prometheus remote write backend should be enabled])
843 +if test "${enable_backend_prometeus_remote_write}" != "no" -a "${have_libprotobuf}" = "yes" -a "${have_libsnappy}" = "yes" \
844 + -a "${have_protoc}" = "yes" -a "${have_CXX_compiler}" = "yes"; then
845 + enable_backend_prometheus_remote_write="yes"
846 + AC_DEFINE([ENABLE_PROMETHEUS_REMOTE_WRITE], [1], [Prometheus remote write API usability])
847 + OPTIONAL_PROMETHEUS_REMOTE_WRITE_CFLAGS="${PROTOBUF_CFLAGS} ${SNAPPY_CFLAGS}"
848 + CXX11FLAG="-std=c++11"
849 + OPTIONAL_PROMETHEUS_REMOTE_WRITE_LIBS="${PROTOBUF_LIBS} ${SNAPPY_LIBS} "
850 +else
851 + enable_backend_prometheus_remote_write="no"
852 +fi
853 +
854 +AC_MSG_RESULT([${enable_backend_prometheus_remote_write}])
855 +AM_CONDITIONAL([ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE], [test "${enable_backend_prometheus_remote_write}" = "yes"])
856 +
857 +
858 # -----------------------------------------------------------------------------
859 # check for setns() - cgroup-network
860
@@ -815,7 +879,7 @@ if test "${enable_lto}" != "no"; then
879 fi
880 if test "${have_lto}" = "yes"; then
881 oCFLAGS="${CFLAGS}"
818 - CFLAGS="${CFLAGS} -flto ${OPTIONAL_MATH_CFLAGS} ${OPTIONAL_NFACCT_CFLAGS} ${OPTIONAL_ZLIB_CFLAGS} ${OPTIONAL_UUID_CFLAGS} ${OPTIONAL_LIBCAP_CFLAGS} ${OPTIONAL_IPMIMONITORING_CFLAGS} ${OPTIONAL_CUPS_CFLAGS} ${OPTIONAL_XENSTAT_FLAGS} ${OPTIONAL_KINESIS_CFLAGS}"
882 + CFLAGS="${CFLAGS} -flto ${OPTIONAL_MATH_CFLAGS} ${OPTIONAL_NFACCT_CFLAGS} ${OPTIONAL_ZLIB_CFLAGS} ${OPTIONAL_UUID_CFLAGS} ${OPTIONAL_LIBCAP_CFLAGS} ${OPTIONAL_IPMIMONITORING_CFLAGS} ${OPTIONAL_CUPS_CFLAGS} ${OPTIONAL_XENSTAT_FLAGS} ${OPTIONAL_KINESIS_CFLAGS} ${OPTIONAL_PROMETHEUS_REMOTE_WRITE_CFLAGS}"
883 ac_cv_c_lto_cross_compile="${enable_lto}"
884 test "${ac_cv_c_lto_cross_compile}" != "yes" && ac_cv_c_lto_cross_compile="no"
885 AC_C_LTO
@@ -836,6 +900,8 @@ AC_MSG_RESULT([${enable_lto}])
900
901 # -----------------------------------------------------------------------------
902
903 +AM_CONDITIONAL([ENABLE_CXX_LINKER], [test "${enable_backend_kinesis}" = "yes" -o "${enable_backend_prometheus_remote_write}" = "yes"])
904 +
905 AC_DEFINE_UNQUOTED([NETDATA_USER], ["${with_user}"], [use this user to drop privileged])
906
907 varlibdir="${localstatedir}/lib/netdata"
@@ -898,6 +964,8 @@ AC_SUBST([OPTIONAL_XENSTAT_CFLAGS])
964 AC_SUBST([OPTIONAL_XENSTAT_LIBS])
965 AC_SUBST([OPTIONAL_KINESIS_CFLAGS])
966 AC_SUBST([OPTIONAL_KINESIS_LIBS])
967 +AC_SUBST([OPTIONAL_PROMETHEUS_REMOTE_WRITE_CFLAGS])
968 +AC_SUBST([OPTIONAL_PROMETHEUS_REMOTE_WRITE_LIBS])
969
970
971 AC_CONFIG_FILES([
@@ -908,6 +976,7 @@ AC_CONFIG_FILES([
976 backends/Makefile
977 backends/opentsdb/Makefile
978 backends/prometheus/Makefile
979 + backends/prometheus/remote_write/Makefile
980 backends/aws_kinesis/Makefile
981 collectors/Makefile
982 collectors/apps.plugin/Makefile
database/rrd.h
+1 -1
@@ -351,7 +351,7 @@ typedef enum rrdset_flags {
351 RRDSET_FLAG_UPSTREAM_EXPOSED = 1 << 8, // if set, we have sent this chart definition to netdata master (streaming)
352 RRDSET_FLAG_STORE_FIRST = 1 << 9, // if set, do not eliminate the first collection during interpolation
353 RRDSET_FLAG_HETEROGENEOUS = 1 << 10, // if set, the chart is not homogeneous (dimensions in it have multiple algorithms, multipliers or dividers)
354 - RRDSET_FLAG_HOMEGENEOUS_CHECK = 1 << 11, // if set, the chart should be checked to determine if the dimensions as homogeneous
354 + RRDSET_FLAG_HOMOGENEOUS_CHECK = 1 << 11, // if set, the chart should be checked to determine if the dimensions are homogeneous
355 RRDSET_FLAG_HIDDEN = 1 << 12, // if set, do not show this chart on the dashboard, but use it for backends
356 RRDSET_FLAG_SYNC_CLOCK = 1 << 13, // if set, microseconds on next data collection will be ignored (the chart will be synced to now)
357 RRDSET_FLAG_OBSOLETE_DIMENSIONS = 1 << 14 // this is marked by the collector/module when a chart has obsolete dimensions
database/rrddim.c
+3 -3
@@ -60,7 +60,7 @@ inline int rrddim_set_algorithm(RRDSET *st, RRDDIM *rd, RRD_ALGORITHM algorithm)
60 debug(D_RRD_CALLS, "Updating algorithm of dimension '%s/%s' from %s to %s", st->id, rd->name, rrd_algorithm_name(rd->algorithm), rrd_algorithm_name(algorithm));
61 rd->algorithm = algorithm;
62 rd->exposed = 0;
63 - rrdset_flag_set(st, RRDSET_FLAG_HOMEGENEOUS_CHECK);
63 + rrdset_flag_set(st, RRDSET_FLAG_HOMOGENEOUS_CHECK);
64 rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
65 return 1;
66 }
@@ -72,7 +72,7 @@ inline int rrddim_set_multiplier(RRDSET *st, RRDDIM *rd, collected_number multip
72 debug(D_RRD_CALLS, "Updating multiplier of dimension '%s/%s' from " COLLECTED_NUMBER_FORMAT " to " COLLECTED_NUMBER_FORMAT, st->id, rd->name, rd->multiplier, multiplier);
73 rd->multiplier = multiplier;
74 rd->exposed = 0;
75 - rrdset_flag_set(st, RRDSET_FLAG_HOMEGENEOUS_CHECK);
75 + rrdset_flag_set(st, RRDSET_FLAG_HOMOGENEOUS_CHECK);
76 rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
77 return 1;
78 }
@@ -84,7 +84,7 @@ inline int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, collected_number divisor)
84 debug(D_RRD_CALLS, "Updating divisor of dimension '%s/%s' from " COLLECTED_NUMBER_FORMAT " to " COLLECTED_NUMBER_FORMAT, st->id, rd->name, rd->divisor, divisor);
85 rd->divisor = divisor;
86 rd->exposed = 0;
87 - rrdset_flag_set(st, RRDSET_FLAG_HOMEGENEOUS_CHECK);
87 + rrdset_flag_set(st, RRDSET_FLAG_HOMOGENEOUS_CHECK);
88 rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
89 return 1;
90 }
database/rrdset.c
+1 -1
@@ -210,7 +210,7 @@ inline void rrdset_update_heterogeneous_flag(RRDSET *st) {
210
211 RRDDIM *rd;
212
213 - rrdset_flag_clear(st, RRDSET_FLAG_HOMEGENEOUS_CHECK);
213 + rrdset_flag_clear(st, RRDSET_FLAG_HOMOGENEOUS_CHECK);
214
215 RRD_ALGORITHM algorithm = st->dimensions->algorithm;
216 collected_number multiplier = abs(st->dimensions->multiplier);
libnetdata/socket/socket.c
+5 -1
@@ -819,11 +819,15 @@ int connect_to_one_of(const char *destination, int default_port, struct timeval
819 while(*s) {
820 const char *e = s;
821
822 + // skip path, moving both s(tart) and e(nd)
823 + if(*e == '/')
824 + while(!isspace(*e) && *e != ',') s = ++e;
825 +
826 // skip separators, moving both s(tart) and e(nd)
827 while(isspace(*e) || *e == ',') s = ++e;
828
829 // move e(nd) to the first separator
826 - while(*e && !isspace(*e) && *e != ',') e++;
830 + while(*e && !isspace(*e) && *e != ',' && *e != '/') e++;
831
832 // is there anything?
833 if(!*s || s == e) break;
netdata-installer.sh
+5
@@ -165,6 +165,9 @@ USAGE: ${PROGRAM} [options]
165 --enable-backend-kinesis Enable AWS Kinesis backend. Default: enable it when libaws_cpp_sdk_kinesis and libraries
166 it depends on are available.
167 --disable-backend-kinesis
168 + --enable-backend-prometheus-remote-write Enable Prometheus remote write backend. Default: enable it when libprotobuf and
169 + libsnappy are available.
170 + --disable-backend-prometheus-remote-write
171 --enable-lto Enable Link-Time-Optimization. Default: enabled
172 --disable-lto
173 --disable-x86-sse Disable SSE instructions. By default SSE optimizations are enabled.
@@ -212,6 +215,8 @@ while [ -n "${1}" ]; do
215 "--disable-plugin-xenstat") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-plugin-xenstat/} --disable-plugin-xenstat";;
216 "--enable-backend-kinesis") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-backend-kinesis/} --enable-backend-kinesis";;
217 "--disable-backend-kinesis") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-backend-kinesis/} --disable-backend-kinesis";;
218 + "--enable-backend-prometheus-remote-write") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-backend-prometheus-remote-write/} --enable-backend-prometheus-remote-write";;
219 + "--disable-backend-prometheus-remote-write") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-backend-prometheus-remote-write/} --disable-backend-prometheus-remote-write";;
220 "--enable-lto") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-lto/} --enable-lto";;
221 "--disable-lto") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-lto/} --disable-lto";;
222 "--disable-x86-sse") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-x86-sse/} --disable-x86-sse";;