summaryrefslogtreecommitdiffstats
path: root/backends/mongodb
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--backends/mongodb/Makefile.am8
-rw-r--r--backends/mongodb/README.md41
-rw-r--r--backends/mongodb/mongodb.c189
-rw-r--r--backends/mongodb/mongodb.conf12
-rw-r--r--backends/mongodb/mongodb.h16
5 files changed, 266 insertions, 0 deletions
diff --git a/backends/mongodb/Makefile.am b/backends/mongodb/Makefile.am
new file mode 100644
index 0000000..161784b
--- /dev/null
+++ b/backends/mongodb/Makefile.am
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+ README.md \
+ $(NULL)
diff --git a/backends/mongodb/README.md b/backends/mongodb/README.md
new file mode 100644
index 0000000..7c7996e
--- /dev/null
+++ b/backends/mongodb/README.md
@@ -0,0 +1,41 @@
+<!--
+title: "MongoDB backend"
+custom_edit_url: https://github.com/netdata/netdata/edit/master/backends/mongodb/README.md
+-->
+
+# MongoDB backend
+
+## Prerequisites
+
+To use MongoDB as a backend, `libmongoc` 1.7.0 or higher should be
+[installed](http://mongoc.org/libmongoc/current/installing.html) first. Next, Netdata should be re-installed from the
+source. The installer will detect that the required libraries are now available.
+
+## Configuration
+
+To enable data sending to the MongoDB backend set the following options in `netdata.conf`:
+
+```conf
+[backend]
+ enabled = yes
+ type = mongodb
+```
+
+In the Netdata configuration directory run `./edit-config mongodb.conf` and set [MongoDB
+URI](https://docs.mongodb.com/manual/reference/connection-string/), database name, and collection name:
+
+```yaml
+# URI
+uri = mongodb://<hostname>
+
+# database name
+database = your_database_name
+
+# collection name
+collection = your_collection_name
+```
+
+The default socket timeout depends on the backend update interval. The timeout is 500 ms shorter than the interval (but
+not less than 1000 ms). You can alter the timeout using the `sockettimeoutms` MongoDB URI option.
+
+[![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%2Fmongodb%2FREADME&_u=MAC~&cid=5792dfd7-8dc4-476b-af31-da2fdb9f93d2&tid=UA-64295674-3)](<>)
diff --git a/backends/mongodb/mongodb.c b/backends/mongodb/mongodb.c
new file mode 100644
index 0000000..d0527a7
--- /dev/null
+++ b/backends/mongodb/mongodb.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#define BACKENDS_INTERNALS
+#include "mongodb.h"
+#include <mongoc.h>
+
+#define CONFIG_FILE_LINE_MAX ((CONFIG_MAX_NAME + CONFIG_MAX_VALUE + 1024) * 2)
+
+static mongoc_client_t *mongodb_client;
+static mongoc_collection_t *mongodb_collection;
+
+int backends_mongodb_init(const char *uri_string,
+ const char *database_string,
+ const char *collection_string,
+ int32_t default_socket_timeout) {
+ mongoc_uri_t *uri;
+ bson_error_t error;
+
+ mongoc_init();
+
+ uri = mongoc_uri_new_with_error(uri_string, &error);
+ if(unlikely(!uri)) {
+ error("BACKEND: failed to parse URI: %s. Error message: %s", uri_string, error.message);
+ return 1;
+ }
+
+ int32_t socket_timeout = mongoc_uri_get_option_as_int32(uri, MONGOC_URI_SOCKETTIMEOUTMS, default_socket_timeout);
+ if(!mongoc_uri_set_option_as_int32(uri, MONGOC_URI_SOCKETTIMEOUTMS, socket_timeout)) {
+ error("BACKEND: failed to set %s to the value %d", MONGOC_URI_SOCKETTIMEOUTMS, socket_timeout);
+ return 1;
+ };
+
+ mongodb_client = mongoc_client_new_from_uri(uri);
+ if(unlikely(!mongodb_client)) {
+ error("BACKEND: failed to create a new client");
+ return 1;
+ }
+
+ if(!mongoc_client_set_appname(mongodb_client, "netdata")) {
+ error("BACKEND: failed to set client appname");
+ };
+
+ mongodb_collection = mongoc_client_get_collection(mongodb_client, database_string, collection_string);
+
+ mongoc_uri_destroy(uri);
+
+ return 0;
+}
+
+void backends_free_bson(bson_t **insert, size_t n_documents) {
+ size_t i;
+
+ for(i = 0; i < n_documents; i++)
+ bson_destroy(insert[i]);
+
+ free(insert);
+}
+
+int backends_mongodb_insert(char *data, size_t n_metrics) {
+ bson_t **insert = calloc(n_metrics, sizeof(bson_t *));
+ bson_error_t error;
+ char *start = data, *end = data;
+ size_t n_documents = 0;
+
+ while(*end && n_documents <= n_metrics) {
+ while(*end && *end != '\n') end++;
+
+ if(likely(*end)) {
+ *end = '\0';
+ end++;
+ }
+ else {
+ break;
+ }
+
+ insert[n_documents] = bson_new_from_json((const uint8_t *)start, -1, &error);
+
+ if(unlikely(!insert[n_documents])) {
+ error("BACKEND: %s", error.message);
+ backends_free_bson(insert, n_documents);
+ return 1;
+ }
+
+ start = end;
+
+ n_documents++;
+ }
+
+ if(unlikely(!mongoc_collection_insert_many(mongodb_collection, (const bson_t **)insert, n_documents, NULL, NULL, &error))) {
+ error("BACKEND: %s", error.message);
+ backends_free_bson(insert, n_documents);
+ return 1;
+ }
+
+ backends_free_bson(insert, n_documents);
+
+ return 0;
+}
+
+void backends_mongodb_cleanup() {
+ mongoc_collection_destroy(mongodb_collection);
+ mongoc_client_destroy(mongodb_client);
+ mongoc_cleanup();
+
+ return;
+}
+
+int read_mongodb_conf(const char *path, char **uri_p, char **database_p, char **collection_p) {
+ char *uri = *uri_p;
+ char *database = *database_p;
+ char *collection = *collection_p;
+
+ if(unlikely(uri)) freez(uri);
+ if(unlikely(database)) freez(database);
+ if(unlikely(collection)) freez(collection);
+ uri = NULL;
+ database = NULL;
+ collection = NULL;
+
+ int line = 0;
+
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s/mongodb.conf", path);
+
+ char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
+
+ debug(D_BACKEND, "BACKEND: opening config file '%s'", filename);
+
+ FILE *fp = fopen(filename, "r");
+ if(!fp) {
+ return 1;
+ }
+
+ while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
+ buffer[CONFIG_FILE_LINE_MAX] = '\0';
+ line++;
+
+ s = trim(buffer);
+ if(!s || *s == '#') {
+ debug(D_BACKEND, "BACKEND: ignoring line %d of file '%s', it is empty.", line, filename);
+ continue;
+ }
+
+ char *name = s;
+ char *value = strchr(s, '=');
+ if(unlikely(!value)) {
+ error("BACKEND: ignoring line %d ('%s') of file '%s', there is no = in it.", line, s, filename);
+ continue;
+ }
+ *value = '\0';
+ value++;
+
+ name = trim(name);
+ value = trim(value);
+
+ if(unlikely(!name || *name == '#')) {
+ error("BACKEND: ignoring line %d of file '%s', name is empty.", line, filename);
+ continue;
+ }
+
+ if(!value)
+ value = "";
+ else
+ value = strip_quotes(value);
+
+ if(name[0] == 'u' && !strcmp(name, "uri")) {
+ uri = strdupz(value);
+ }
+ else if(name[0] == 'd' && !strcmp(name, "database")) {
+ database = strdupz(value);
+ }
+ else if(name[0] == 'c' && !strcmp(name, "collection")) {
+ collection = strdupz(value);
+ }
+ }
+
+ fclose(fp);
+
+ if(unlikely(!collection || !*collection)) {
+ error("BACKEND: collection name is a mandatory MongoDB parameter, but it is not configured");
+ return 1;
+ }
+
+ *uri_p = uri;
+ *database_p = database;
+ *collection_p = collection;
+
+ return 0;
+}
diff --git a/backends/mongodb/mongodb.conf b/backends/mongodb/mongodb.conf
new file mode 100644
index 0000000..11ea6ef
--- /dev/null
+++ b/backends/mongodb/mongodb.conf
@@ -0,0 +1,12 @@
+# MongoDB backend configuration
+#
+# All options in this file are mandatory
+
+# URI
+uri =
+
+# database name
+database =
+
+# collection name
+collection =
diff --git a/backends/mongodb/mongodb.h b/backends/mongodb/mongodb.h
new file mode 100644
index 0000000..cae9b09
--- /dev/null
+++ b/backends/mongodb/mongodb.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_BACKEND_MONGODB_H
+#define NETDATA_BACKEND_MONGODB_H
+
+#include "backends/backends.h"
+
+extern int backends_mongodb_init(const char *uri_string, const char *database_string, const char *collection_string, const int32_t socket_timeout);
+
+extern int backends_mongodb_insert(char *data, size_t n_metrics);
+
+extern void backends_mongodb_cleanup();
+
+extern int read_mongodb_conf(const char *path, char **uri_p, char **database_p, char **collection_p);
+
+#endif //NETDATA_BACKEND_MONGODB_H