summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/tests.yml2
-rw-r--r--.gitmodules9
-rw-r--r--.lgtm.yml2
-rw-r--r--CMakeLists.txt6
-rw-r--r--Makefile.am47
-rw-r--r--aclk/aclk_util.h6
-rw-r--r--configure.ac109
-rw-r--r--daemon/buildinfo.c11
-rw-r--r--daemon/common.h3
-rw-r--r--daemon/main.c9
-rw-r--r--database/engine/rrdenginelib.h8
-rw-r--r--database/rrd.h9
-rw-r--r--database/rrddim.c6
-rw-r--r--database/rrdhost.c4
-rw-r--r--database/rrdset.c13
-rw-r--r--libnetdata/config/appconfig.c1
-rw-r--r--libnetdata/config/appconfig.h1
-rw-r--r--libnetdata/libnetdata.h7
-rw-r--r--ml/BitBufferCounter.cc29
-rw-r--r--ml/BitBufferCounter.h54
-rw-r--r--ml/BitRateWindow.cc75
-rw-r--r--ml/BitRateWindow.h170
-rw-r--r--ml/Config.cc128
-rw-r--r--ml/Config.h45
-rw-r--r--ml/Database.cc127
-rw-r--r--ml/Database.h131
-rw-r--r--ml/Dimension.cc169
-rw-r--r--ml/Dimension.h124
-rw-r--r--ml/Host.cc458
-rw-r--r--ml/Host.h104
-rw-r--r--ml/Makefile.am8
-rw-r--r--ml/Query.h49
-rw-r--r--ml/Tests.cc301
m---------ml/json0
-rw-r--r--ml/kmeans/KMeans.cc55
-rw-r--r--ml/kmeans/KMeans.h34
-rw-r--r--ml/kmeans/Makefile.am4
-rw-r--r--ml/kmeans/SamplesBuffer.cc144
-rw-r--r--ml/kmeans/SamplesBuffer.h140
-rw-r--r--ml/kmeans/Tests.cc143
m---------ml/kmeans/dlib0
-rw-r--r--ml/ml-dummy.c38
-rw-r--r--ml/ml-private.h26
-rw-r--r--ml/ml.cc153
-rw-r--r--ml/ml.h41
-rwxr-xr-xnetdata-installer.sh6
-rw-r--r--web/api/queries/query.c18
-rw-r--r--web/api/queries/rrdr.h1
-rw-r--r--web/api/web_api_v1.c105
-rw-r--r--web/gui/dashboard_info.js29
50 files changed, 3141 insertions, 21 deletions
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index f13a0bdba5..20c6f7b8c7 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -57,7 +57,7 @@ jobs:
- name: Configure
run: |
autoreconf -ivf
- ./configure
+ ./configure --disable-ml
# XXX: Work-around for bug with libbson-1.0 in Ubuntu 18.04
# See: https://bugs.launchpad.net/ubuntu/+source/libmongoc/+bug/1790771
# https://jira.mongodb.org/browse/CDRIVER-2818
diff --git a/.gitmodules b/.gitmodules
index 83ef65e8d1..0f01d3d680 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,12 @@
[submodule "aclk/aclk-schemas"]
path = aclk/aclk-schemas
url = https://github.com/netdata/aclk-schemas.git
+[submodule "ml/kmeans/dlib"]
+ path = ml/kmeans/dlib
+ url = https://github.com/davisking/dlib.git
+ shallow = true
+ ignore = dirty
+[submodule "ml/json"]
+ path = ml/json
+ url = https://github.com/nlohmann/json.git
+ shallow = true
diff --git a/.lgtm.yml b/.lgtm.yml
index 38f6675cbe..b79f8bb7f6 100644
--- a/.lgtm.yml
+++ b/.lgtm.yml
@@ -17,6 +17,8 @@ path_classifiers:
- collectors/node.d.plugin/node_modules/extend.js
- collectors/node.d.plugin/node_modules/net-snmp.js
- collectors/node.d.plugin/node_modules/pixl-xml.js
+ - ml/kmeans/dlib/
+ - ml/json/
- web/gui/lib/
- web/gui/src/
- web/gui/css/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 873ad9a07f..aa49294e85 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -945,6 +945,11 @@ set(DAEMON_FILES
daemon/unit_test.h
)
+set(ML_FILES
+ ml/ml.h
+ ml/ml-dummy.c
+)
+
set(NETDATA_FILES
collectors/all.h
${DAEMON_FILES}
@@ -954,6 +959,7 @@ set(NETDATA_FILES
${CHECKS_PLUGIN_FILES}
${HEALTH_PLUGIN_FILES}
${IDLEJITTER_PLUGIN_FILES}
+ ${ML_FILES}
${PLUGINSD_PLUGIN_FILES}
${RRD_PLUGIN_FILES}
${REGISTRY_PLUGIN_FILES}
diff --git a/Makefile.am b/Makefile.am
index 508ddf381c..0cc3111aa3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -39,6 +39,7 @@ EXTRA_DIST = \
build/m4/ax_c_mallopt.m4 \
build/m4/tcmalloc.m4 \
build/m4/ax_c__generic.m4 \
+ ml/kmeans/dlib \
README.md \
LICENSE \
REDISTRIBUTED.md \
@@ -117,6 +118,7 @@ SUBDIRS += \
claim \
parser \
spawn \
+ ml \
$(NULL)
if ENABLE_ACLK
@@ -233,6 +235,44 @@ HEALTH_PLUGIN_FILES = \
health/health_log.c \
$(NULL)
+ML_FILES = \
+ ml/ml.h \
+ ml/ml-dummy.c \
+ $(NULL)
+
+if ENABLE_ML
+ML_FILES += \
+ ml/BitBufferCounter.h \
+ ml/BitBufferCounter.cc \
+ ml/BitRateWindow.h \
+ ml/BitRateWindow.cc \
+ ml/Config.h \
+ ml/Config.cc \
+ ml/Database.h \
+ ml/Database.cc \
+ ml/Dimension.cc \
+ ml/Dimension.h \
+ ml/Host.h \
+ ml/Host.cc \
+ ml/Query.h \
+ ml/kmeans/KMeans.h \
+ ml/kmeans/KMeans.cc \
+ ml/kmeans/SamplesBuffer.h \
+ ml/kmeans/SamplesBuffer.cc \
+ ml/kmeans/dlib/dlib/all/source.cpp \
+ ml/json/single_include/nlohmann/json.hpp \
+ ml/ml.cc \
+ ml/ml-private.h \
+ $(NULL)
+endif
+
+if ENABLE_ML_TESTS
+ML_TESTS_FILES = \
+ ml/kmeans/Tests.cc \
+ ml/Tests.cc \
+ $(NULL)
+endif
+
IDLEJITTER_PLUGIN_FILES = \
collectors/idlejitter.plugin/plugin_idlejitter.c \
collectors/idlejitter.plugin/plugin_idlejitter.h \
@@ -863,6 +903,8 @@ NETDATA_FILES = \
$(EXPORTING_ENGINE_FILES) \
$(CHECKS_PLUGIN_FILES) \
$(HEALTH_PLUGIN_FILES) \
+ $(ML_FILES) \
+ $(ML_TESTS_FILES) \
$(IDLEJITTER_PLUGIN_FILES) \
$(PLUGINSD_PLUGIN_FILES) \
$(REGISTRY_PLUGIN_FILES) \
@@ -944,6 +986,11 @@ if ACLK_NG
$(NULL)
endif
+if ENABLE_ML_TESTS
+ netdata_LDADD += $(OPTIONAL_ML_TESTS_LIBS) \
+ $(NULL)
+endif
+
if ACLK_LEGACY
netdata_LDADD += \
$(abs_top_srcdir)/externaldeps/mosquitto/libmosquitto.a \
diff --git a/aclk/aclk_util.h b/aclk/aclk_util.h
index fed1f7c200..750463b1c3 100644
--- a/aclk/aclk_util.h
+++ b/aclk/aclk_util.h
@@ -5,12 +5,6 @@
#include "libnetdata/libnetdata.h"
#include "mqtt_wss_client.h"
-// CentOS 7 has older version that doesn't define this
-// same goes for MacOS
-#ifndef UUID_STR_LEN
-#define UUID_STR_LEN 37
-#endif
-
// Helper stuff which should not have any further inside ACLK dependency
// and are supposed not to be needed outside of ACLK
diff --git a/configure.ac b/configure.ac
index 809192e870..4b42d8481b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -184,6 +184,18 @@ AC_ARG_WITH(
[with_bundled_protobuf="$withval"],
[with_bundled_protobuf="detect"]
)
+AC_ARG_ENABLE(
+ [ml],
+ [AS_HELP_STRING([--enable-ml], [Enable anomaly detection @<:@default autodetect@:>@])],
+ ,
+ [enable_ml="detect"]
+)
+AC_ARG_ENABLE(
+ [ml_tests],
+ [AS_HELP_STRING([--enable-ml-tests], [Enable anomaly detection tests @<:@no@:>@])],
+ [enable_ml_tests="yes"],
+ [enable_ml_tests="no"]
+)
# -----------------------------------------------------------------------------
# Enforce building with C99, bail early if we can't.
@@ -1190,6 +1202,90 @@ AC_MSG_RESULT([${enable_plugin_perf}])
AM_CONDITIONAL([ENABLE_PLUGIN_PERF], [test "${enable_plugin_perf}" = "yes"])
# -----------------------------------------------------------------------------
+# gtest/gmock
+
+AC_MSG_CHECKING([if gtest and gmock can be found])
+
+PKG_CHECK_MODULES([GTEST], [gtest], [have_gtest=yes], [have_gtest=no])
+PKG_CHECK_MODULES([GMOCK], [gmock], [have_gmock=yes], [have_gmock=no])
+
+if test "${have_gtest}" = "yes" -a "${have_gmock}" = "yes"; then
+ OPTIONAL_GTEST_CFLAGS="${GTEST_CFLAGS} ${GMOCK_CFLAGS}"
+ OPTIONAL_GTEST_LIBS="${GTEST_LIBS} ${GMOCK_LIBS}"
+ have_gtest="yes"
+else
+ have_gtest="no"
+fi
+
+# -----------------------------------------------------------------------------
+# ml - anomaly detection
+
+# Check if uuid is availabe. Fail if ML was explicitly requested.
+if test "${enable_ml}" = "yes" -a "${have_uuid}" != "yes"; then
+ AC_MSG_ERROR([You have explicitly requested --enable-ml functionality but libuuid can not be found."])
+fi
+
+# Check if submodules have not been fetched. Fail if ML was explicitly requested.
+AC_MSG_CHECKING([if git submodules are present for machine learning functionality])
+if test -f "ml/kmeans/dlib/dlib/all/source.cpp" -a -f "ml/json/single_include/nlohmann/json.hpp"; then
+ AC_MSG_RESULT([yes])
+ have_ml_submodules="yes"
+else
+ AC_MSG_RESULT([no])
+ have_ml_submodules="no"
+fi
+
+if test "${enable_ml}" = "yes" -a "${have_ml_submodules}" = "no"; then
+ AC_MSG_ERROR([You have explicitly requested --enable-ml functionality but it cannot be built because the required git submodules are missing.])
+fi
+
+# Check if C++ toolchain does not support C++11. Fail if ML was explicitly requested.
+AC_LANG_PUSH([C++])
+AX_CHECK_COMPILE_FLAG([-std=c++11], [have_cxx11=yes], [have_cxx11=no])
+AC_LANG_POP([C++])
+
+# PPC64LE needs -std=gnu++11 in order to build dlib. However, the rest of
+# the agent's components use and have been tested only with -std=c++11.
+# Skip ML compilation on that CPU until we reorganize and test the C++ flags.
+if test "${host_cpu}" = "powerpc64le"; then
+ have_cxx11="no"
+fi
+
+if test "${enable_ml}" = "yes" -a "${have_cxx11}" = "no"; then
+ AC_MSG_ERROR([You have explicitly requested --enable-ml functionality but it cannot be built without a C++11 toolchain.])
+else
+ CXX11FLAG="$CXX11FLAG -std=c++11"
+fi
+
+# Decide if we should build ML
+if test "${enable_ml}" != "no" -a "${have_ml_submodules}" = "yes" -a "${have_cxx11}" = "yes" -a "${have_uuid}" = "yes"; then
+ build_ml="yes"
+else
+ build_ml="no"
+fi
+
+AM_CONDITIONAL([ENABLE_ML], [test "${build_ml}" = "yes"])
+if test "${build_ml}" = "yes"; then
+ AC_DEFINE([ENABLE_ML], [1], [anomaly detection usability])
+ OPTIONAL_ML_CFLAGS="-DDLIB_NO_GUI_SUPPORT -I \$(abs_top_srcdir)/ml/kmeans/dlib"
+ OPTIONAL_ML_LIBS=""
+fi
+
+# Decide if we should build ML tests.
+if test "${build_ml}" = "yes" -a "${enable_ml_tests}" = "yes" -a "${have_gtest}" = "yes"; then
+ build_ml_tests="yes"
+else
+ build_ml_tests="no"
+fi
+
+AM_CONDITIONAL([ENABLE_ML_TESTS], [test "${build_ml_tests}" = "yes"])
+if test "${build_ml_tests}" = "yes"; then
+ AC_DEFINE([ENABLE_ML_TESTS], [1], [anomaly detection tests])
+ OPTIONAL_ML_TESTS_CFLAGS="${OPTIONAL_GTEST_CFLAGS}"
+ OPTIONAL_ML_TESTS_LIBS="${OPTIONAL_GTEST_LIBS}"
+fi
+
+# -----------------------------------------------------------------------------
# ebpf.plugin
if test "${build_target}" = "linux" -a "${enable_ebpf}" != "no"; then
@@ -1557,7 +1653,8 @@ AC_MSG_RESULT([${enable_lto}])
AM_CONDITIONAL([ENABLE_CXX_LINKER], [test "${enable_backend_kinesis}" = "yes" \
-o "${enable_exporting_pubsub}" = "yes" \
-o "${enable_backend_prometheus_remote_write}" = "yes" \
- -o "${new_cloud_protocol}" = "yes"])
+ -o "${new_cloud_protocol}" = "yes" \
+ -o "${build_ml}" = "yes"])
AC_DEFINE_UNQUOTED([NETDATA_USER], ["${with_user}"], [use this user to drop privileged])
@@ -1589,7 +1686,7 @@ CFLAGS="${CFLAGS} ${OPTIONAL_PROTOBUF_CFLAGS} ${OPTIONAL_MATH_CFLAGS} ${OPTIONAL
${OPTIONAL_LIBCAP_CFLAGS} ${OPTIONAL_IPMIMONITORING_CFLAGS} ${OPTIONAL_CUPS_CFLAGS} ${OPTIONAL_XENSTAT_FLAGS} \
${OPTIONAL_KINESIS_CFLAGS} ${OPTIONAL_PUBSUB_CFLAGS} ${OPTIONAL_PROMETHEUS_REMOTE_WRITE_CFLAGS} \
${OPTIONAL_MONGOC_CFLAGS} ${LWS_CFLAGS} ${OPTIONAL_JSONC_STATIC_CFLAGS} ${OPTIONAL_BPF_CFLAGS} ${OPTIONAL_JUDY_CFLAGS} \
- ${OPTIONAL_ACLK_NG_CFLAGS}"
+ ${OPTIONAL_ACLK_NG_CFLAGS} ${OPTIONAL_ML_CFLAGS} ${OPTIONAL_ML_TESTS_CFLAGS}"
CXXFLAGS="${CFLAGS} ${CXX11FLAG}"
@@ -1642,6 +1739,12 @@ AC_SUBST([OPTIONAL_LWS_LIBS])
AC_SUBST([OPTIONAL_ACLK_NG_CFLAGS])
AC_SUBST([OPTIONAL_PROTOBUF_CFLAGS])
AC_SUBST([OPTIONAL_PROTOBUF_LIBS])
+AC_SUBST([OPTIONAL_GTEST_CFLAGS])
+AC_SUBST([OPTIONAL_GTEST_LIBS])
+AC_SUBST([OPTIONAL_ML_CFLAGS])
+AC_SUBST([OPTIONAL_ML_LIBS])
+AC_SUBST([OPTIONAL_ML_TESTS_CFLAGS])
+AC_SUBST([OPTIONAL_ML_TESTS_LIBS])
# -----------------------------------------------------------------------------
# Check if cmocka is available - needed for unit testing
@@ -1731,6 +1834,8 @@ AC_CONFIG_FILES([
exporting/tests/Makefile
health/Makefile
health/notifications/Makefile
+ ml/Makefile
+ ml/kmeans/Makefile
libnetdata/Makefile
libnetdata/tests/Makefile
libnetdata/adaptive_resortable_list/Makefile
diff --git a/daemon/buildinfo.c b/daemon/buildinfo.c
index 7477e3790b..3974074645 100644
--- a/daemon/buildinfo.c
+++ b/daemon/buildinfo.c
@@ -37,6 +37,12 @@
#define FEAT_NATIVE_HTTPS 0
#endif
+#ifdef ENABLE_ML
+#define FEAT_ML 1
+#else
+#define FEAT_ML 0
+#endif
+
// Optional libraries
#ifdef ENABLE_JSONC
@@ -224,6 +230,7 @@ void print_build_info(void) {
printf(" ACLK-NG New Cloud Protocol: %s\n", FEAT_YES_NO(NEW_CLOUD_PROTO));
printf(" ACLK Legacy: %s\n", FEAT_YES_NO(FEAT_ACLK_LEGACY));
printf(" TLS Host Verification: %s\n", FEAT_YES_NO(FEAT_TLS_HOST_VERIFY));
+ printf(" Machine Learning: %s\n", FEAT_YES_NO(FEAT_ML));
printf("Libraries:\n");
printf(" jemalloc: %s\n", FEAT_YES_NO(FEAT_JEMALLOC));
@@ -282,7 +289,8 @@ void print_build_info_json(void) {
printf(" \"aclk-ng-new-cloud-proto\": %s,\n", FEAT_JSON_BOOL(NEW_CLOUD_PROTO));
printf(" \"aclk-legacy\": %s,\n", FEAT_JSON_BOOL(FEAT_ACLK_LEGACY));
- printf(" \"tls-host-verify\": %s\n", FEAT_JSON_BOOL(FEAT_TLS_HOST_VERIFY));
+ printf(" \"tls-host-verify\": %s,\n", FEAT_JSON_BOOL(FEAT_TLS_HOST_VERIFY));
+ printf(" \"machine-learning\": %s\n", FEAT_JSON_BOOL(FEAT_ML));
printf(" },\n");
printf(" \"libs\": {\n");
@@ -337,6 +345,7 @@ void analytics_build_info(BUFFER *b) {
if(NEW_CLOUD_PROTO) buffer_strcat (b, "|New Cloud Protocol Support");
if(FEAT_ACLK_LEGACY) buffer_strcat (b, "|ACLK Legacy");
if(FEAT_TLS_HOST_VERIFY) buffer_strcat (b, "|TLS Host Verification");
+ if(FEAT_ML) buffer_strcat (b, "|Machine Learning");
if(FEAT_JEMALLOC) buffer_strcat (b, "|jemalloc");
if(FEAT_JSONC) buffer_strcat (b, "|JSON-C");
diff --git a/daemon/common.h b/daemon/common.h
index 4c0677d96d..c892dbdb16 100644
--- a/daemon/common.h
+++ b/daemon/common.h
@@ -44,6 +44,9 @@
// health monitoring and alarm notifications
#include "health/health.h"
+// anomaly detection
+#include "ml/ml.h"
+
// the netdata registry
// the registry is actually an API feature
#include "registry/registry.h"
diff --git a/daemon/main.c b/daemon/main.c
index 4bd434637e..0826e09d4f 100644
--- a/daemon/main.c
+++ b/daemon/main.c
@@ -826,6 +826,11 @@ int main(int argc, char **argv) {
fprintf(stderr, "\n\nALL TESTS PASSED\n\n");
return 0;
}
+#ifdef ENABLE_ML_TESTS
+ else if(strcmp(optarg, "mltest") == 0) {
+ return test_ml(argc, argv);
+ }
+#endif
#ifdef ENABLE_DBENGINE
else if(strncmp(optarg, createdataset_string, strlen(createdataset_string)) == 0) {
optarg += strlen(createdataset_string);
@@ -1145,6 +1150,10 @@ int main(int argc, char **argv) {
health_initialize_global_silencers();
// --------------------------------------------------------------------
+ // Initialize ML configuration
+ ml_init();
+
+ // --------------------------------------------------------------------
// setup process signals
// block signals while initializing threads.
diff --git a/database/engine/rrdenginelib.h b/database/engine/rrdenginelib.h
index ebab93c8fe..8b6751f005 100644
--- a/database/engine/rrdenginelib.h
+++ b/database/engine/rrdenginelib.h
@@ -3,6 +3,8 @@
#ifndef NETDATA_RRDENGINELIB_H
#define NETDATA_RRDENGINELIB_H
+#include "libnetdata/libnetdata.h"
+
/* Forward declarations */
struct rrdeng_page_descr;
struct rrdengine_instance;
@@ -12,10 +14,6 @@ struct rrdengine_instance;
#define BITS_PER_ULONG (sizeof(unsigned long) * 8)
-#ifndef UUID_STR_LEN
-#define UUID_STR_LEN (37)
-#endif
-
/* Taken from linux kernel */
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
@@ -141,4 +139,4 @@ extern char *get_rrdeng_statistics(struct rrdengine_instance *ctx, char *str, si
extern int compute_multidb_diskspace();
extern int is_legacy_child(const char *machine_guid);
-#endif /* NETDATA_RRDENGINELIB_H */ \ No newline at end of file
+#endif /* NETDATA_RRDENGINELIB_H */
diff --git a/database/rrd.h b/database/rrd.h
index 95c49eb21e..62edec423f 100644
--- a/database/rrd.h
+++ b/database/rrd.h
@@ -15,6 +15,9 @@ typedef struct rrdcalctemplate RRDCALCTEMPLATE;
typedef struct alarm_entry ALARM_ENTRY;
typedef struct context_param CONTEXT_PARAM;
+typedef void *ml_host_t;
+typedef void *ml_dimension_t;
+
// forward declarations
struct rrddim_volatile;
struct rrdset_volatile;
@@ -421,6 +424,8 @@ struct rrddim_volatile {
// get the timestamp of the first entry of this metric
time_t (*oldest_time)(RRDDIM *rd);
} query_ops;
+
+ ml_dimension_t ml_dimension;
};
// ----------------------------------------------------------------------------
@@ -877,6 +882,10 @@ struct rrdhost {
netdata_rwlock_t rrdhost_rwlock; // lock for this RRDHOST (protects rrdset_root linked list)
// ------------------------------------------------------------------------
+ // ML handle
+ ml_host_t ml_host;
+
+ // ------------------------------------------------------------------------
// Support for host-level labels
struct label_index labels;
diff --git a/database/rrddim.c b/database/rrddim.c
index 5479ade7aa..78885df3dc 100644
--- a/database/rrddim.c
+++ b/database/rrddim.c
@@ -386,7 +386,7 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
rd->last_collected_time.tv_sec = 0;
rd->last_collected_time.tv_usec = 0;
rd->rrdset = st;
- rd->state = mallocz(sizeof(*rd->state));
+ rd->state = callocz(1, sizeof(*rd->state));
#ifdef ENABLE_ACLK
rd->state->aclk_live_status = -1;
#endif
@@ -454,6 +454,8 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
calc_link_to_rrddim(rd);
+ ml_new_dimension(rd);
+
rrdset_unlock(st);
#ifdef ENABLE_ACLK
rrdset_flag_clear(st, RRDSET_FLAG_ACLK);
@@ -466,6 +468,8 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
void rrddim_free_custom(RRDSET *st, RRDDIM *rd, int db_rotated)
{
+ ml_delete_dimension(rd);
+
#ifndef ENABLE_ACLK
UNUSED(db_rotated);
#endif
diff --git a/database/rrdhost.c b/database/rrdhost.c
index abb14beaf4..b28db1e3e4 100644
--- a/database/rrdhost.c
+++ b/database/rrdhost.c
@@ -382,6 +382,8 @@ RRDHOST *rrdhost_create(const char *hostname,
else localhost = host;
}
+ ml_new_host(host);
+
info("Host '%s' (at registry as '%s') with guid '%s' initialized"
", os '%s'"
", timezone '%s'"
@@ -906,6 +908,8 @@ void rrdhost_free(RRDHOST *host) {
rrdeng_exit(host->rrdeng_ctx);
#endif
+ ml_delete_host(host);
+
// ------------------------------------------------------------------------
// remove it from the indexes
diff --git a/database/rrdset.c b/database/rrdset.c
index 282b0e5ba1..c0ac3be7b8 100644
--- a/database/rrdset.c
+++ b/database/rrdset.c
@@ -1237,13 +1237,22 @@ static inline size_t rrdset_done_interpolate(
}
if(unlikely(!store_this_entry)) {
+ (void) ml_is_anomalous(rd, 0, false);
+
rd->state->collect_ops.store_metric(rd, next_store_ut, SN_EMPTY_SLOT);
// rd->values[current_entry] = SN_EMPTY_SLOT;
continue;
}
if(likely(rd->updated && rd->collections_counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
- rd->state->collect_ops.store_metric(rd, next_store_ut, pack_storage_number(new_value, storage_flags));
+ uint32_t dim_storage_flags = storage_flags;
+
+ if (ml_is_anomalous(rd, new_value, true)) {
+ // clear anomaly bit: 0 -> is anomalous, 1 -> not anomalous
+ dim_storage_flags &= ~ ((uint32_t) SN_ANOMALY_BIT);
+ }
+
+ rd->state->collect_ops.store_metric(rd, next_store_ut, pack_storage_number(new_value, dim_storage_flags));
// rd->values[current_entry] = pack_storage_number(new_value, storage_flags );
rd->last_stored_value = new_value;
@@ -1255,9 +1264,9 @@ static inline size_t rrdset_done_interpolate(
, unpack_storage_number(rd->values[current_entry]), new_value
);
#endif
-
}
else {
+ (void) ml_is_anomalous(rd, 0, false);
#ifdef NETDATA_INTERNAL_CHECKS
rrdset_debug(st, "%s: STORE[%ld] = NON EXISTING "
diff --git a/libnetdata/config/appconfig.c b/libnetdata/config/appconfig.c
index 90fa6ab852..37e9e76886 100644
--- a/libnetdata/config/appconfig.c
+++ b/libnetdata/config/appconfig.c
@@ -796,6 +796,7 @@ void appconfig_generate(struct config *root, BUFFER *wb, int only_changed)
|| !strcmp(co->name, CONFIG_SECTION_BACKEND)
|| !strcmp(co->name, CONFIG_SECTION_STREAM)
|| !strcmp(co->name, CONFIG_SECTION_HOST_LABEL)
+ || !strcmp(co->name, CONFIG_SECTION_ML)
)
pri = 0;
else if(!strncmp(co->name, "plugin:", 7)) pri = 1;
diff --git a/libnetdata/config/appconfig.h b/libnetdata/config/appconfig.h
index 246d1d5b92..bfc927353a 100644
--- a/libnetdata/config/appconfig.h
+++ b/libnetdata/config/appconfig.h
@@ -91,6 +91,7 @@
#define CONFIG_SECTION_HEALTH "health"
#define CONFIG_SECTION_BACKEND "backend"
#define CONFIG_SECTION_STREAM "stream"
+#define CONFIG_SECTION_ML "ml"
#define CONFIG_SECTION_EXPORTING "exporting:global"
#define CONFIG_SECTION_PROMETHEUS "prometheus:exporter"
#define CONFIG_SECTION_HOST_LABEL "host labels"
diff --git a/libnetdata/libnetdata.h b/libnetdata/libnetdata.h
index 77a1bbe7fd..b49ab21a08 100644
--- a/libnetdata/libnetdata.h
+++ b/libnetdata/libnetdata.h
@@ -53,6 +53,7 @@ extern "C" {
#include <pthread.h>
#include <errno.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -90,6 +91,12 @@ extern "C" {
#include <uv.h>
#include <assert.h>
+// CentOS 7 has older version that doesn't define this
+// same goes for MacOS
+#ifndef UUID_STR_LEN
+#define UUID_STR_LEN (37)
+#endif
+
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
diff --git a/ml/BitBufferCounter.cc b/ml/BitBufferCounter.cc
new file mode 100644
index 0000000000..5e1ab5aca3
--- /dev/null
+++ b/ml/BitBufferCounter.cc
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "BitBufferCounter.h"
+
+using namespace ml;
+
+std::vector<bool> BitBufferCounter::getBuffer() const {
+ std::vector<bool> Buffer;
+
+ for (size_t Idx = start(); Idx != (start() + size()); Idx++)
+ Buffer.push_back(V[Idx % V.size()]);
+
+ return Buffer;
+}
+
+void BitBufferCounter::insert(bool Bit) {
+ if (N >= V.size())
+ NumSetBits -= (V[start()] == true);
+
+ NumSetBits += (Bit == true);
+ V[N++ % V.size()] = Bit;
+}
+
+void BitBufferCounter::print(std::ostream &OS) const {
+ std::vector<bool> Buffer = getBuffer();
+
+ for (bool B : Buffer)
+ OS << B;