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
+[]()
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";;