summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--CMakeLists.txt1
-rw-r--r--Makefile.am1
-rw-r--r--backends/backends.c8
-rw-r--r--exporting/README.md15
-rw-r--r--exporting/aws_kinesis/aws_kinesis.c2
-rw-r--r--exporting/clean_connectors.c43
-rw-r--r--exporting/exporting_engine.h51
-rw-r--r--exporting/graphite/README.md4
-rw-r--r--exporting/graphite/graphite.c45
-rw-r--r--exporting/graphite/graphite.h2
-rw-r--r--exporting/init_connectors.c45
-rw-r--r--exporting/json/README.md4
-rw-r--r--exporting/json/json.c138
-rw-r--r--exporting/json/json.h6
-rw-r--r--exporting/mongodb/mongodb.c11
-rw-r--r--exporting/mongodb/mongodb.h1
-rw-r--r--exporting/opentsdb/README.md42
-rw-r--r--exporting/opentsdb/opentsdb.c110
-rw-r--r--exporting/opentsdb/opentsdb.h10
-rw-r--r--exporting/process_data.c58
-rw-r--r--exporting/prometheus/remote_write/README.md3
-rw-r--r--exporting/prometheus/remote_write/remote_write.c69
-rw-r--r--exporting/prometheus/remote_write/remote_write.h6
-rw-r--r--exporting/prometheus/remote_write/remote_write_request.h4
-rw-r--r--exporting/pubsub/pubsub.c2
-rw-r--r--exporting/read_config.c34
-rw-r--r--exporting/send_data.c278
-rw-r--r--exporting/tests/exporting_doubles.c7
-rw-r--r--exporting/tests/test_exporting_engine.c172
-rw-r--r--exporting/tests/test_exporting_engine.h2
-rw-r--r--libnetdata/config/appconfig.c10
-rw-r--r--libnetdata/socket/security.c26
-rw-r--r--libnetdata/socket/security.h4
-rw-r--r--web/api/exporters/allmetrics.c28
35 files changed, 846 insertions, 398 deletions
diff --git a/.gitignore b/.gitignore
index 79851707cf..07dd9f0088 100644
--- a/.gitignore
+++ b/.gitignore
@@ -146,6 +146,8 @@ cmake-build-release/
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
+.cmake
+compile_commands.json
# jetbrains IDE
.jetbrains*
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac72ec44fb..00f9f12b97 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1270,6 +1270,7 @@ endif()
-Wl,--wrap=connect_to_one_of
-Wl,--wrap=create_main_rusage_chart
-Wl,--wrap=send_main_rusage
+ -Wl,--wrap=simple_connector_end_batch
${PROMETHEUS_REMOTE_WRITE_LINK_OPTIONS}
${KINESIS_LINK_OPTIONS}
${PUBSUB_LINK_OPTIONS}
diff --git a/Makefile.am b/Makefile.am
index 24de58e66f..d5daff71d3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -955,6 +955,7 @@ if ENABLE_UNITTESTS
-Wl,--wrap=connect_to_one_of \
-Wl,--wrap=create_main_rusage_chart \
-Wl,--wrap=send_main_rusage \
+ -Wl,--wrap=simple_connector_end_batch \
$(TEST_LDFLAGS) \
$(NULL)
exporting_tests_exporting_engine_testdriver_LDADD = $(NETDATA_COMMON_LIBS) $(TEST_LIBS)
diff --git a/backends/backends.c b/backends/backends.c
index 34df05f26c..074e18679d 100644
--- a/backends/backends.c
+++ b/backends/backends.c
@@ -551,7 +551,7 @@ void *backends_main(void *ptr) {
case BACKEND_TYPE_OPENTSDB_USING_HTTP: {
#ifdef ENABLE_HTTPS
if (!strcmp(type, "opentsdb:https")) {
- security_start_ssl(NETDATA_SSL_CONTEXT_OPENTSDB);
+ security_start_ssl(NETDATA_SSL_CONTEXT_EXPORTING);
}
#endif
backend_set_opentsdb_http_variables(&default_port,&backend_response_checker,&backend_request_formatter);
@@ -1001,9 +1001,9 @@ void *backends_main(void *ptr) {
sock = connect_to_one_of(destination, default_port, &timeout, &reconnects, NULL, 0);
#ifdef ENABLE_HTTPS
if(sock != -1) {
- if(netdata_opentsdb_ctx) {
+ if(netdata_exporting_ctx) {
if(!opentsdb_ssl.conn) {
- opentsdb_ssl.conn = SSL_new(netdata_opentsdb_ctx);
+ opentsdb_ssl.conn = SSL_new(netdata_exporting_ctx);
if(!opentsdb_ssl.conn) {
error("Failed to allocate SSL structure %d.", sock);
opentsdb_ssl.flags = NETDATA_SSL_NO_HANDSHAKE;
@@ -1229,7 +1229,7 @@ cleanup:
buffer_free(response);
#ifdef ENABLE_HTTPS
- if(netdata_opentsdb_ctx) {
+ if(netdata_exporting_ctx) {
if(opentsdb_ssl.conn) {
SSL_free(opentsdb_ssl.conn);
}
diff --git a/exporting/README.md b/exporting/README.md
index 1a04e4085d..8f490cc2ff 100644
--- a/exporting/README.md
+++ b/exporting/README.md
@@ -44,7 +44,7 @@ X seconds (though, it can send them per second if you need it to).
also be configured). Learn more in our guide to [export and visualize Netdata metrics in
Graphite](/docs/guides/export/export-netdata-metrics-graphite.md).
- [**JSON** document databases](/exporting/json/README.md)
- - [**OpenTSDB**](/exporting/opentsdb/README.md): Use a plaintext, HTTP, or HTTPS interfaces. Metrics are sent to
+ - [**OpenTSDB**](/exporting/opentsdb/README.md): Use a plaintext or HTTP interfaces. Metrics are sent to
OpenTSDB as `prefix.chart.dimension` with tag `host=hostname`.
- [**MongoDB**](/exporting/mongodb/README.md): Metrics are sent to the database in `JSON` format.
- [**Prometheus**](/exporting/prometheus/README.md): Use an existing Prometheus installation to scrape metrics
@@ -173,8 +173,10 @@ You can configure each connector individually using the available [options](#opt
- `[prometheus:exporter]` defines settings for Prometheus exporter API queries (e.g.:
`http://NODE:19999/api/v1/allmetrics?format=prometheus&help=yes&source=as-collected`).
- `[<type>:<name>]` keeps settings for a particular exporting connector instance, where:
- - `type` selects the exporting connector type: graphite | opentsdb:telnet | opentsdb:http | opentsdb:https |
- prometheus_remote_write | json | kinesis | pubsub | mongodb
+ - `type` selects the exporting connector type: graphite | opentsdb:telnet | opentsdb:http |
+ prometheus_remote_write | json | kinesis | pubsub | mongodb. For graphite, opentsdb,
+ json, and prometheus_remote_write connectors you can also use `:http` or `:https` modifiers
+ (e.g.: `opentsdb:https`).
- `name` can be arbitrary instance name you chose.
### Options
@@ -270,6 +272,13 @@ Configure individual connectors and override any global settings with the follow
> You can check how the host tags were parsed using the /api/v1/info API call. But, keep in mind that backends subsystem
> is deprecated and will be deleted soon. Please move your existing tags to the `[host labels]` section.
+## HTTPS
+
+Netdata can send metrics to external databases using the TLS/SSL protocol. Unfortunately, some of
+them does not support encrypted connections, so you will have to configure a reverse proxy to enable
+HTTPS communication between Netdata and an external database. You can set up a reverse proxy with
+[Nginx](/docs/Running-behind-nginx.md).
+
## Exporting engine monitoring
Netdata creates five charts in the dashboard, under the **Netdata Monitoring** section, to help you monitor the health
diff --git a/exporting/aws_kinesis/aws_kinesis.c b/exporting/aws_kinesis/aws_kinesis.c
index 00600fa9bb..036afb49fc 100644
--- a/exporting/aws_kinesis/aws_kinesis.c
+++ b/exporting/aws_kinesis/aws_kinesis.c
@@ -48,7 +48,7 @@ int init_aws_kinesis_instance(struct instance *instance)
instance->end_host_formatting = flush_host_labels;
instance->end_batch_formatting = NULL;
- instance->send_header = NULL;
+ instance->prepare_header = NULL;
instance->check_response = NULL;
instance->buffer = (void *)buffer_create(0);
diff --git a/exporting/clean_connectors.c b/exporting/clean_connectors.c
index 4ad644d69c..459777f0fd 100644
--- a/exporting/clean_connectors.c
+++ b/exporting/clean_connectors.c
@@ -35,3 +35,46 @@ void clean_instance(struct instance *instance)
uv_cond_destroy(&instance->cond_var);
// uv_mutex_destroy(&instance->mutex);
}
+
+/**
+ * Clean up a simple connector instance on Netdata exit
+ *
+ * @param instance an instance data structure.
+ */
+void simple_connector_cleanup(struct instance *instance)
+{
+ info("EXPORTING: cleaning up instance %s ...", instance->config.name);
+
+ struct simple_connector_data *simple_connector_data =
+ (struct simple_connector_data *)instance->connector_specific_data;
+
+ buffer_free(instance->buffer);
+ buffer_free(simple_connector_data->buffer);
+ buffer_free(simple_connector_data->header);
+
+ struct simple_connector_buffer *next_buffer = simple_connector_data->first_buffer;
+ for (int i = 0; i < instance->config.buffer_on_failures; i++) {
+ struct simple_connector_buffer *current_buffer = next_buffer;
+ next_buffer = next_buffer->next;
+
+ buffer_free(current_buffer->header);
+ buffer_free(current_buffer->buffer);
+ freez(current_buffer);
+ }
+
+#ifdef ENABLE_HTTPS
+ if (simple_connector_data->conn)
+ SSL_free(simple_connector_data->conn);
+#endif
+
+ freez(simple_connector_data);
+
+ struct simple_connector_config *simple_connector_config =
+ (struct simple_connector_config *)instance->config.connector_specific_config;
+ freez(simple_connector_config);
+
+ info("EXPORTING: instance %s exited", instance->config.name);
+ instance->exited = 1;
+
+ return;
+}
diff --git a/exporting/exporting_engine.h b/exporting/exporting_engine.h
index b436f5d809..e0993c98f8 100644
--- a/exporting/exporting_engine.h
+++ b/exporting/exporting_engine.h
@@ -46,10 +46,12 @@ typedef enum exporting_options {
typedef enum exporting_connector_types {
EXPORTING_CONNECTOR_TYPE_UNKNOWN, // Invalid type
EXPORTING_CONNECTOR_TYPE_GRAPHITE, // Send plain text to Graphite
- EXPORTING_CONNECTOR_TYPE_OPENTSDB_USING_TELNET, // Send data to OpenTSDB using telnet API
- EXPORTING_CONNECTOR_TYPE_OPENTSDB_USING_HTTP, // Send data to OpenTSDB using HTTP API
- EXPORTING_CONNECTOR_TYPE_JSON, // Stores the data using JSON.
- EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE, // The user selected to use Prometheus backend
+ EXPORTING_CONNECTOR_TYPE_GRAPHITE_HTTP, // Send data to Graphite using HTTP API
+ EXPORTING_CONNECTOR_TYPE_JSON, // Send data in JSON format
+ EXPORTING_CONNECTOR_TYPE_JSON_HTTP, // Send data in JSON format using HTTP API
+ EXPORTING_CONNECTOR_TYPE_OPENTSDB, // Send data to OpenTSDB using telnet API
+ EXPORTING_CONNECTOR_TYPE_OPENTSDB_HTTP, // Send data to OpenTSDB using HTTP API
+ EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE, // User selected to use Prometheus backend
EXPORTING_CONNECTOR_TYPE_KINESIS, // Send message to AWS Kinesis
EXPORTING_CONNECTOR_TYPE_PUBSUB, // Send message to Google Cloud Pub/Sub
EXPORTING_CONNECTOR_TYPE_MONGODB, // Send data to MongoDB collection
@@ -81,6 +83,38 @@ struct simple_connector_config {
int default_port;
};
+struct simple_connector_buffer {
+ BUFFER *header;
+ BUFFER *buffer;
+
+ size_t buffered_metrics;
+ size_t buffered_bytes;
+
+ int used;
+
+ struct simple_connector_buffer *next;
+};
+
+struct simple_connector_data {
+ void *connector_specific_data;
+
+ size_t total_buffered_metrics;
+
+ BUFFER *header;
+ BUFFER *buffer;
+ size_t buffered_metrics;
+ size_t buffered_bytes;
+
+ struct simple_connector_buffer *previous_buffer;
+ struct simple_connector_buffer *first_buffer;
+ struct simple_connector_buffer *last_buffer;
+
+#ifdef ENABLE_HTTPS
+ SSL *conn; //SSL connection
+ int flags; //The flags for SSL connection
+#endif
+};
+
struct prometheus_remote_write_specific_config {
char *remote_write_path;
};
@@ -175,7 +209,7 @@ struct instance {
int (*end_host_formatting)(struct instance *instance, RRDHOST *host);
int (*end_batch_formatting)(struct instance *instance);
- int (*send_header)(int *sock, struct instance *instance);
+ void (*prepare_header)(struct instance *instance);
int (*check_response)(BUFFER *buffer, struct instance *instance);
void *connector_specific_data;
@@ -210,6 +244,7 @@ struct engine *read_exporting_config();
EXPORTING_CONNECTOR_TYPE exporting_select_type(const char *type);
int init_connectors(struct engine *engine);
+void simple_connector_init(struct instance *instance);
int mark_scheduled_instances(struct engine *engine);
void prepare_buffers(struct engine *engine);
@@ -232,11 +267,12 @@ void end_chart_formatting(struct engine *engine, RRDSET *st);
void end_host_formatting(struct engine *engine, RRDHOST *host);
void end_batch_formatting(struct engine *engine);
int flush_host_labels(struct instance *instance, RRDHOST *host);
-int simple_connector_update_buffered_bytes(struct instance *instance);
+int simple_connector_end_batch(struct instance *instance);
int exporting_discard_response(BUFFER *buffer, struct instance *instance);
void simple_connector_receive_response(int *sock, struct instance *instance);
-void simple_connector_send_buffer(int *sock, int *failures, struct instance *instance);
+void simple_connector_send_buffer(
+ int *sock, int *failures, struct instance *instance, BUFFER *header, BUFFER *buffer, size_t buffered_metrics);
void simple_connector_worker(void *instance_p);
void create_main_rusage_chart(RRDSET **st_rusage, RRDDIM **rd_user, RRDDIM **rd_system);
@@ -244,6 +280,7 @@ void send_main_rusage(RRDSET *st_rusage, RRDDIM *rd_user, RRDDIM *rd_system);
void send_internal_metrics(struct instance *instance);
extern void clean_instance(struct instance *ptr);
+void simple_connector_cleanup(struct instance *instance);
static inline void disable_instance(struct instance *instance)
{
diff --git a/exporting/graphite/README.md b/exporting/graphite/README.md
index 95b8ef954d..2ac7adc7af 100644
--- a/exporting/graphite/README.md
+++ b/exporting/graphite/README.md
@@ -3,6 +3,7 @@ title: "Export metrics to Graphite providers"
sidebar_label: Graphite
description: "Archive your Agent's metrics to a any Graphite database provider for long-term storage, further analysis, or correlation with data from other sources."
custom_edit_url: https://github.com/netdata/netdata/edit/master/exporting/graphite/README.md
+sidebar_label: Graphite
-->
# Export metrics to Graphite providers
@@ -21,6 +22,9 @@ directory and set the following options:
destination = localhost:2003
```
+Add `:http` or `:https` modifiers to the connector type if you need to use other than a plaintext protocol. For example: `graphite:http:my_graphite_instance`,
+`graphite:https:my_graphite_instance`.
+
The Graphite connector is further configurable using additional settings. See the [exporting reference
doc](/exporting/README.md#options) for details.
diff --git a/exporting/graphite/graphite.c b/exporting/graphite/graphite.c
index 6aad2054db..23e40c369e 100644
--- a/exporting/graphite/graphite.c
+++ b/exporting/graphite/graphite.c
@@ -16,6 +16,17 @@ int init_graphite_instance(struct instance *instance)
instance->config.connector_specific_config = (void *)connector_specific_config;
connector_specific_config->default_port = 2003;
+ struct simple_connector_data *connector_specific_data = callocz(1, sizeof(struct simple_connector_data));
+ instance->connector_specific_data = connector_specific_data;
+
+#ifdef ENABLE_HTTPS
+ connector_specific_data->flags = NETDATA_SSL_START;
+ connector_specific_data->conn = NULL;
+ if (instance->config.options & EXPORTING_OPTION_USE_TLS) {
+ security_start_ssl(NETDATA_SSL_CONTEXT_EXPORTING);
+ }
+#endif
+
instance->start_batch_formatting = NULL;
instance->start_host_formatting = format_host_labels_graphite_plaintext;
instance->start_chart_formatting = NULL;
@@ -27,9 +38,13 @@ int init_graphite_instance(struct instance *instance)
instance->end_chart_formatting = NULL;
instance->end_host_formatting = flush_host_labels;
- instance->end_batch_formatting = simple_connector_update_buffered_bytes;
+ instance->end_batch_formatting = simple_connector_end_batch;
+
+ if (instance->config.type == EXPORTING_CONNECTOR_TYPE_GRAPHITE_HTTP)
+ instance->prepare_header = graphite_http_prepare_header;
+ else
+ instance->prepare_header = NULL;
- instance->send_header = NULL;
instance->check_response = exporting_discard_response;
instance->buffer = (void *)buffer_create(0);
@@ -37,6 +52,9 @@ int init_graphite_instance(struct instance *instance)
error("EXPORTING: cannot create buffer for graphite exporting connector instance %s", instance->config.name);
return 1;
}
+
+ simple_connector_init(instance);
+
if (uv_mutex_init(&instance->mutex))
return 1;
if (uv_cond_init(&instance->cond_var))
@@ -187,3 +205,26 @@ int format_dimension_stored_graphite_plaintext(struct instance *instance, RRDDIM
return 0;
}
+
+/**
+ * Ppepare HTTP header
+ *
+ * @param instance an instance data structure.
+ * @return Returns 0 on success, 1 on failure.
+ */
+void graphite_http_prepare_header(struct instance *instance)
+{
+ struct simple_connector_data *simple_connector_data = instance->connector_specific_data;
+
+ buffer_sprintf(
+ simple_connector_data->last_buffer->header,
+ "POST /api/put HTTP/1.1\r\n"
+ "Host: %s\r\n"
+ "Content-Type: application/graphite\r\n"
+ "Content-Length: %lu\r\n"
+ "\r\n",
+ instance->config.destination,
+ buffer_strlen(simple_connector_data->last_buffer->buffer));
+
+ return;
+}
diff --git a/exporting/graphite/graphite.h b/exporting/graphite/graphite.h
index edda498e85..993c12e57a 100644
--- a/exporting/graphite/graphite.h
+++ b/exporting/graphite/graphite.h
@@ -13,4 +13,6 @@ int format_host_labels_graphite_plaintext(struct instance *instance, RRDHOST *ho
int format_dimension_collected_graphite_plaintext(struct instance *instance, RRDDIM *rd);
int format_dimension_stored_graphite_plaintext(struct instance *instance, RRDDIM *rd);
+void graphite_http_prepare_header(struct instance *instance);
+
#endif //NETDATA_EXPORTING_GRAPHITE_H
diff --git a/exporting/init_connectors.c b/exporting/init_connectors.c
index 4a68118970..57ac030d9a 100644
--- a/exporting/init_connectors.c
+++ b/exporting/init_connectors.c
@@ -40,15 +40,23 @@ int init_connectors(struct engine *engine)
if (init_graphite_instance(instance) != 0)
return 1;
break;
+ case EXPORTING_CONNECTOR_TYPE_GRAPHITE_HTTP:
+ if (init_graphite_instance(instance) != 0)
+ return 1;
+ break;
case EXPORTING_CONNECTOR_TYPE_JSON:
if (init_json_instance(instance) != 0)
return 1;
break;
- case EXPORTING_CONNECTOR_TYPE_OPENTSDB_USING_TELNET:
+ case EXPORTING_CONNECTOR_TYPE_JSON_HTTP:
+ if (init_json_http_instance(instance) != 0)
+ return 1;
+ break;
+ case EXPORTING_CONNECTOR_TYPE_OPENTSDB:
if (init_opentsdb_telnet_instance(instance) != 0)
return 1;
break;
- case EXPORTING_CONNECTOR_TYPE_OPENTSDB_USING_HTTP:
+ case EXPORTING_CONNECTOR_TYPE_OPENTSDB_HTTP:
if (init_opentsdb_http_instance(instance) != 0)
return 1;
break;
@@ -96,3 +104,36 @@ int init_connectors(struct engine *engine)
return 0;
}
+
+/**
+ * Initialize a ring buffer for a simple connector
+ *
+ * @param instance an instance data structure.
+ */
+void simple_connector_init(struct instance *instance)
+{
+ struct simple_connector_data *connector_specific_data =
+ (struct simple_connector_data *)instance->connector_specific_data;
+
+ // create a ring buffer
+ struct simple_connector_buffer *first_buffer = NULL;
+
+ if (instance->config.buffer_on_failures < 1)
+ instance->config.buffer_on_failures = 1;
+
+ for (int i = 0; i < instance->config.buffer_on_failures; i++) {
+ struct simple_connector_buffer *current_buffer = callocz(1, sizeof(struct simple_connector_buffer));
+
+ if (!connector_specific_data->first_buffer)
+ first_buffer = current_buffer;
+ else
+ current_buffer->next = connector_specific_data->first_buffer;
+
+ connector_specific_data->first_buffer = current_buffer;
+ }
+
+ first_buffer->next = connector_specific_data->first_buffer;
+ connector_specific_data->last_buffer = connector_specific_data->first_buffer;
+
+ return;
+}
diff --git a/exporting/json/README.md b/exporting/json/README.md
index 8ef084cf22..1dd41e738e 100644
--- a/exporting/json/README.md
+++ b/exporting/json/README.md
@@ -3,6 +3,7 @@ title: "Export metrics to JSON document databases"
sidebar_label: JSON
description: "Archive your Agent's metrics to a JSON document database for long-term storage, further analysis, or correlation with data from other sources."
custom_edit_url: https://github.com/netdata/netdata/edit/master/exporting/json/README.md
+sidebar_label: JSON Document Databases
-->
# Export metrics to JSON document databases
@@ -21,6 +22,9 @@ directory and set the following options:
destination = localhost:5448
```
+Add `:http` or `:https` modifiers to the connector type if you need to use other than a plaintext protocol. For example: `json:http:my_json_instance`,
+`json:https:my_json_instance`.
+
The JSON connector is further configurable using additional settings. See the [exporting reference
doc](/exporting/README.md#options) for details.
diff --git a/exporting/json/json.c b/exporting/json/json.c
index cea7eff07c..458e7e8cce 100644
--- a/exporting/json/json.c
+++ b/exporting/json/json.c
@@ -16,6 +16,9 @@ int init_json_instance(struct instance *instance)
instance->config.connector_specific_config = (void *)connector_specific_config;
connector_specific_config->default_port = 5448;
+ struct simple_connector_data *connector_specific_data = callocz(1, sizeof(struct simple_connector_data));
+ instance->connector_specific_data = connector_specific_data;
+
instance->start_batch_formatting = NULL;
instance->start_host_formatting = format_host_labels_json_plaintext;
instance->start_chart_formatting = NULL;
@@ -27,9 +30,10 @@ int init_json_instance(struct instance *instance)
instance->end_chart_formatting = NULL;
instance->end_host_formatting = flush_host_labels;
- instance->end_batch_formatting = simple_connector_update_buffered_bytes;
+ instance->end_batch_formatting = simple_connector_end_batch;
+
+ instance->prepare_header = NULL;
- instance->send_header = NULL;
instance->check_response = exporting_discard_response;
instance->buffer = (void *)buffer_create(0);
@@ -37,6 +41,63 @@ int init_json_instance(struct instance *instance)
error("EXPORTING: cannot create buffer for json exporting connector instance %s", instance->config.name);
return 1;
}
+
+ simple_connector_init(instance);
+
+ if (uv_mutex_init(&instance->mutex))
+ return 1;
+ if (uv_cond_init(&instance->cond_var))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Initialize JSON connector instance for HTTP protocol
+ *
+ * @param instance an instance data structure.
+ * @return Returns 0 on success, 1 on failure.
+ */
+int init_json_http_instance(struct instance *instance)
+{
+ instance->worker = simple_connector_worker;
+
+ struct simple_connector_config *connector_specific_config = callocz(1, sizeof(struct simple_connector_config));
+ instance->config.connector_specific_config = (void *)connector_specific_config;
+ connector_specific_config->default_port = 5448;
+
+ struct simple_connector_data *connector_specific_data = callocz(1, sizeof(struct simple_connector_data));
+ instance->connector_specific_data = connector_specific_data;
+
+#ifdef ENABLE_HTTPS
+ connector_specific_data->flags = NETDATA_SSL_START;
+ connector_specific_data->conn = NULL;
+ if (instance->config.options & EXPORTING_OPTION_USE_TLS) {
+ security_start_ssl(NETDATA_SSL_CONTEXT_EXPORTING);
+ }
+#endif
+
+ instance->start_batch_formatting = open_batch_json_http;
+ instance->start_host_formatting = format_host_labels_json_plaintext;
+ instance->start_chart_formatting = NULL;
+
+ if (EXPORTING_OPTIONS_DATA_SOURCE(instance->config.options) == EXPORTING_SOURCE_DATA_AS_COLLECTED)
+ instance->metric_formatting = format_dimension_collected_json_plaintext;
+ else
+ instance->metric_formatting = format_dimension_stored_json_plaintext;
+
+ instance->end_chart_formatting = NULL;
+ instance->end_host_formatting = flush_host_labels;
+ instance->end_batch_formatting = close_batch_json_http;
+
+ instance->prepare_header = json_http_prepare_header;
+
+ instance->check_response = exporting_discard_response;
+
+ instance->buffer = (void *)buffer_create(0);
+
+ simple_connector_init(instance);
+
if (uv_mutex_init(&instance->mutex))
return 1;
if (uv_cond_init(&instance->cond_var))
@@ -111,6 +172,11 @@ int format_dimension_collected_json_plaintext(struct instance *instance, RRDDIM
}
}
+ if (instance->config.type == EXPORTING_CONNECTOR_TYPE_JSON_HTTP) {
+ if (buffer_strlen((BUFFER *)instance->buffer) > 2)
+ buffer_strcat(instance->buffer, ",\n");
+ }
+
buffer_sprintf(
instance->buffer,
@@ -131,7 +197,7 @@ int format_dimension_collected_json_plaintext(struct instance *instance, RRDDIM
"\"name\":\"%s\","
"\"value\":" COLLECTED_NUMBER_FORMAT ","
- "\"timestamp\":%llu}\n",
+ "\"timestamp\":%llu}",
instance->config.prefix,
(host == localhost) ? engine->config.hostname : host->hostname,
@@ -153,6 +219,10 @@ int format_dimension_collected_json_plaintext(struct instance *instance, RRDDIM
(unsigned long long)rd->last_collected_time.tv_sec);
+ if (instance->config.type != EXPORTING_CONNECTOR_TYPE_JSON_HTTP) {
+ buffer_strcat(instance->buffer, "\n");
+ }
+
return 0;
}
@@ -189,6 +259,11 @@ int format_dimension_stored_json_plaintext(struct instance *instance, RRDDIM *rd
}
}
+ if (instance->config.type == EXPORTING_CONNECTOR_TYPE_JSON_HTTP) {
+ if (buffer_strlen((BUFFER *)instance->buffer) > 2)
+ buffer_strcat(instance->buffer, ",\n");
+ }
+
buffer_sprintf(
instance->buffer,
"{"
@@ -208,7 +283,7 @@ int format_dimension_stored_json_plaintext(struct instance *instance, RRDDIM *rd
"\"name\":\"%s\","
"\"value\":" CALCULATED_NUMBER_FORMAT ","
- "\"timestamp\": %llu}\n",
+ "\"timestamp\": %llu}",
instance->config.prefix,
(host == localhost) ? engine->config.hostname : host->hostname,
@@ -230,5 +305,60 @@ int format_dimension_stored_json_plaintext(struct instance *instance, RRDDIM *rd
(unsigned long long)last_t);
+ if (instance->config.type != EXPORTING_CONNECTOR_TYPE_JSON_HTTP) {
+ buffer_strcat(instance->buffer, "\n");
+ }
+
return 0;
}
+
+/**
+ * Open a JSON list for a bach
+ *
+ * @param instance an instance data structure.
+ * @return Always returns 0.
+ */
+int open_batch_json_http(struct instance *instance)
+{
+ buffer_strcat(instance->buffer, "[\n");
+
+ return 0;
+}
+
+/**
+ * Close a JSON list for a bach and update buffered bytes counter
+ *
+ * @param instance an instance data structure.
+ * @return Always returns 0.
+ */
+int close_batch_json_http(struct instance *instance)
+{
+ buffer_strcat(instance->buffer, "\n]\n");
+
+ simple_connector_end_batch(instance);
+
+ return 0;
+}
+
+/**
+ * Prepare HTTP header
+ *
+ * @param instance an instance data structure.
+ * @return Returns 0 on success, 1 on failure.
+ */
+void json_http_prepare_header(struct instance *instance)
+{
+ struct simple_connector_data *simple_connector_data = instance->connector_specific_data;
+
+ buffer_sprintf(
+ simple_connector_data->last_buffer->header,
+ "POST /api/put HTTP/1.1\r\n"
+ "Host: %s\r\n"