Remove backends subsystem (#12146)

This commit is contained in:
Vladimir Kobal 2022-03-15 11:50:24 +01:00 committed by GitHub
parent 908d369195
commit 52456f5baf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
88 changed files with 211 additions and 5248 deletions

5
.github/CODEOWNERS vendored
View File

@ -8,11 +8,6 @@
.travis/ @Ferroin @iigorkarpov @maneamarius @kaskavel
.github/ @Ferroin @iigorkarpov @maneamarius @kaskavel
aclk/ @stelfrag @underhood
backends/ @thiagoftsm @vlvkobal
backends/graphite/ @thiagoftsm @vlvkobal
backends/json/ @thiagoftsm @vlvkobal
backends/opentsdb/ @thiagoftsm @vlvkobal
backends/prometheus/ @vlvkobal @thiagoftsm
build/ @Ferroin @iigorkarpov @maneamarius
contrib/debian @Ferroin @iigorkarpov @maneamarius
collectors/ @vlvkobal

4
.github/labeler.yml vendored
View File

@ -15,10 +15,6 @@ ACLK:
- aclk/**/*
- mqtt_websockets
area/backends:
- backends/*
- backends/**/*
area/claim:
- claim/*

View File

@ -745,19 +745,6 @@ set(STREAMING_PLUGIN_FILES
streaming/sender.c
)
set(BACKENDS_PLUGIN_FILES
backends/backends.c
backends/backends.h
backends/graphite/graphite.c
backends/graphite/graphite.h
backends/json/json.c
backends/json/json.h
backends/opentsdb/opentsdb.c
backends/opentsdb/opentsdb.h
backends/prometheus/backend_prometheus.c
backends/prometheus/backend_prometheus.h
)
set(CLAIM_PLUGIN_FILES
claim/claim.c
claim/claim.h
@ -884,23 +871,6 @@ set(MONGODB_EXPORTING_FILES
exporting/mongodb/mongodb.h
)
set(KINESIS_BACKEND_FILES
backends/aws_kinesis/aws_kinesis.c
backends/aws_kinesis/aws_kinesis.h
backends/aws_kinesis/aws_kinesis_put_record.cc
backends/aws_kinesis/aws_kinesis_put_record.h
)
set(PROMETHEUS_REMOTE_WRITE_BACKEND_FILES
backends/prometheus/remote_write/remote_write.cc
backends/prometheus/remote_write/remote_write.h
)
set(MONGODB_BACKEND_FILES
backends/mongodb/mongodb.c
backends/mongodb/mongodb.h
)
set(DAEMON_FILES
daemon/buildinfo.c
daemon/buildinfo.h
@ -960,7 +930,6 @@ set(NETDATA_FILES
collectors/all.h
${DAEMON_FILES}
${API_PLUGIN_FILES}
${BACKENDS_PLUGIN_FILES}
${EXPORTING_ENGINE_FILES}
${CHECKS_PLUGIN_FILES}
${HEALTH_PLUGIN_FILES}
@ -997,25 +966,25 @@ add_definitions(
)
# -----------------------------------------------------------------------------
# kinesis backend
# kinesis exporting connector
IF(KINESIS_LIBRARIES AND AWS_CORE_LIBRARIES AND HAVE_AWS_EVENT_STREAM AND HAVE_AWS_COMMON AND HAVE_AWS_CHECKSUMS AND
CRYPTO_LIBRARIES AND SSL_LIBRARIES AND CURL_LIBRARIES)
SET(ENABLE_BACKEND_KINESIS True)
SET(ENABLE_EXPORTING_KINESIS True)
ELSE()
SET(ENABLE_BACKEND_KINESIS False)
SET(ENABLE_EXPORTING_KINESIS False)
ENDIF()
IF(ENABLE_BACKEND_KINESIS)
message(STATUS "kinesis backend: enabled")
list(APPEND NETDATA_FILES ${KINESIS_BACKEND_FILES} ${KINESIS_EXPORTING_FILES})
IF(ENABLE_EXPORTING_KINESIS)
message(STATUS "kinesis exporting: enabled")
list(APPEND NETDATA_FILES ${KINESIS_EXPORTING_FILES})
list(APPEND NETDATA_COMMON_LIBRARIES ${KINESIS_LIBRARIES} ${AWS_CORE_LIBRARIES}
${CRYPTO_LIBRARIES} ${SSL_LIBRARIES} ${CURL_LIBRARIES})
list(APPEND NETDATA_COMMON_INCLUDE_DIRS ${KINESIS_INCLUDE_DIRS} ${AWS_CORE_INCLUDE_DIRS}
${CRYPTO_INCLUDE_DIRS} ${SSL_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS})
list(APPEND NETDATA_COMMON_CFLAGS ${CRYPTO_CFLAGS_OTHER} ${SSL_CFLAGS_OTHER} ${CURL_CFLAGS_OTHER})
ELSE()
message(STATUS "kinesis backend: disabled (requires AWS SDK for C++)")
message(STATUS "kinesis exporting: disabled (requires AWS SDK for C++)")
ENDIF()
# -----------------------------------------------------------------------------
@ -1038,16 +1007,16 @@ ELSE()
ENDIF()
# -----------------------------------------------------------------------------
# prometheus remote write backend
# prometheus remote write exporting connector
IF(PROTOBUF_LIBRARIES AND SNAPPY_LIBRARIES)
SET(ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE True)
SET(ENABLE_EXPORTING_PROMETHEUS_REMOTE_WRITE True)
ELSE()
SET(ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE False)
SET(ENABLE_EXPORTING_PROMETHEUS_REMOTE_WRITE False)
ENDIF()
IF(ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE)
message(STATUS "prometheus remote write backend: enabled")
IF(ENABLE_EXPORTING_PROMETHEUS_REMOTE_WRITE)
message(STATUS "prometheus remote write exporting: enabled")
find_package(Protobuf REQUIRED)
@ -1083,26 +1052,26 @@ IF(ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE)
protobuf_remote_write_generate_cpp(PROTO_SRCS PROTO_HDRS exporting/prometheus/remote_write/remote_write.proto)
list(APPEND NETDATA_FILES ${PROMETHEUS_REMOTE_WRITE_BACKEND_FILES} ${PROMETHEUS_REMOTE_WRITE_EXPORTING_FILES} ${PROTO_SRCS} ${PROTO_HDRS})
list(APPEND NETDATA_FILES ${PROMETHEUS_REMOTE_WRITE_EXPORTING_FILES} ${PROTO_SRCS} ${PROTO_HDRS})
list(APPEND NETDATA_COMMON_LIBRARIES ${PROTOBUF_LIBRARIES} ${SNAPPY_LIBRARIES})
list(APPEND NETDATA_COMMON_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS} ${SNAPPY_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
list(APPEND NETDATA_COMMON_CFLAGS ${PROTOBUF_CFLAGS_OTHER} ${SNAPPY_CFLAGS_OTHER})
ELSE()
message(STATUS "prometheus remote write backend: disabled (requires protobuf and snappy libraries)")
message(STATUS "prometheus remote write exporting: disabled (requires protobuf and snappy libraries)")
ENDIF()
# -----------------------------------------------------------------------------
# mongodb backend
# mongodb exporting connector
IF(MONGOC_LIBRARIES)
message(STATUS "mongodb backend: enabled")
message(STATUS "mongodb exporting: enabled")
list(APPEND NETDATA_FILES ${MONGODB_BACKEND_FILES} ${MONGODB_EXPORTING_FILES})
list(APPEND NETDATA_FILES ${MONGODB_EXPORTING_FILES})
list(APPEND NETDATA_COMMON_LIBRARIES ${MONGOC_LIBRARIES})
list(APPEND NETDATA_COMMON_INCLUDE_DIRS ${MONGOC_INCLUDE_DIRS})
list(APPEND NETDATA_COMMON_CFLAGS ${MONGOC_CFLAGS_OTHER})
ELSE()
message(STATUS "mongodb backend: disabled (requires mongoc library)")
message(STATUS "mongodb exporting: disabled (requires mongoc library)")
ENDIF()
set(NETDATA_COMMON_LIBRARIES ${NETDATA_COMMON_LIBRARIES} m ${CMAKE_THREAD_LIBS_INIT})
@ -1223,7 +1192,7 @@ ELSEIF(MACOS)
ENDIF()
IF(ENABLE_BACKEND_KINESIS OR ENABLE_EXPORTING_PUBSUB OR ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE)
IF(ENABLE_EXPORTING_KINESIS OR ENABLE_EXPORTING_PUBSUB OR ENABLE_EXPORTING_PROMETHEUS_REMOTE_WRITE)
set_property(TARGET netdata PROPERTY CXX_STANDARD 11)
set_property(TARGET netdata PROPERTY CMAKE_CXX_STANDARD_REQUIRED ON)
ENDIF()
@ -1397,7 +1366,7 @@ if(BUILD_TESTING)
set(KINESIS_LINK_OPTIONS)
set(PUBSUB_LINK_OPTIONS)
set(MONGODB_LINK_OPTIONS)
if(ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE)
if(ENABLE_EXPORTING_PROMETHEUS_REMOTE_WRITE)
list(APPEND EXPORTING_ENGINE_FILES ${PROMETHEUS_REMOTE_WRITE_EXPORTING_FILES} ${PROTO_SRCS} ${PROTO_HDRS})
list(
APPEND PROMETHEUS_REMOTE_WRITE_LINK_OPTIONS
@ -1407,7 +1376,7 @@ if(ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE)
-Wl,--wrap=add_metric
)
endif()
if(ENABLE_BACKEND_KINESIS)
if(ENABLE_EXPORTING_KINESIS)
list(APPEND EXPORTING_ENGINE_FILES ${KINESIS_EXPORTING_FILES})
list(
APPEND KINESIS_LINK_OPTIONS

View File

@ -99,7 +99,6 @@ dist_noinst_SCRIPTS = \
# Compile netdata binaries
SUBDIRS += \
backends \
collectors \
daemon \
database \
@ -580,19 +579,6 @@ WEB_PLUGIN_FILES = \
web/server/static/static-threaded.h \
$(NULL)
BACKENDS_PLUGIN_FILES = \
backends/backends.c \
backends/backends.h \
backends/graphite/graphite.c \
backends/graphite/graphite.h \
backends/json/json.c \
backends/json/json.h \
backends/opentsdb/opentsdb.c \
backends/opentsdb/opentsdb.h \
backends/prometheus/backend_prometheus.c \
backends/prometheus/backend_prometheus.h \
$(NULL)
CLAIM_FILES = \
claim/claim.c \
claim/claim.h \
@ -831,23 +817,6 @@ MONGODB_EXPORTING_FILES = \
exporting/mongodb/mongodb.h \
$(NULL)
KINESIS_BACKEND_FILES = \
backends/aws_kinesis/aws_kinesis.c \
backends/aws_kinesis/aws_kinesis.h \
backends/aws_kinesis/aws_kinesis_put_record.cc \
backends/aws_kinesis/aws_kinesis_put_record.h \
$(NULL)
PROMETHEUS_REMOTE_WRITE_BACKEND_FILES = \
backends/prometheus/remote_write/remote_write.cc \
backends/prometheus/remote_write/remote_write.h \
$(NULL)
MONGODB_BACKEND_FILES = \
backends/mongodb/mongodb.c \
backends/mongodb/mongodb.h \
$(NULL)
DAEMON_FILES = \
daemon/buildinfo.c \
daemon/buildinfo.h \
@ -877,7 +846,6 @@ NETDATA_FILES = \
$(DAEMON_FILES) \
$(LIBNETDATA_FILES) \
$(API_PLUGIN_FILES) \
$(BACKENDS_PLUGIN_FILES) \
$(EXPORTING_ENGINE_FILES) \
$(CHECKS_PLUGIN_FILES) \
$(HEALTH_PLUGIN_FILES) \
@ -1065,8 +1033,8 @@ if ENABLE_PLUGIN_SLABINFO
$(NULL)
endif
if ENABLE_BACKEND_KINESIS
netdata_SOURCES += $(KINESIS_BACKEND_FILES) $(KINESIS_EXPORTING_FILES)
if ENABLE_EXPORTING_KINESIS
netdata_SOURCES += $(KINESIS_EXPORTING_FILES)
netdata_LDADD += $(OPTIONAL_KINESIS_LIBS)
endif
@ -1075,17 +1043,17 @@ if ENABLE_EXPORTING_PUBSUB
netdata_LDADD += $(OPTIONAL_PUBSUB_LIBS)
endif
if ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE
netdata_SOURCES += $(PROMETHEUS_REMOTE_WRITE_BACKEND_FILES) $(PROMETHEUS_REMOTE_WRITE_EXPORTING_FILES)
if ENABLE_EXPORTING_PROMETHEUS_REMOTE_WRITE
netdata_SOURCES += $(PROMETHEUS_REMOTE_WRITE_EXPORTING_FILES)
netdata_LDADD += $(OPTIONAL_PROMETHEUS_REMOTE_WRITE_LIBS) \
$(OPTIONAL_PROTOBUF_LIBS) \
$(NULL)
BACKEND_PROMETHEUS_BUILT_SOURCES = \
EXPORTING_PROMETHEUS_BUILT_SOURCES = \
exporting/prometheus/remote_write/remote_write.pb.cc \
exporting/prometheus/remote_write/remote_write.pb.h \
$(NULL)
BUILT_SOURCES += $(BACKEND_PROMETHEUS_BUILT_SOURCES)
nodist_netdata_SOURCES += $(BACKEND_PROMETHEUS_BUILT_SOURCES)
BUILT_SOURCES += $(EXPORTING_PROMETHEUS_BUILT_SOURCES)
nodist_netdata_SOURCES += $(EXPORTING_PROMETHEUS_BUILT_SOURCES)
exporting/prometheus/remote_write/remote_write.pb.cc \
exporting/prometheus/remote_write/remote_write.pb.h: exporting/prometheus/remote_write/remote_write.proto
@ -1093,8 +1061,8 @@ exporting/prometheus/remote_write/remote_write.pb.h: exporting/prometheus/remote
endif
if ENABLE_BACKEND_MONGODB
netdata_SOURCES += $(MONGODB_BACKEND_FILES) $(MONGODB_EXPORTING_FILES)
if ENABLE_EXPORTING_MONGODB
netdata_SOURCES += $(MONGODB_EXPORTING_FILES)
netdata_LDADD += $(OPTIONAL_MONGOC_LIBS)
endif
@ -1217,7 +1185,7 @@ if ENABLE_UNITTESTS
$(TEST_LDFLAGS) \
$(NULL)
exporting_tests_exporting_engine_testdriver_LDADD = $(NETDATA_COMMON_LIBS) $(TEST_LIBS)
if ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE
if ENABLE_EXPORTING_PROMETHEUS_REMOTE_WRITE
exporting_tests_exporting_engine_testdriver_SOURCES += $(PROMETHEUS_REMOTE_WRITE_EXPORTING_FILES)
exporting_tests_exporting_engine_testdriver_LDADD += \
$(OPTIONAL_PROMETHEUS_REMOTE_WRITE_LIBS) \
@ -1229,9 +1197,9 @@ if ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE
-Wl,--wrap=add_label \
-Wl,--wrap=add_metric \
$(NULL)
nodist_exporting_tests_exporting_engine_testdriver_SOURCES = $(BACKEND_PROMETHEUS_BUILT_SOURCES)
nodist_exporting_tests_exporting_engine_testdriver_SOURCES = $(EXPORTING_PROMETHEUS_BUILT_SOURCES)
endif
if ENABLE_BACKEND_KINESIS
if ENABLE_EXPORTING_KINESIS
exporting_tests_exporting_engine_testdriver_SOURCES += $(KINESIS_EXPORTING_FILES)
exporting_tests_exporting_engine_testdriver_LDADD += $(OPTIONAL_KINESIS_LIBS)
exporting_tests_exporting_engine_testdriver_LDFLAGS += \
@ -1251,7 +1219,7 @@ if ENABLE_EXPORTING_PUBSUB
-Wl,--wrap=pubsub_get_result \
$(NULL)
endif
if ENABLE_BACKEND_MONGODB
if ENABLE_EXPORTING_MONGODB
exporting_tests_exporting_engine_testdriver_SOURCES += $(MONGODB_EXPORTING_FILES)
exporting_tests_exporting_engine_testdriver_LDADD += $(OPTIONAL_MONGOC_LIBS)
exporting_tests_exporting_engine_testdriver_LDFLAGS += \

View File

@ -1,22 +0,0 @@
# SPDX-License-Identifier: GPL-3.0-or-later
AUTOMAKE_OPTIONS = subdir-objects
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
SUBDIRS = \
graphite \
json \
opentsdb \
prometheus \
aws_kinesis \
mongodb \
$(NULL)
dist_noinst_DATA = \
README.md \
WALKTHROUGH.md \
$(NULL)
dist_noinst_SCRIPTS = \
nc-backend.sh \
$(NULL)

View File

@ -1,236 +0,0 @@
<!--
title: "Metrics long term archiving"
custom_edit_url: https://github.com/netdata/netdata/edit/master/backends/README.md
-->
# Metrics long term archiving
> ⚠️ The backends system is now deprecated in favor of the [exporting engine](/exporting/README.md).
Netdata supports backends for archiving the metrics, or providing long term dashboards, using Grafana or other tools,
like this:
![image](https://cloud.githubusercontent.com/assets/2662304/20649711/29f182ba-b4ce-11e6-97c8-ab2c0ab59833.png)
Since Netdata collects thousands of metrics per server per second, which would easily congest any backend server when
several Netdata servers are sending data to it, Netdata allows sending metrics at a lower frequency, by resampling them.
So, although Netdata collects metrics every second, it can send to the backend servers averages or sums every X seconds
(though, it can send them per second if you need it to).
## features
1. Supported backends
- **graphite** (`plaintext interface`, used by **Graphite**, **InfluxDB**, **KairosDB**, **Blueflood**,
**ElasticSearch** via logstash tcp input and the graphite codec, etc)
metrics are sent to the backend server as `prefix.hostname.chart.dimension`. `prefix` is configured below,
`hostname` is the hostname of the machine (can also be configured).
- **opentsdb** (`telnet or HTTP interfaces`, used by **OpenTSDB**, **InfluxDB**, **KairosDB**, etc)
metrics are sent to opentsdb as `prefix.chart.dimension` with tag `host=hostname`.
- **json** document DBs
metrics are sent to a document db, `JSON` formatted.
- **prometheus** is described at [prometheus page](/backends/prometheus/README.md) since it pulls data from
Netdata.
- **prometheus remote write** (a binary snappy-compressed protocol buffer encoding over HTTP used by
**Elasticsearch**, **Gnocchi**, **Graphite**, **InfluxDB**, **Kafka**, **OpenTSDB**, **PostgreSQL/TimescaleDB**,
**Splunk**, **VictoriaMetrics**, and a lot of other [storage
providers](https://prometheus.io/docs/operating/integrations/#remote-endpoints-and-storage))
metrics are labeled in the format, which is used by Netdata for the [plaintext prometheus
protocol](/backends/prometheus/README.md). Notes on using the remote write backend are [here](/backends/prometheus/remote_write/README.md).
- **TimescaleDB** via [community-built connector](/backends/TIMESCALE.md) that takes JSON streams from a Netdata
client and writes them to a TimescaleDB table.
- **AWS Kinesis Data Streams**
metrics are sent to the service in `JSON` format.
- **MongoDB**
metrics are sent to the database in `JSON` format.
2. Only one backend may be active at a time.
3. Netdata can filter metrics (at the chart level), to send only a subset of the collected metrics.
4. Netdata supports three modes of operation for all backends:
- `as-collected` sends to backends the metrics as they are collected, in the units they are collected. So,
counters are sent as counters and gauges are sent as gauges, much like all data collectors do. For example, to
calculate CPU utilization in this format, you need to know how to convert kernel ticks to percentage.
- `average` sends to backends normalized metrics from the Netdata database. In this mode, all metrics are sent as
gauges, in the units Netdata uses. This abstracts data collection and simplifies visualization, but you will not
be able to copy and paste queries from other sources to convert units. For example, CPU utilization percentage
is calculated by Netdata, so Netdata will convert ticks to percentage and send the average percentage to the
backend.
- `sum` or `volume`: the sum of the interpolated values shown on the Netdata graphs is sent to the backend. So, if
Netdata is configured to send data to the backend every 10 seconds, the sum of the 10 values shown on the
Netdata charts will be used.
Time-series databases suggest to collect the raw values (`as-collected`). If you plan to invest on building your
monitoring around a time-series database and you already know (or you will invest in learning) how to convert units
and normalize the metrics in Grafana or other visualization tools, we suggest to use `as-collected`.
If, on the other hand, you just need long term archiving of Netdata metrics and you plan to mainly work with
Netdata, we suggest to use `average`. It decouples visualization from data collection, so it will generally be a lot
simpler. Furthermore, if you use `average`, the charts shown in the back-end will match exactly what you see in
Netdata, which is not necessarily true for the other modes of operation.
5. This code is smart enough, not to slow down Netdata, independently of the speed of the backend server.
## configuration
In `/etc/netdata/netdata.conf` you should have something like this (if not download the latest version of `netdata.conf`
from your Netdata):
```conf
[backend]
enabled = yes | no
type = graphite | opentsdb:telnet | opentsdb:http | opentsdb:https | prometheus_remote_write | json | kinesis | mongodb
host tags = list of TAG=VALUE
destination = space separated list of [PROTOCOL:]HOST[:PORT] - the first working will be used, or a region for kinesis
data source = average | sum | as collected
prefix = Netdata
hostname = my-name
update every = 10
buffer on failures = 10
timeout ms = 20000
send charts matching = *
send hosts matching = localhost *
send names instead of ids = yes
```
- `enabled = yes | no`, enables or disables sending data to a backend
- `type = graphite | opentsdb:telnet | opentsdb:http | opentsdb:https | json | kinesis | mongodb`, selects the backend
type
- `destination = host1 host2 host3 ...`, accepts **a space separated list** of hostnames, IPs (IPv4 and IPv6) and
ports to connect to. Netdata will use the **first available** to send the metrics.
The format of each item in this list, is: `[PROTOCOL:]IP[:PORT]`.
`PROTOCOL` can be `udp` or `tcp`. `tcp` is the default and only supported by the current backends.
`IP` can be `XX.XX.XX.XX` (IPv4), or `[XX:XX...XX:XX]` (IPv6). For IPv6 you can to enclose the IP in `[]` to
separate it from the port.
`PORT` can be a number of a service name. If omitted, the default port for the backend will be used
(graphite = 2003, opentsdb = 4242).
Example IPv4:
```conf
destination = 10.11.14.2:4242 10.11.14.3:4242 10.11.14.4:4242
```
Example IPv6 and IPv4 together:
```conf
destination = [ffff:...:0001]:2003 10.11.12.1:2003
```
When multiple servers are defined, Netdata will try the next one when the first one fails. This allows you to
load-balance different servers: give your backend servers in different order on each Netdata.
Netdata also ships `nc-backend.sh`, a script that can be used as a fallback backend to save the
metrics to disk and push them to the time-series database when it becomes available again. It can also be used to
monitor / trace / debug the metrics Netdata generates.
For kinesis backend `destination` should be set to an AWS region (for example, `us-east-1`).
The MongoDB backend doesn't use the `destination` option for its configuration. It uses the `mongodb.conf`
[configuration file](/backends/mongodb/README.md) instead.
- `data source = as collected`, or `data source = average`, or `data source = sum`, selects the kind of data that will
be sent to the backend.
- `hostname = my-name`, is the hostname to be used for sending data to the backend server. By default this is
`[global].hostname`.
- `prefix = Netdata`, is the prefix to add to all metrics.
- `update every = 10`, is the number of seconds between sending data to the backend. Netdata will add some randomness
to this number, to prevent stressing the backend server when many Netdata servers send data to the same backend.
This randomness does not affect the quality of the data, only the time they are sent.
- `buffer on failures = 10`, is the number of iterations (each iteration is `[backend].update every` seconds) to
buffer data, when the backend is not available. If the backend fails to receive the data after that many failures,
data loss on the backend is expected (Netdata will also log it).
- `timeout ms = 20000`, is the timeout in milliseconds to wait for the backend server to process the data. By default
this is `2 * update_every * 1000`.
- `send hosts matching = localhost *` includes one or more space separated patterns, using `*` as wildcard (any number
of times within each pattern). The patterns are checked against the hostname (the localhost is always checked as
`localhost`), allowing us to filter which hosts will be sent to the backend when this Netdata is a central Netdata
aggregating multiple hosts. A pattern starting with `!` gives a negative match. So to match all hosts named `*db*`
except hosts containing `*child*`, use `!*child* *db*` (so, the order is important: the first pattern
matching the hostname will be used - positive or negative).
- `send charts matching = *` includes one or more space separated patterns, using `*` as wildcard (any number of times
within each pattern). The patterns are checked against both chart id and chart name. A pattern starting with `!`
gives a negative match. So to match all charts named `apps.*` except charts ending in `*reads`, use `!*reads
apps.*` (so, the order is important: the first pattern matching the chart id or the chart name will be used -
positive or negative).
- `send names instead of ids = yes | no` controls the metric names Netdata should send to backend. Netdata supports
names and IDs for charts and dimensions. Usually IDs are unique identifiers as read by the system and names are
human friendly labels (also unique). Most charts and metrics have the same ID and name, but in several cases they
are different: disks with device-mapper, interrupts, QoS classes, statsd synthetic charts, etc.
- `host tags = list of TAG=VALUE` defines tags that should be appended on all metrics for the given host. These are
currently only sent to graphite, json, opentsdb and prometheus. Please use the appropriate format for each
time-series db. For example opentsdb likes them like `TAG1=VALUE1 TAG2=VALUE2`, but prometheus like `tag1="value1",
tag2="value2"`. Host tags are mirrored with database replication (streaming of metrics between Netdata servers).
Starting from Netdata v1.20 the host tags are parsed in accordance with a configured backend type and stored as
host labels so that they can be reused in API responses and exporting connectors. The parsing is supported for
graphite, json, opentsdb, and prometheus (default) backend types. You can check how the host tags were parsed using
the /api/v1/info API call.
## monitoring operation
Netdata provides 5 charts:
1. **Buffered metrics**, the number of metrics Netdata added to the buffer for dispatching them to the
backend server.
2. **Buffered data size**, the amount of data (in KB) Netdata added the buffer.
3. ~~**Backend latency**, the time the backend server needed to process the data Netdata sent. If there was a
re-connection involved, this includes the connection time.~~ (this chart has been removed, because it only measures
the time Netdata needs to give the data to the O/S - since the backend servers do not ack the reception, Netdata
does not have any means to measure this properly).
4. **Backend operations**, the number of operations performed by Netdata.
5. **Backend thread CPU usage**, the CPU resources consumed by the Netdata thread, that is responsible for sending the
metrics to the backend server.
![image](https://cloud.githubusercontent.com/assets/2662304/20463536/eb196084-af3d-11e6-8ee5-ddbd3b4d8449.png)
## alarms
Netdata adds 4 alarms:
1. `backend_last_buffering`, number of seconds since the last successful buffering of backend data
2. `backend_metrics_sent`, percentage of metrics sent to the backend server
3. `backend_metrics_lost`, number of metrics lost due to repeating failures to contact the backend server
4. ~~`backend_slow`, the percentage of time between iterations needed by the backend time to process the data sent by
Netdata~~ (this was misleading and has been removed).
![image](https://cloud.githubusercontent.com/assets/2662304/20463779/a46ed1c2-af43-11e6-91a5-07ca4533cac3.png)

View File

@ -1,57 +0,0 @@
<!--
title: "Writing metrics to TimescaleDB"
custom_edit_url: https://github.com/netdata/netdata/edit/master/backends/TIMESCALE.md
-->
# Writing metrics to TimescaleDB
Thanks to Netdata's community of developers and system administrators, and Mahlon Smith
([GitHub](https://github.com/mahlonsmith)/[Website](http://www.martini.nu/)) in particular, Netdata now supports
archiving metrics directly to TimescaleDB.
What's TimescaleDB? Here's how their team defines the project on their [GitHub page](https://github.com/timescale/timescaledb):
> TimescaleDB is an open-source database designed to make SQL scalable for time-series data. It is engineered up from
> PostgreSQL, providing automatic partitioning across time and space (partitioning key), as well as full SQL support.
## Quickstart
To get started archiving metrics to TimescaleDB right away, check out Mahlon's [`netdata-timescale-relay`
repository](https://github.com/mahlonsmith/netdata-timescale-relay) on GitHub.
This small program takes JSON streams from a Netdata client and writes them to a PostgreSQL (aka TimescaleDB) table.
You'll run this program in parallel with Netdata, and after a short [configuration
process](https://github.com/mahlonsmith/netdata-timescale-relay#configuration), your metrics should start populating
TimescaleDB.
Finally, another member of Netdata's community has built a project that quickly launches Netdata, TimescaleDB, and
Grafana in easy-to-manage Docker containers. Rune Juhl Jacobsen's
[project](https://github.com/runejuhl/grafana-timescaledb) uses a `Makefile` to create everything, which makes it
perfect for testing and experimentation.
## Netdata&#8596;TimescaleDB in action
Aside from creating incredible contributions to Netdata, Mahlon works at [LAIKA](https://www.laika.com/), an
Oregon-based animation studio that's helped create acclaimed films like _Coraline_ and _Kubo and the Two Strings_.
As part of his work to maintain the company's infrastructure of render farms, workstations, and virtual machines, he's
using Netdata, `netdata-timescale-relay`, and TimescaleDB to store Netdata metrics alongside other data from other
sources.
> LAIKA is a long-time PostgreSQL user and added TimescaleDB to their infrastructure in 2018 to help manage and store
> their IT metrics and time-series data. So far, the tool has been in production at LAIKA for over a year and helps them
> with their use case of time-based logging, where they record over 8 million metrics an hour for netdata content alone.
By archiving Netdata metrics to a backend like TimescaleDB, LAIKA can consolidate metrics data from distributed machines
efficiently. Mahlon can then correlate Netdata metrics with other sources directly in TimescaleDB.
And, because LAIKA will soon be storing years worth of Netdata metrics data in TimescaleDB, they can analyze long-term
metrics as their films move from concept to final cut.
Read the full blog post from LAIKA at the [TimescaleDB
blog](https://blog.timescale.com/blog/writing-it-metrics-from-netdata-to-timescaledb/amp/).
Thank you to Mahlon, Rune, TimescaleDB, and the members of the Netdata community that requested and then built this
backend connection between Netdata and TimescaleDB!

View File

@ -1,258 +0,0 @@
<!--
title: "Netdata, Prometheus, Grafana stack"
custom_edit_url: https://github.com/netdata/netdata/edit/master/backends/WALKTHROUGH.md
-->
# Netdata, Prometheus, Grafana stack
## Intro
In this article I will walk you through the basics of getting Netdata, Prometheus and Grafana all working together and
monitoring your application servers. This article will be using docker on your local workstation. We will be working
with docker in an ad-hoc way, launching containers that run /bin/bash and attaching a TTY to them. I use docker here
in a purely academic fashion and do not condone running Netdata in a container. I pick this method so individuals
without cloud accounts or access to VMs can try this out and for its speed of deployment.
## Why Netdata, Prometheus, and Grafana
Some time ago I was introduced to Netdata by a coworker. We were attempting to troubleshoot python code which seemed to
be bottlenecked. I was instantly impressed by the amount of metrics Netdata exposes to you. I quickly added Netdata to
my set of go-to tools when troubleshooting systems performance.
Some time ago, even later, I was introduced to Prometheus. Prometheus is a monitoring application which flips the normal
architecture around and polls rest endpoints for its metrics. This architectural change greatly simplifies and decreases
the time necessary to begin monitoring your applications. Compared to current monitoring solutions the time spent on
designing the infrastructure is greatly reduced. Running a single Prometheus server per application becomes feasible
with the help of Grafana.
Grafana has been the go to graphing tool for… some time now. Its awesome, anyone that has used it knows its awesome.
We can point Grafana at Prometheus and use Prometheus as a data source. This allows a pretty simple overall monitoring
architecture: Install Netdata on your application servers, point Prometheus at Netdata, and then point Grafana at
Prometheus.
Im omitting an important ingredient in this stack in order to keep this tutorial simple and that is service discovery.
My personal preference is to use Consul. Prometheus can plug into consul and automatically begin to scrape new hosts
that register a Netdata client with Consul.
At the end of this tutorial you will understand how each technology fits together to create a modern monitoring stack.
This stack will offer you visibility into your application and systems performance.
## Getting Started - Netdata
To begin lets create our container which we will install Netdata on. We need to run a container, forward the necessary
port that Netdata listens on, and attach a tty so we can interact with the bash shell on the container. But before we do
this we want name resolution between the two containers to work. In order to accomplish this we will create a
user-defined network and attach both containers to this network. The first command we should run is:
```sh
docker network create --driver bridge netdata-tutorial
```
With this user-defined network created we can now launch our container we will install Netdata on and point it to this
network.
```sh
docker run -it --name netdata --hostname netdata --network=netdata-tutorial -p 19999:19999 centos:latest '/bin/bash'
```
This command creates an interactive tty session (-it), gives the container both a name in relation to the docker daemon
and a hostname (this is so you know what container is which when working in the shells and docker maps hostname
resolution to this container), forwards the local port 19999 to the containers port 19999 (-p 19999:19999), sets the
command to run (/bin/bash) and then chooses the base container images (centos:latest). After running this you should be
sitting inside the shell of the container.
After we have entered the shell we can install Netdata. This process could not be easier. If you take a look at [this
link](/packaging/installer/README.md), the Netdata devs give us several one-liners to install Netdata. I have not had
any issues with these one liners and their bootstrapping scripts so far (If you guys run into anything do share). Run
the following command in your container.
```sh
bash <(curl -Ss https://my-netdata.io/kickstart.sh) --dont-wait
```
After the install completes you should be able to hit the Netdata dashboard at <http://localhost:19999/> (replace
localhost if youre doing this on a VM or have the docker container hosted on a machine not on your local system). If
this is your first time using Netdata I suggest you take a look around. The amount of time Ive spent digging through
/proc and calculating my own metrics has been greatly reduced by this tool. Take it all in.
Next I want to draw your attention to a particular endpoint. Navigate to
<http://localhost:19999/api/v1/allmetrics?format=prometheus&help=yes> In your browser. This is the endpoint which
publishes all the metrics in a format which Prometheus understands. Lets take a look at one of these metrics.
`netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="system"} 0.0831255 1501271696000` This
metric is representing several things which I will go in more details in the section on prometheus. For now understand
that this metric: `netdata_system_cpu_percentage_average` has several labels: (chart, family, dimension). This
corresponds with the first cpu chart you see on the Netdata dashboard.
![](https://github.com/ldelossa/NetdataTutorial/raw/master/Screen%20Shot%202017-07-28%20at%204.00.45%20PM.png)
This CHART is called system.cpu, The FAMILY is cpu, and the DIMENSION we are observing is “system”. You can begin to
draw links between the charts in Netdata to the prometheus metrics format in this manner.
## Prometheus
We will be installing prometheus in a container for purpose of demonstration. While prometheus does have an official
container I would like to walk through the install process and setup on a fresh container. This will allow anyone
reading to migrate this tutorial to a VM or Server of any sort.
Lets start another container in the same fashion as we did the Netdata container.
```sh
docker run -it --name prometheus --hostname prometheus
--network=netdata-tutorial -p 9090:9090 centos:latest '/bin/bash'
```
This should drop you into a shell once again. Once there quickly install your favorite editor as we will be editing
files later in this tutorial.
```sh
yum install vim -y
```
Prometheus provides a tarball of their latest stable versions [here](https://prometheus.io/download/).
Lets download the latest version and install into your container.
```sh
cd /tmp && curl -s https://api.github.com/repos/prometheus/prometheus/releases/latest \
| grep "browser_download_url.*linux-amd64.tar.gz" \
| cut -d '"' -f 4 \
| wget -qi -
mkdir /opt/prometheus
sudo tar -xvf /tmp/prometheus-*linux-amd64.tar.gz -C /opt/prometheus --strip=1
```
This should get prometheus installed into the container. Lets test that we can run prometheus and connect to its web
interface.
```sh
/opt/prometheus/prometheus
```
Now attempt to go to <http://localhost:9090/>. You should be presented with the prometheus homepage. This is a good
point to talk about Prometheuss data model which can be viewed here: <https://prometheus.io/docs/concepts/data_model/>
As explained we have two key elements in Prometheus metrics. We have the metric and its labels. Labels allow for
granularity between metrics. Lets use our previous example to further explain.
```conf
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="system"} 0.0831255 1501271696000
```
Here our metric is netdata_system_cpu_percentage_average and our labels are chart, family, and dimension. The
last two values constitute the actual metric value for the metric type (gauge, counter, etc…). We can begin graphing
system metrics with this information, but first we need to hook up Prometheus to poll Netdata stats.
Lets move our attention to Prometheuss configuration. Prometheus gets it config from the file located (in our example)
at `/opt/prometheus/prometheus.yml`. I wont spend an extensive amount of time going over the configuration values
documented here: <https://prometheus.io/docs/operating/configuration/>. We will be adding a new“job” under the
“scrape_configs”. Lets make the “scrape_configs” section look like this (we can use the dns name Netdata due to the
custom user-defined network we created in docker beforehand).
```yaml
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: 'prometheus'
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ['localhost:9090']
- job_name: 'netdata'
metrics_path: /api/v1/allmetrics
params:
format: [ prometheus ]
static_configs:
- targets: ['netdata:19999']
```
Lets start prometheus once again by running `/opt/prometheus/prometheus`. If we now navigate to prometheus at
<http://localhost:9090/targets> we should see our target being successfully scraped. If we now go back to the
Prometheuss homepage and begin to type netdata\_ Prometheus should auto complete metrics it is now scraping.
![](https://github.com/ldelossa/NetdataTutorial/raw/master/Screen%20Shot%202017-07-28%20at%205.13.43%20PM.png)
Lets now start exploring how we can graph some metrics. Back in our Netdata container lets get the CPU spinning with a
pointless busy loop. On the shell do the following:
```sh
[root@netdata /]# while true; do echo "HOT HOT HOT CPU"; done
```
Our Netdata cpu graph should be showing some activity. Lets represent this in Prometheus. In order to do this lets
keep our metrics page open for reference: <http://localhost:19999/api/v1/allmetrics?format=prometheus&help=yes> We are
setting out to graph the data in the CPU chart so lets search for “system.cpu”in the metrics page above. We come across
a section of metrics with the first comments `# COMMENT homogeneous chart "system.cpu", context "system.cpu", family
"cpu", units "percentage"` Followed by the metrics. This is a good start now let us drill down to the specific metric we
would like to graph.
```conf
# COMMENT
netdata_system_cpu_percentage_average: dimension "system", value is percentage, gauge, dt 1501275951 to 1501275951 inclusive
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="system"} 0.0000000 1501275951000
```
Here we learn that the metric name we care about isnetdata_system_cpu_percentage_average so throw this into Prometheus
and see what we get. We should see something similar to this (I shut off my busy loop)
![](https://github.com/ldelossa/NetdataTutorial/raw/master/Screen%20Shot%202017-07-28%20at%205.47.53%20PM.png)
This is a good step toward what we want. Also make note that Prometheus will tag on an instance label for us which
corresponds to our statically defined job in the configuration file. This allows us to tailor our queries to specific
instances. Now we need to isolate the dimension we want in our query. To do this let us refine the query slightly. Lets
query the dimension also. Place this into our query text box.
`netdata_system_cpu_percentage_average{dimension="system"}` We now wind up with the following graph.
![](https://github.com/ldelossa/NetdataTutorial/raw/master/Screen%20Shot%202017-07-28%20at%205.54.40%20PM.png)
Awesome, this is exactly what we wanted. If you havent caught on yet we can emulate entire charts from Netdata by using
the `chart` dimension. If youd like you can combine the chart and instance dimension to create per-instance charts.
Lets give this a try: `netdata_system_cpu_percentage_average{chart="system.cpu", instance="netdata:19999"}`
This is the basics of using Prometheus to query Netdata. Id advise everyone at this point to read [this
page](/backends/prometheus/README.md#using-netdata-with-prometheus). The key point here is that Netdata can export metrics from
its internal DB or can send metrics “as-collected” by specifying the source=as-collected url parameter like so.
<http://localhost:19999/api/v1/allmetrics?format=prometheus&help=yes&types=yes&source=as-collected> If you choose to use
this method you will need to use Prometheus's set of functions here: <https://prometheus.io/docs/querying/functions/> to
obtain useful metrics as you are now dealing with raw counters from the system. For example you will have to use the
`irate()` function over a counter to get that metric's rate per second. If your graphing needs are met by using the
metrics returned by Netdata's internal database (not specifying any source= url parameter) then use that. If you find
limitations then consider re-writing your queries using the raw data and using Prometheus functions to get the desired
chart.
## Grafana
Finally we make it to grafana. This is the easiest part in my opinion. This time we will actually run the official
grafana docker container as all configuration we need to do is done via the GUI. Lets run the following command:
```sh
docker run -i -p 3000:3000 --network=netdata-tutorial grafana/grafana
```
This will get grafana running at <http://localhost:3000/> Lets go there and
login using the credentials Admin:Admin.
The first thing we want to do is click Add data source. Lets make it look like the following screenshot
![](https://github.com/ldelossa/NetdataTutorial/raw/master/Screen%20Shot%202017-07-28%20at%206.36.55%20PM.png)
With this completed lets graph! Create a new Dashboard by clicking on the top left Grafana Icon and create a new graph
in that dashboard. Fill in the query like we did above and save.
![](https://github.com/ldelossa/NetdataTutorial/raw/master/Screen%20Shot%202017-07-28%20at%206.39.38%20PM.png)
## Conclusion
There you have it, a complete systems monitoring stack which is very easy to deploy. From here I would begin to
understand how Prometheus and a service discovery mechanism such as Consul can play together nicely. My current prod
deployments automatically register Netdata services into Consul and Prometheus automatically begins to scrape them. Once
achieved you do not have to think about the monitoring system until Prometheus cannot keep up with your scale. Once this
happens there are options presented in the Prometheus documentation for solving this. Hope this was helpful, happy
monitoring.

View File

@ -1,12 +0,0 @@
# SPDX-License-Identifier: GPL-3.0-or-later
AUTOMAKE_OPTIONS = subdir-objects
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
dist_noinst_DATA = \
README.md \
$(NULL)
dist_libconfig_DATA = \
aws_kinesis.conf \
$(NULL)

View File

@ -1,53 +0,0 @@
<!--
title: "Using Netdata with AWS Kinesis Data Streams"
custom_edit_url: https://github.com/netdata/netdata/edit/master/backends/aws_kinesis/README.md
-->
# Using Netdata with AWS Kinesis Data Streams
## Prerequisites
To use AWS Kinesis as a backend AWS SDK for C++ should be
[installed](https://docs.aws.amazon.com/en_us/sdk-for-cpp/v1/developer-guide/setup.html) first. `libcrypto`, `libssl`,
and `libcurl` are also required to compile Netdata with Kinesis support enabled. Next, Netdata should be re-installed
from the source. The installer will detect that the required libraries are now available.
If the AWS SDK for C++ is being installed from source, it is useful to set `-DBUILD_ONLY="kinesis"`. Otherwise, the
building process could take a very long time. Take a note, that the default installation path for the libraries is
`/usr/local/lib64`. Many Linux distributions don't include this path as the default one for a library search, so it is
advisable to use the following options to `cmake` while building the AWS SDK:
```sh
cmake -DCMAKE_INSTALL_LIBDIR=/usr/lib -DCMAKE_INSTALL_INCLUDEDIR=/usr/include -DBUILD_SHARED_LIBS=OFF -DBUILD_ONLY=kinesis <aws-sdk-cpp sources>
```
## Configuration
To enable data sending to the kinesis backend set the following options in `netdata.conf`:
```conf
[backend]
enabled = yes
type = kinesis
destination = us-east-1
```
set the `destination` option to an AWS region.
In the Netdata configuration directory run `./edit-config aws_kinesis.conf` and set AWS credentials and stream name:
```yaml
# AWS credentials
aws_access_key_id = your_access_key_id
aws_secret_access_key = your_secret_access_key
# destination stream
stream name = your_stream_name
```
Alternatively, AWS credentials can be set for the `netdata` user using AWS SDK for C++ [standard methods](https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/credentials.html).
A partition key for every record is computed automatically by Netdata with the purpose to distribute records across
available shards evenly.

View File

@ -1,94 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#define BACKENDS_INTERNALS
#include "aws_kinesis.h"
#define CONFIG_FILE_LINE_MAX ((CONFIG_MAX_NAME + CONFIG_MAX_VALUE + 1024) * 2)
// ----------------------------------------------------------------------------
// kinesis backend
// read the aws_kinesis.conf file
int read_kinesis_conf(const char *path, char **access_key_id_p, char **secret_access_key_p, char **stream_name_p)
{
char *access_key_id = *access_key_id_p;
char *secret_access_key = *secret_access_key_p;
char *stream_name = *stream_name_p;
if(unlikely(access_key_id)) freez(access_key_id);
if(unlikely(secret_access_key)) freez(secret_access_key);
if(unlikely(stream_name)) freez(stream_name);
access_key_id = NULL;
secret_access_key = NULL;
stream_name = NULL;
int line = 0;
char filename[FILENAME_MAX + 1];
snprintfz(filename, FILENAME_MAX, "%s/aws_kinesis.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] == 'a' && name[4] == 'a' && !strcmp(name, "aws_access_key_id")) {
access_key_id = strdupz(value);
}
else if(name[0] == 'a' && name[4] == 's' && !strcmp(name, "aws_secret_access_key")) {
secret_access_key = strdupz(value);
}
else if(name[0] == 's' && !strcmp(name, "stream name")) {
stream_name = strdupz(value);
}
}
fclose(fp);
if(unlikely(!stream_name || !*stream_name)) {
error("BACKEND: stream name is a mandatory Kinesis parameter but it is not configured");
return 1;
}
*access_key_id_p = access_key_id;
*secret_access_key_p = secret_access_key;
*stream_name_p = stream_name;
return 0;
}

View File

@ -1,10 +0,0 @@
# AWS Kinesis Data Streams backend configuration
#
# All options in this file are mandatory
# AWS credentials
aws_access_key_id =
aws_secret_access_key =
# destination stream
stream name =

View File

@ -1,14 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_BACKEND_KINESIS_H
#define NETDATA_BACKEND_KINESIS_H
#include "backends/backends.h"
#include "aws_kinesis_put_record.h"
#define KINESIS_PARTITION_KEY_MAX 256
#define KINESIS_RECORD_MAX 1024 * 1024
extern int read_kinesis_conf(const char *path, char **auth_key_id_p, char **secure_key_p, char **stream_name_p);
#endif //NETDATA_BACKEND_KINESIS_H

View File

@ -1,87 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include <aws/core/Aws.h>
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/auth/AWSCredentials.h>
#include <aws/core/utils/Outcome.h>
#include <aws/kinesis/KinesisClient.h>
#include <aws/kinesis/model/PutRecordRequest.h>
#include "aws_kinesis_put_record.h"
using namespace Aws;
static SDKOptions options;
static Kinesis::KinesisClient *client;
struct request_outcome {
Kinesis::Model::PutRecordOutcomeCallable future_outcome;
size_t data_len;
};
static Vector<request_outcome> request_outcomes;
void backends_kinesis_init(const char *region, const char *access_key_id, const char *secret_key, const long timeout) {
InitAPI(options);
Client::ClientConfiguration config;
config.region = region;
config.requestTimeoutMs = timeout;
config.connectTimeoutMs = timeout;
if(access_key_id && *access_key_id && secret_key && *secret_key) {
client = New<Kinesis::KinesisClient>("client", Auth::AWSCredentials(access_key_id, secret_key), config);
} else {
client = New<Kinesis::KinesisClient>("client", config);
}
}
void backends_kinesis_shutdown() {
Delete(client);
ShutdownAPI(options);
}
int backends_kinesis_put_record(const char *stream_name, const char *partition_key,
const char *data, size_t data_len) {
Kinesis::Model::PutRecordRequest request;
request.SetStreamName(stream_name);
request.SetPartitionKey(partition_key);
request.SetData(Utils::ByteBuffer((unsigned char*) data, data_len));
request_outcomes.push_back({client->PutRecordCallable(request), data_len});
return 0;
}
int backends_kinesis_get_result(char *error_message, size_t *sent_bytes, size_t *lost_bytes) {
Kinesis::Model::PutRecordOutcome outcome;
*sent_bytes = 0;
*lost_bytes = 0;
for(auto request_outcome = request_outcomes.begin(); request_outcome != request_outcomes.end(); ) {
std::future_status status = request_outcome->future_outcome.wait_for(std::chrono::microseconds(100));
if(status == std::future_status::ready || status == std::future_status::deferred) {
outcome = request_outcome->future_outcome.get();
*sent_bytes += request_outcome->data_len;
if(!outcome.IsSuccess()) {
*lost_bytes += request_outcome->data_len;
outcome.GetError().GetMessage().copy(error_message, ERROR_LINE_MAX);
}
request_outcomes.erase(request_outcome);
} else {
++request_outcome;
}
}
if(*lost_bytes) {
return 1;
}
return 0;
}

View File

@ -1,25 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_BACKEND_KINESIS_PUT_RECORD_H
#define NETDATA_BACKEND_KINESIS_PUT_RECORD_H
#define ERROR_LINE_MAX 1023
#ifdef __cplusplus
extern "C" {
#endif
void backends_kinesis_init(const char *region, const char *access_key_id, const char *secret_key, const long timeout);
void backends_kinesis_shutdown();
int backends_kinesis_put_record(const char *stream_name, const char *partition_key,
const char *data, size_t data_len);
int backends_kinesis_get_result(char *error_message, size_t *sent_bytes, size_t *lost_bytes);
#ifdef __cplusplus
}
#endif
#endif //NETDATA_BACKEND_KINESIS_PUT_RECORD_H

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_BACKENDS_H
#define NETDATA_BACKENDS_H 1
#include "daemon/common.h"
typedef enum backend_options {
BACKEND_OPTION_NONE = 0,
BACKEND_SOURCE_DATA_AS_COLLECTED = (1 << 0),
BACKEND_SOURCE_DATA_AVERAGE = (1 << 1),
BACKEND_SOURCE_DATA_SUM = (1 << 2),
BACKEND_OPTION_SEND_NAMES = (1 << 16)
} BACKEND_OPTIONS;
typedef enum backend_types {
BACKEND_TYPE_UNKNOWN, // Invalid type
BACKEND_TYPE_GRAPHITE, // Send plain text to Graphite
BACKEND_TYPE_OPENTSDB_USING_TELNET, // Send data to OpenTSDB using telnet API
BACKEND_TYPE_OPENTSDB_USING_HTTP, // Send data to OpenTSDB using HTTP API
BACKEND_TYPE_JSON, // Stores the data using JSON.
BACKEND_TYPE_PROMETHEUS_REMOTE_WRITE, // The user selected to use Prometheus backend
BACKEND_TYPE_KINESIS, // Send message to AWS Kinesis
BACKEND_TYPE_MONGODB, // Send data to MongoDB collection
BACKEND_TYPE_NUM // Number of backend types
} BACKEND_TYPE;
typedef int (**backend_response_checker_t)(BUFFER *);
typedef int (**backend_request_formatter_t)(BUFFER *, const char *, RRDHOST *, const char *, RRDSET *, RRDDIM *, time_t, time_t, BACKEND_OPTIONS);
#define BACKEND_OPTIONS_SOURCE_BITS (BACKEND_SOURCE_DATA_AS_COLLECTED|BACKEND_SOURCE_DATA_AVERAGE|BACKEND_SOURCE_DATA_SUM)
#define BACKEND_OPTIONS_DATA_SOURCE(backend_options) (backend_options & BACKEND_OPTIONS_SOURCE_BITS)
extern int global_backend_update_every;
extern BACKEND_OPTIONS global_backend_options;
extern const char *global_backend_source;
extern const char *global_backend_prefix;
extern const char *global_backend_send_charts_matching;
extern void *backends_main(void *ptr);
BACKEND_TYPE backend_select_type(const char *type);
extern BACKEND_OPTIONS backend_parse_data_source(const char *source, BACKEND_OPTIONS backend_options);
#ifdef BACKENDS_INTERNALS
extern int backends_can_send_rrdset(BACKEND_OPTIONS backend_options, RRDSET *st);
extern calculated_number backend_calculate_value_from_stored_data(
RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
, time_t *first_timestamp // the timestamp of the first point used in this response
, time_t *last_timestamp // the timestamp that should be reported to backend
);
extern size_t backend_name_copy(char *d, const char *s, size_t usable);
extern int discard_response(BUFFER *b, const char *backend);
static inline char *strip_quotes(char *str) {
if(*str == '"' || *str == '\'') {
char *s;
str++;
s = str;
while(*s) s++;
if(s != str) s--;
if(*s == '"' || *s == '\'') *s = '\0';
}
return str;
}
#endif // BACKENDS_INTERNALS
#include "backends/prometheus/backend_prometheus.h"
#include "backends/graphite/graphite.h"
#include "backends/json/json.h"
#include "backends/opentsdb/opentsdb.h"
#if HAVE_KINESIS
#include "backends/aws_kinesis/aws_kinesis.h"
#endif
#if ENABLE_PROMETHEUS_REMOTE_WRITE
#include "backends/prometheus/remote_write/remote_write.h"
#endif
#if HAVE_MONGOC
#include "backends/mongodb/mongodb.h"
#endif
#endif /* NETDATA_BACKENDS_H */

View File

@ -1,4 +0,0 @@
# SPDX-License-Identifier: GPL-3.0-or-later
AUTOMAKE_OPTIONS = subdir-objects
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

View File

@ -1,90 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#define BACKENDS_INTERNALS
#include "graphite.h"
// ----------------------------------------------------------------------------
// graphite backend
int backends_format_dimension_collected_graphite_plaintext(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
) {
(void)host;
(void)after;
(void)before;
char chart_name[RRD_ID_LENGTH_MAX + 1];
char dimension_name[RRD_ID_LENGTH_MAX + 1];
backend_name_copy(chart_name, (backend_options & BACKEND_OPTION_SEND_NAMES && st->name)?st->name:st->id, RRD_ID_LENGTH_MAX);
backend_name_copy(dimension_name, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name)?rd->name:rd->id, RRD_ID_LENGTH_MAX);
buffer_sprintf(
b
, "%s.%s.%s.%s%s%s " COLLECTED_NUMBER_FORMAT " %llu\n"
, prefix
, hostname
, chart_name
, dimension_name
, (host->tags)?";":""
, (host->tags)?host->tags:""
, rd->last_collected_value
, (unsigned long long)rd->last_collected_time.tv_sec
);
return 1;
}
int backends_format_dimension_stored_graphite_plaintext(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
) {
(void)host;
char chart_name[RRD_ID_LENGTH_MAX + 1];
char dimension_name[RRD_ID_LENGTH_MAX + 1];
backend_name_copy(chart_name, (backend_options & BACKEND_OPTION_SEND_NAMES && st->name)?st->name:st->id, RRD_ID_LENGTH_MAX);
backend_name_copy(dimension_name, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name)?rd->name:rd->id, RRD_ID_LENGTH_MAX);
time_t first_t = after, last_t = before;
calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, backend_options, &first_t, &last_t);
if(!isnan(value)) {
buffer_sprintf(
b
, "%s.%s.%s.%s%s%s " CALCULATED_NUMBER_FORMAT " %llu\n"
, prefix
, hostname
, chart_name
, dimension_name
, (host->tags)?";":""
, (host->tags)?host->tags:""
, value
, (unsigned long long) last_t
);
return 1;
}
return 0;
}
int process_graphite_response(BUFFER *b) {
return discard_response(b, "graphite");
}

View File

@ -1,35 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_BACKEND_GRAPHITE_H
#define NETDATA_BACKEND_GRAPHITE_H
#include "backends/backends.h"
extern int backends_format_dimension_collected_graphite_plaintext(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
);
extern int backends_format_dimension_stored_graphite_plaintext(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
);
extern int process_graphite_response(BUFFER *b);
#endif //NETDATA_BACKEND_GRAPHITE_H

View File

@ -1,4 +0,0 @@
# SPDX-License-Identifier: GPL-3.0-or-later
AUTOMAKE_OPTIONS = subdir-objects
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

View File

@ -1,152 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#define BACKENDS_INTERNALS
#include "json.h"
// ----------------------------------------------------------------------------
// json backend
int backends_format_dimension_collected_json_plaintext(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
) {
(void)host;
(void)after;
(void)before;
(void)backend_options;
const char *tags_pre = "", *tags_post = "", *tags = host->tags;
if(!tags) tags = "";
if(*tags) {
if(*tags == '{' || *tags == '[' || *tags == '"') {
tags_pre = "\"host_tags\":";
tags_post = ",";
}
else {
tags_pre = "\"host_tags\":\"";
tags_post = "\",";
}
}
buffer_sprintf(b, "{"
"\"prefix\":\"%s\","
"\"hostname\":\"%s\","
"%s%s%s"
"\"chart_id\":\"%s\","
"\"chart_name\":\"%s\","
"\"chart_family\":\"%s\","
"\"chart_context\": \"%s\","
"\"chart_type\":\"%s\","
"\"units\": \"%s\","
"\"id\":\"%s\","
"\"name\":\"%s\","
"\"value\":" COLLECTED_NUMBER_FORMAT ","
"\"timestamp\": %llu}\n",
prefix,
hostname,
tags_pre, tags, tags_post,
st->id,
st->name,
st->family,
st->context,
st->type,
st->units,
rd->id,
rd->name,
rd->last_collected_value,
(unsigned long long) rd->last_collected_time.tv_sec
);
return 1;
}
int backends_format_dimension_stored_json_plaintext(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
) {
(void)host;
time_t first_t = after, last_t = before;
calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, backend_options, &first_t, &last_t);
if(!isnan(value)) {
const char *tags_pre = "", *tags_post = "", *tags = host->tags;
if(!tags) tags = "";
if(*tags) {
if(*tags == '{' || *tags == '[' || *tags == '"') {
tags_pre = "\"host_tags\":";
tags_post = ",";
}
else {
tags_pre = "\"host_tags\":\"";
tags_post = "\",";
}
}
buffer_sprintf(b, "{"
"\"prefix\":\"%s\","
"\"hostname\":\"%s\","
"%s%s%s"
"\"chart_id\":\"%s\","
"\"chart_name\":\"%s\","
"\"chart_family\":\"%s\","
"\"chart_context\": \"%s\","
"\"chart_type\":\"%s\","
"\"units\": \"%s\","
"\"id\":\"%s\","
"\"name\":\"%s\","
"\"value\":" CALCULATED_NUMBER_FORMAT ","
"\"timestamp\": %llu}\n",
prefix,
hostname,
tags_pre, tags, tags_post,
st->id,
st->name,
st->family,
st->context,
st->type,
st->units,
rd->id,
rd->name,
value,
(unsigned long long) last_t
);
return 1;
}
return 0;
}
int process_json_response(BUFFER *b) {
return discard_response(b, "json");
}

View File

@ -1,34 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_BACKEND_JSON_H
#define NETDATA_BACKEND_JSON_H
#include "backends/backends.h"
extern int backends_format_dimension_collected_json_plaintext(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
);
extern int backends_format_dimension_stored_json_plaintext(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
);
extern int process_json_response(BUFFER *b);
#endif //NETDATA_BACKEND_JSON_H

View File

@ -1,8 +0,0 @@
# SPDX-License-Identifier: GPL-3.0-or-later
AUTOMAKE_OPTIONS = subdir-objects
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
dist_noinst_DATA = \
README.md \
$(NULL)

View File

@ -1,41 +0,0 @@
<!--
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.

View File

@ -1,189 +0,0 @@
// 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;
}

View File

@ -1,12 +0,0 @@
# MongoDB backend configuration
#
# All options in this file are mandatory
# URI
uri =
# database name
database =
# collection name
collection =

View File

@ -1,16 +0,0 @@
// 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

View File

@ -1,158 +0,0 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-3.0-or-later
# This is a simple backend database proxy, written in BASH, using the nc command.
# Run the script without any parameters for help.
MODE="${1}"
MY_PORT="${2}"
BACKEND_HOST="${3}"
BACKEND_PORT="${4}"
FILE="${NETDATA_NC_BACKEND_DIR-/tmp}/netdata-nc-backend-${MY_PORT}"
log() {
logger --stderr --id=$$ --tag "netdata-nc-backend" "${*}"
}
mync() {
local ret
log "Running: nc ${*}"
nc "${@}"
ret=$?
log "nc stopped with return code ${ret}."
return ${ret}
}
listen_save_replay_forever() {
local file="${1}" port="${2}" real_backend_host="${3}" real_backend_port="${4}" ret delay=1 started ended
while true
do
log "Starting nc to listen on port ${port} and save metrics to ${file}"
started=$(date +%s)
mync -l -p "${port}" | tee -a -p --output-error=exit "${file}"
ended=$(date +%s)
if [ -s "${file}" ]
then
if [ ! -z "${real_backend_host}" ] && [ ! -z "${real_backend_port}" ]
then
log "Attempting to send the metrics to the real backend at ${real_backend_host}:${real_backend_port}"
mync "${real_backend_host}" "${real_backend_port}" <"${file}"
ret=$?
if [ ${ret} -eq 0 ]
then
log "Successfully sent the metrics to ${real_backend_host}:${real_backend_port}"
mv "${file}" "${file}.old"
touch "${file}"
else
log "Failed to send the metrics to ${real_backend_host}:${real_backend_port} (nc returned ${ret}) - appending more data to ${file}"
fi
else
log "No backend configured - appending more data to ${file}"
fi
fi
# prevent a CPU hungry infinite loop
# if nc cannot listen to port
if [ $((ended - started)) -lt 5 ]
then
log "nc has been stopped too fast."
delay=30
else
delay=1
fi
log "Waiting ${delay} seconds before listening again for data."
sleep ${delay}
done
}
if [ "${MODE}" = "start" ]
then
# start the listener, in exclusive mode
# only one can use the same file/port at a time
{
flock -n 9
# shellcheck disable=SC2181
if [ $? -ne 0 ]
then
log "Cannot get exclusive lock on file ${FILE}.lock - Am I running multiple times?"
exit 2
fi
# save our PID to the lock file
echo "$$" >"${FILE}.lock"
listen_save_replay_forever "${FILE}" "${MY_PORT}" "${BACKEND_HOST}" "${BACKEND_PORT}"
ret=$?
log "listener exited."
exit ${ret}
} 9>>"${FILE}.lock"
# we can only get here if ${FILE}.lock cannot be created
log "Cannot create file ${FILE}."
exit 3
elif [ "${MODE}" = "stop" ]
then
{
flock -n 9
# shellcheck disable=SC2181
if [ $? -ne 0 ]
then
pid=$(<"${FILE}".lock)
log "Killing process ${pid}..."
kill -TERM "-${pid}"
exit 0
fi
log "File ${FILE}.lock has been locked by me but it shouldn't. Is a collector running?"
exit 4
} 9<"${FILE}.lock"
log "File ${FILE}.lock does not exist. Is a collector running?"
exit 5
else
cat <<EOF
Usage:
"${0}" start|stop PORT [BACKEND_HOST BACKEND_PORT]
PORT The port this script will listen
(configure netdata to use this as a second backend)
BACKEND_HOST The real backend host
BACKEND_PORT The real backend port
This script can act as fallback backend for netdata.
It will receive metrics from netdata, save them to
${FILE}
and once netdata reconnects to the real-backend, this script
will push all metrics collected to the real-backend too and
wait for a failure to happen again.
Only one netdata can connect to this script at a time.
If you need fallback for multiple netdata, run this script
multiple times with different ports.
You can run me in the background with this:
screen -d -m "${0}" start PORT [BACKEND_HOST BACKEND_PORT]
EOF
exit 1
fi

View File

@ -1,4 +0,0 @@
# SPDX-License-Identifier: GPL-3.0-or-later
AUTOMAKE_OPTIONS = subdir-objects
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

View File

@ -1,37 +0,0 @@
<!--
title: "OpenTSDB with HTTP"
custom_edit_url: https://github.com/netdata/netdata/edit/master/backends/opentsdb/README.md
-->
# OpenTSDB with HTTP
Netdata can easily communicate with OpenTSDB using HTTP API. To enable this channel, set the following options in your
`netdata.conf`:
```conf
[backend]
type = opentsdb:http
destination = localhost:4242
```
In this example, OpenTSDB is running with its default port, which is `4242`. If you run OpenTSDB on a different port,
change the `destination = localhost:4242` line accordingly.
## HTTPS
As of [v1.16.0](https://github.com/netdata/netdata/releases/tag/v1.16.0), Netdata can send metrics to OpenTSDB using
TLS/SSL. Unfortunately, OpenTDSB does not support encrypted connections, so you will have to configure a reverse proxy
to enable HTTPS communication between Netdata and OpenTSDB. You can set up a reverse proxy with
[Nginx](/docs/Running-behind-nginx.md).
After your proxy is configured, make the following changes to `netdata.conf`:
```conf
[backend]
type = opentsdb:https
destination = localhost:8082
```
In this example, we used the port `8082` for our reverse proxy. If your reverse proxy listens on a different port,
change the `destination = localhost:8082` line accordingly.

View File

@ -1,205 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#define BACKENDS_INTERNALS
#include "opentsdb.h"
// ----------------------------------------------------------------------------
// opentsdb backend
int backends_format_dimension_collected_opentsdb_telnet(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
) {
(void)host;
(void)after;
(void)before;
char chart_name[RRD_ID_LENGTH_MAX + 1];
char dimension_name[RRD_ID_LENGTH_MAX + 1];
backend_name_copy(chart_name, (backend_options & BACKEND_OPTION_SEND_NAMES && st->name)?st->name:st->id, RRD_ID_LENGTH_MAX);
backend_name_copy(dimension_name, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name)?rd->name:rd->id, RRD_ID_LENGTH_MAX);
buffer_sprintf(
b
, "put %s.%s.%s %llu " COLLECTED_NUMBER_FORMAT " host=%s%s%s\n"
, prefix
, chart_name
, dimension_name
, (unsigned long long)rd->last_collected_time.tv_sec
, rd->last_collected_value
, hostname
, (host->tags)?" ":""
, (host->tags)?host->tags:""
);
return 1;
}
int backends_format_dimension_stored_opentsdb_telnet(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
) {
(void)host;
time_t first_t = after, last_t = before;
calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, backend_options, &first_t, &last_t);
char chart_name[RRD_ID_LENGTH_MAX + 1];
char dimension_name[RRD_ID_LENGTH_MAX + 1];
backend_name_copy(chart_name, (backend_options & BACKEND_OPTION_SEND_NAMES && st->name)?st->name:st->id, RRD_ID_LENGTH_MAX);
backend_name_copy(dimension_name, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name)?rd->name:rd->id, RRD_ID_LENGTH_MAX);
if(!isnan(value)) {
buffer_sprintf(
b
, "put %s.%s.%s %llu " CALCULATED_NUMBER_FORMAT " host=%s%s%s\n"
, prefix
, chart_name
, dimension_name
, (unsigned long long) last_t
, value
, hostname
, (host->tags)?" ":""
, (host->tags)?host->tags:""
);
return 1;
}
return 0;
}
int process_opentsdb_response(BUFFER *b) {
return discard_response(b, "opentsdb");
}
static inline void opentsdb_build_message(BUFFER *b, char *message, const char *hostname, int length) {
buffer_sprintf(
b
, "POST /api/put HTTP/1.1\r\n"
"Host: %s\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s"
, hostname
, length
, message
);
}
int backends_format_dimension_collected_opentsdb_http(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
) {
(void)host;
(void)after;
(void)before;
char message[1024];
char chart_name[RRD_ID_LENGTH_MAX + 1];
char dimension_name[RRD_ID_LENGTH_MAX + 1];
backend_name_copy(chart_name, (backend_options & BACKEND_OPTION_SEND_NAMES && st->name)?st->name:st->id, RRD_ID_LENGTH_MAX);
backend_name_copy(dimension_name, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name)?rd->name:rd->id, RRD_ID_LENGTH_MAX);
int length = snprintfz(message
, sizeof(message)
, "{"
" \"metric\": \"%s.%s.%s\","
" \"timestamp\": %llu,"
" \"value\": "COLLECTED_NUMBER_FORMAT ","
" \"tags\": {"
" \"host\": \"%s%s%s\""
" }"
"}"
, prefix
, chart_name
, dimension_name
, (unsigned long long)rd->last_collected_time.tv_sec
, rd->last_collected_value
, hostname
, (host->tags)?" ":""
, (host->tags)?host->tags:""
);
if(length > 0) {
opentsdb_build_message(b, message, hostname, length);
}
return 1;
}
int backends_format_dimension_stored_opentsdb_http(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
) {
(void)host;
time_t first_t = after, last_t = before;
calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, backend_options, &first_t, &last_t);
if(!isnan(value)) {
char chart_name[RRD_ID_LENGTH_MAX + 1];
char dimension_name[RRD_ID_LENGTH_MAX + 1];
backend_name_copy(chart_name, (backend_options & BACKEND_OPTION_SEND_NAMES && st->name)?st->name:st->id, RRD_ID_LENGTH_MAX);
backend_name_copy(dimension_name, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name)?rd->name:rd->id, RRD_ID_LENGTH_MAX);
char message[1024];
int length = snprintfz(message
, sizeof(message)
, "{"
" \"metric\": \"%s.%s.%s\","
" \"timestamp\": %llu,"
" \"value\": "CALCULATED_NUMBER_FORMAT ","
" \"tags\": {"
" \"host\": \"%s%s%s\""
" }"
"}"
, prefix
, chart_name
, dimension_name
, (unsigned long long)last_t
, value
, hostname
, (host->tags)?" ":""
, (host->tags)?host->tags:""
);
if(length > 0) {
opentsdb_build_message(b, message, hostname, length);
}
return 1;
}
return 0;
}

View File

@ -1,58 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_BACKEND_OPENTSDB_H
#define NETDATA_BACKEND_OPENTSDB_H
#include "backends/backends.h"
extern int backends_format_dimension_collected_opentsdb_telnet(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
);
extern int backends_format_dimension_stored_opentsdb_telnet(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
);
extern int process_opentsdb_response(BUFFER *b);
int backends_format_dimension_collected_opentsdb_http(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
);
int backends_format_dimension_stored_opentsdb_http(
BUFFER *b // the buffer to write data to
, const char *prefix // the prefix to use
, RRDHOST *host // the host this chart comes from
, const char *hostname // the hostname (to override host->hostname)
, RRDSET *st // the chart
, RRDDIM *rd // the dimension
, time_t after // the start timestamp
, time_t before // the end timestamp
, BACKEND_OPTIONS backend_options // BACKEND_SOURCE_* bitmap
);
#endif //NETDATA_BACKEND_OPENTSDB_H

View File

@ -1,12 +0,0 @@
# SPDX-License-Identifier: GPL-3.0-or-later
AUTOMAKE_OPTIONS = subdir-objects
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
SUBDIRS = \
remote_write \
$(NULL)
dist_noinst_DATA = \
README.md \
$(NULL)

View File

@ -1,457 +0,0 @@
<!--
title: "Using Netdata with Prometheus"
custom_edit_url: https://github.com/netdata/netdata/edit/master/backends/prometheus/README.md
-->
# Using Netdata with Prometheus
> IMPORTANT: the format Netdata sends metrics to prometheus has changed since Netdata v1.7. The new prometheus backend
> for Netdata supports a lot more features and is aligned to the development of the rest of the Netdata backends.
Prometheus is a distributed monitoring system which offers a very simple setup along with a robust data model. Recently
Netdata added support for Prometheus. I'm going to quickly show you how to install both Netdata and prometheus on the
same server. We can then use grafana pointed at Prometheus to obtain long term metrics Netdata offers. I'm assuming we
are starting at a fresh ubuntu shell (whether you'd like to follow along in a VM or a cloud instance is up to you).
## Installing Netdata and prometheus
### Installing Netdata
There are number of ways to install Netdata according to [Installation](/packaging/installer/README.md). The suggested way
of installing the latest Netdata and keep it upgrade automatically. Using one line installation:
```sh
bash <(curl -Ss https://my-netdata.io/kickstart.sh)
```
At this point we should have Netdata listening on port 19999. Attempt to take your browser here:
```sh
http://your.netdata.ip:19999
```
_(replace `your.netdata.ip` with the IP or hostname of the server running Netdata)_
### Installing Prometheus
In order to install prometheus we are going to introduce our own systemd startup script along with an example of
prometheus.yaml configuration. Prometheus needs to be pointed to your server at a specific target url for it to scrape
Netdata's api. Prometheus is always a pull model meaning Netdata is the passive client within this architecture.
Prometheus always initiates the connection with Netdata.
#### Download Prometheus
```sh
cd /tmp && curl -s https://api.github.com/repos/prometheus/prometheus/releases/latest \
| grep "browser_download_url.*linux-amd64.tar.gz" \
| cut -d '"' -f 4 \
| wget -qi -
```
#### Create prometheus system user
```sh
sudo useradd -r prometheus
```
#### Create prometheus directory
```sh
sudo mkdir /opt/prometheus
sudo chown prometheus:prometheus /opt/prometheus
```
#### Untar prometheus directory
```sh
sudo tar -xvf /tmp/prometheus-*linux-amd64.tar.gz -C /opt/prometheus --strip=1
```
#### Install prometheus.yml
We will use the following `prometheus.yml` file. Save it at `/opt/prometheus/prometheus.yml`.
Make sure to replace `your.netdata.ip` with the IP or hostname of the host running Netdata.
```yaml
# my global config
global:
scrape_interval: 5s # Set the scrape interval to every 5 seconds. Default is every 1 minute.
evaluation_interval: 5s # Evaluate rules every 5 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Attach these labels to any time series or alerts when communicating with
# external systems (federation, remote storage, Alertmanager).
external_labels:
monitor: 'codelab-monitor'
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first.rules"
# - "second.rules"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: 'prometheus'
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ['0.0.0.0:9090']
- job_name: 'netdata-scrape'
metrics_path: '/api/v1/allmetrics'
params:
# format: prometheus | prometheus_all_hosts
# You can use `prometheus_all_hosts` if you want Prometheus to set the `instance` to your hostname instead of IP
format: [prometheus]
#
# source: as-collected | raw | average | sum | volume
# default is: average
#source: [as-collected]
#
# server name for this prometheus - the default is the client IP
# for Netdata to uniquely identify it
#server: ['prometheus1']
honor_labels: true
static_configs:
- targets: ['{your.netdata.ip}:19999']
```
#### Install nodes.yml
The following is completely optional, it will enable Prometheus to generate alerts from some Netdata sources. Tweak the
values to your own needs. We will use the following `nodes.yml` file below. Save it at `/opt/prometheus/nodes.yml`, and
add a _- "nodes.yml"_ entry under the _rule_files:_ section in the example prometheus.yml file above.
```yaml
groups:
- name: nodes
rules:
- alert: node_high_cpu_usage_70
expr: sum(sum_over_time(netdata_system_cpu_percentage_average{dimension=~"(user|system|softirq|irq|guest)"}[10m])) by (job) / sum(count_over_time(netdata_system_cpu_percentage_average{dimension="idle"}[10m])) by (job) > 70
for: 1m
annotations:
description: '{{ $labels.job }} on ''{{ $labels.job }}'' CPU usage is at {{ humanize $value }}%.'
summary: CPU alert for container node '{{ $labels.job }}'
- alert: node_high_memory_usage_70
expr: 100 / sum(netdata_system_ram_MB_average) by (job)
* sum(netdata_system_ram_MB_average{dimension=~"free|cached"}) by (job) < 30
for: 1m
annotations:
description: '{{ $labels.job }} memory usage is {{ humanize $value}}%.'
summary: Memory alert for container node '{{ $labels.job }}'
- alert: node_low_root_filesystem_space_20
expr: 100 / sum(netdata_disk_space_GB_average{family="/"}) by (job)
* sum(netdata_disk_space_GB_average{family="/",dimension=~"avail|cached"}) by (job) < 20
for: 1m
annotations:
description: '{{ $labels.job }} root filesystem space is {{ humanize $value}}%.'
summary: Root filesystem alert for container node '{{ $labels.job }}'
- alert: node_root_filesystem_fill_rate_6h
expr: predict_linear(netdata_disk_space_GB_average{family="/",dimension=~"avail|cached"}[1h], 6 * 3600) < 0
for: 1h
labels:
severity: critical
annotations:
description: Container node {{ $labels.job }} root filesystem is going to fill up in 6h.
summary: Disk fill alert for Swarm node '{{ $labels.job }}'
```
#### Install prometheus.service
Save this service file as `/etc/systemd/system/prometheus.service`:
```sh
[Unit]
Description=Prometheus Server
AssertPathExists=/opt/prometheus
[Service]
Type=simple
WorkingDirectory=/opt/prometheus
User=prometheus
Group=prometheus
ExecStart=/opt/prometheus/prometheus --config.file=/opt/prometheus/prometheus.yml --log.level=info
ExecReload=/bin/kill -SIGHUP $MAINPID
ExecStop=/bin/kill -SIGINT $MAINPID
[Install]
WantedBy=multi-user.target
```
##### Start Prometheus
```sh
sudo systemctl start prometheus
sudo systemctl enable prometheus
```
Prometheus should now start and listen on port 9090. Attempt to head there with your browser.
If everything is working correctly when you fetch `http://your.prometheus.ip:9090` you will see a 'Status' tab. Click
this and click on 'targets' We should see the Netdata host as a scraped target.
---
## Netdata support for prometheus
> IMPORTANT: the format Netdata sends metrics to prometheus has changed since Netdata v1.6. The new format allows easier
> queries for metrics and supports both `as collected` and normalized metrics.
Before explaining the changes, we have to understand the key differences between Netdata and prometheus.
### understanding Netdata metrics
#### charts
Each chart in Netdata has several properties (common to all its metrics):
- `chart_id` - uniquely identifies a chart.
- `chart_name` - a more human friendly name for `chart_id`, also unique.
- `context` - this is the template of the chart. All disk I/O charts have the same context, all mysql requests charts
have the same context, etc. This is used for alarm templates to match all the charts they should be attached to.
- `family` groups a set of charts together. It is used as the submenu of the dashboard.
- `units` is the units for all the metrics attached to the chart.
#### dimensions
Then each Netdata chart contains metrics called `dimensions`. All the dimensions of a chart have the same units of
measurement, and are contextually in the same category (ie. the metrics for disk bandwidth are `read` and `write` and
they are both in the same chart).
### Netdata data source
Netdata can send metrics to prometheus from 3 data sources:
- `as collected` or `raw` - this data source sends the metrics to prometheus as they are collected. No conversion is
done by Netdata. The latest value for each metric is just given to prometheus. This is the most preferred method by
prometheus, but it is also the harder to work with. To work with this data source, you will need to understand how
to get meaningful values out of them.
The format of the metrics is: `CONTEXT{chart="CHART",family="FAMILY",dimension="DIMENSION"}`.
If the metric is a counter (`incremental` in Netdata lingo), `_total` is appended the context.
Unlike prometheus, Netdata allows each dimension of a chart to have a different algorithm and conversion constants
(`multiplier` and `divisor`). In this case, that the dimensions of a charts are heterogeneous, Netdata will use this
format: `CONTEXT_DIMENSION{chart="CHART",family="FAMILY"}`
- `average` - this data source uses the Netdata database to send the metrics to prometheus as they are presented on
the Netdata dashboard. So, all the metrics are sent as gauges, at the units they are presented in the Netdata
dashboard charts. This is the easiest to work with.
The format of the metrics is: `CONTEXT_UNITS_average{chart="CHART",family="FAMILY",dimension="DIMENSION"}`.
When this source is used, Netdata keeps track of the last access time for each prometheus server fetching the
metrics. This last access time is used at the subsequent queries of the same prometheus server to identify the
time-frame the `average` will be calculated.
So, no matter how frequently prometheus scrapes Netdata, it will get all the database data.
To identify each prometheus server, Netdata uses by default the IP of the client fetching the metrics.
If there are multiple prometheus servers fetching data from the same Netdata, using the same IP, each prometheus
server can append `server=NAME` to the URL. Netdata will use this `NAME` to uniquely identify the prometheus server.
- `sum` or `volume`, is like `average` but instead of averaging the values, it sums them.
The format of the metrics is: `CONTEXT_UNITS_sum{chart="CHART",family="FAMILY",dimension="DIMENSION"}`. All the
other operations are the same with `average`.
To change the data source to `sum` or `as-collected` you need to provide the `source` parameter in the request URL.
e.g.: `http://your.netdata.ip:19999/api/v1/allmetrics?format=prometheus&help=yes&source=as-collected`
Keep in mind that early versions of Netdata were sending the metrics as: `CHART_DIMENSION{}`.
### Querying Metrics
Fetch with your web browser this URL:
`http://your.netdata.ip:19999/api/v1/allmetrics?format=prometheus&help=yes`
_(replace `your.netdata.ip` with the ip or hostname of your Netdata server)_
Netdata will respond with all the metrics it sends to prometheus.
If you search that page for `"system.cpu"` you will find all the metrics Netdata is exporting to prometheus for this
chart. `system.cpu` is the chart name on the Netdata dashboard (on the Netdata dashboard all charts have a text heading
such as : `Total CPU utilization (system.cpu)`. What we are interested here in the chart name: `system.cpu`).
Searching for `"system.cpu"` reveals:
```sh
# COMMENT homogeneous chart "system.cpu", context "system.cpu", family "cpu", units "percentage"
# COMMENT netdata_system_cpu_percentage_average: dimension "guest_nice", value is percentage, gauge, dt 1500066653 to 1500066662 inclusive
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="guest_nice"} 0.0000000 1500066662000
# COMMENT netdata_system_cpu_percentage_average: dimension "guest", value is percentage, gauge, dt 1500066653 to 1500066662 inclusive
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="guest"} 1.7837326 1500066662000
# COMMENT netdata_system_cpu_percentage_average: dimension "steal", value is percentage, gauge, dt 1500066653 to 1500066662 inclusive
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="steal"} 0.0000000 1500066662000
# COMMENT netdata_system_cpu_percentage_average: dimension "softirq", value is percentage, gauge, dt 1500066653 to 1500066662 inclusive
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="softirq"} 0.5275442 1500066662000
# COMMENT netdata_system_cpu_percentage_average: dimension "irq", value is percentage, gauge, dt 1500066653 to 1500066662 inclusive
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="irq"} 0.2260836 1500066662000
# COMMENT netdata_system_cpu_percentage_average: dimension "user", value is percentage, gauge, dt 1500066653 to 1500066662 inclusive
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="user"} 2.3362762 1500066662000
# COMMENT netdata_system_cpu_percentage_average: dimension "system", value is percentage, gauge, dt 1500066653 to 1500066662 inclusive
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="system"} 1.7961062 1500066662000
# COMMENT netdata_system_cpu_percentage_average: dimension "nice", value is percentage, gauge, dt 1500066653 to 1500066662 inclusive
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="nice"} 0.0000000 1500066662000
# COMMENT netdata_system_cpu_percentage_average: dimension "iowait", value is percentage, gauge, dt 1500066653 to 1500066662 inclusive
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="iowait"} 0.9671802 1500066662000
# COMMENT netdata_system_cpu_percentage_average: dimension "idle", value is percentage, gauge, dt 1500066653 to 1500066662 inclusive
netdata_system_cpu_percentage_average{chart="system.cpu",family="cpu",dimension="idle"} 92.3630770 1500066662000
```
_(Netdata response for `system.cpu` with source=`average`)_
In `average` or `sum` data sources, all values are normalized and are reported to prometheus as gauges. Now, use the
'expression' text form in prometheus. Begin to type the metrics we are looking for: `netdata_system_cpu`. You should see
that the text form begins to auto-fill as prometheus knows about this metric.
If the data source was `as collected`, the response would be:
```sh
# COMMENT homogeneous chart "system.cpu", context "system.cpu", family "cpu", units "percentage"
# COMMENT netdata_system_cpu_total: chart "system.cpu", context "system.cpu", family "cpu", dimension "guest_nice", value * 1 / 1 delta gives percentage (counter)
netdata_system_cpu_total{chart="system.cpu",family="cpu",dimension="guest_nice"} 0 1500066716438
# COMMENT netdata_system_cpu_total: chart "system.cpu", context "system.cpu", family "cpu", dimension "guest", value * 1 / 1 delta gives percentage (counter)
netdata_system_cpu_total{chart="system.cpu",family="cpu",dimension="guest"} 63945 1500066716438
# COMMENT netdata_system_cpu_total: chart "system.cpu", context "system.cpu", family "cpu", dimension "steal", value * 1 / 1 delta gives percentage (counter)
netdata_system_cpu_total{chart="system.cpu",family="cpu",dimension="steal"} 0 1500066716438
# COMMENT netdata_system_cpu_total: chart "system.cpu", context "system.cpu", family "cpu", dimension "softirq", value * 1 / 1 delta gives percentage (counter)
netdata_system_cpu_total{chart="system.cpu",family="cpu",dimension="softirq"} 8295 1500066716438
# COMMENT netdata_system_cpu_total: chart "system.cpu", context "system.cpu", family "cpu", dimension "irq", value * 1 / 1 delta gives percentage (counter)
netdata_system_cpu_total{chart="system.cpu",family="cpu",dimension="irq"} 4079 1500066716438
# COMMENT netdata_system_cpu_total: chart "system.cpu", context "system.cpu", family "cpu", dimension "user", value * 1 / 1 delta gives percentage (counter)
netdata_system_cpu_total{chart="system.cpu",family="cpu",dimension="user"} 116488 1500066716438
# COMMENT netdata_system_cpu_total: chart "system.cpu", context "system.cpu", family "cpu", dimension "system", value * 1 / 1 delta gives percentage (counter)
netdata_system_cpu_total{chart="system.cpu",family="cpu",dimension="system"} 35084 1500066716438
# COMMENT netdata_system_cpu_total: chart "system.cpu", context "system.cpu", family "cpu", dimension "nice", value * 1 / 1 delta gives percentage (counter)
netdata_system_cpu_total{chart="system.cpu",family="cpu",dimension="nice"} 505 1500066716438
# COMMENT netdata_system_cpu_total: chart "system.cpu", context "system.cpu", family "cpu", dimension "iowait", value * 1 / 1 delta gives percentage (counter)
netdata_system_cpu_total{chart="system.cpu",family="cpu",dimension="iowait"} 23314 1500066716438
# COMMENT netdata_system_cpu_total: chart "system.cpu", context "system.cpu", family "cpu", dimension "idle", value * 1 / 1 delta gives percentage (counter)
netdata_system_cpu_total{chart="system.cpu",family="cpu",dimension="idle"} 918470 1500066716438
```
_(Netdata response for `system.cpu` with source=`as-collected`)_
For more information check prometheus documentation.
### Streaming data from upstream hosts
The `format=prometheus` parameter only exports the host's Netdata metrics. If you are using the parent-child
functionality of Netdata this ignores any upstream hosts - so you should consider using the below in your
**prometheus.yml**:
```yaml
metrics_path: '/api/v1/allmetrics'
params:
format: [prometheus_all_hosts]
honor_labels: true
```
This will report all upstream host data, and `honor_labels` will make Prometheus take note of the instance names
provided.
### Timestamps
To pass the metrics through prometheus pushgateway, Netdata supports the option `&timestamps=no` to send the metrics
without timestamps.
## Netdata host variables
Netdata collects various system configuration metrics, like the max number of TCP sockets supported, the max number of
files allowed system-wide, various IPC sizes, etc. These metrics are not exposed to prometheus by default.
To expose them, append `variables=yes` to the Netdata URL.
### TYPE and HELP
To save bandwidth, and because prometheus does not use them anyway, `# TYPE` and `# HELP` lines are suppressed. If
wanted they can be re-enabled via `types=yes` and `help=yes`, e.g.
`/api/v1/allmetrics?format=prometheus&types=yes&help=yes`
Note that if enabled, the `# TYPE` and `# HELP` lines are repeated for every occurrence of a metric, which goes against the Prometheus documentation's [specification for these lines](https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md#comments-help-text-and-type-information).
### Names and IDs
Netdata supports names and IDs for charts and dimensions. Usually IDs are unique identifiers as read by the system and
names are human friendly labels (also unique).
Most charts and metrics have the same ID and name, but in several cases they are different: disks with device-mapper,
interrupts, QoS classes, statsd synthetic charts, etc.
The default is controlled in `netdata.conf`:
```conf
[backend]
send names instead of ids = yes | no
```
You can overwrite it from prometheus, by appending to the URL:
- `&names=no` to get IDs (the old behaviour)
- `&names=yes` to get names
### Filtering metrics sent to prometheus
Netdata can filter the metrics it sends to prometheus with this setting:
```conf
[backend]
send charts matching = *
```
This settings accepts a space separated list of patterns to match the **charts** to be sent to prometheus. Each pattern
can use `*` as wildcard, any number of times (e.g `*a*b*c*` is valid). Patterns starting with `!` give a negative match
(e.g `!*.bad users.* groups.*` will send all the users and groups except `bad` user and `bad` group). The order is
important: the first match (positive or negative) left to right, is used.
### Changing the prefix of Netdata metrics
Netdata sends all metrics prefixed with `netdata_`. You can change this in `netdata.conf`, like this:
```conf
[backend]
prefix = netdata
```
It can also be changed from the URL, by appending `&prefix=netdata`.
### Metric Units
The default source `average` adds the unit of measurement to the name of each metric (e.g. `_KiB_persec`). To hide the
units and get the same metric names as with the other sources, append to the URL `&hideunits=yes`.
The units were standardized in v1.12, with the effect of changing the metric names. To get the metric names as they were
before v1.12, append to the URL `&oldunits=yes`
### Accuracy of `average` and `sum` data sources
When the data source is set to `average` or `sum`, Netdata remembers the last access of each client accessing prometheus
metrics and uses this last access time to respond with the `average` or `sum` of all the entries in the database since
that. This means that prometheus servers are not losing data when they access Netdata with data source = `average` or
`sum`.
To uniquely identify each prometheus server, Netdata uses the IP of the client accessing the metrics. If however the IP
is not good enough for identifying a single prometheus server (e.g. when prometheus servers are accessing Netdata
through a web proxy, or when multiple prometheus servers are NATed to a single IP), each prometheus may append
`&server=NAME` to the URL. This `NAME` is used by Netdata to uniquely identify each prometheus server and keep track of
its last access time.

View File

@ -1,797 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#define BACKENDS_INTERNALS
#include "backend_prometheus.h"
// ----------------------------------------------------------------------------
// PROMETHEUS
// /api/v1/allmetrics?format=prometheus and /api/v1/allmetrics?format=prometheus_all_hosts
static struct prometheus_server {
const char *server;
uint32_t hash;
RRDHOST *host;
time_t last_access;
struct prometheus_server *next;
} *prometheus_server_root = NULL;
static inline time_t prometheus_server_last_access(const char *server, RRDHOST *host, time_t now) {
static netdata_mutex_t prometheus_server_root_mutex = NETDATA_MUTEX_INITIALIZER;
uint32_t hash = simple_hash(server);
netdata_mutex_lock(&prometheus_server_root_mutex);
struct prometheus_server *ps;
for(ps = prometheus_server_root; ps ;ps = ps->next) {
if (host == ps->host && hash == ps->hash && !strcmp(server, ps->server)) {
time_t last = ps->last_access;
ps->last_access = now;
netdata_mutex_unlock(&prometheus_server_root_mutex);
return last;
}
}
ps = callocz(1, sizeof(struct prometheus_server));
ps->server = strdupz(server);
ps->hash = hash;
ps->host = host;
ps->last_access = now;
ps->next = prometheus_server_root;
prometheus_server_root = ps;
netdata_mutex_unlock(&prometheus_server_root_mutex);
return 0;
}
static inline size_t backends_prometheus_name_copy(char *d, const char *s, size_t usable) {
size_t n;
for(n = 0; *s && n < usable ; d++, s++, n++) {
register char c = *s;
if(!isalnum(c)) *d = '_';
else *d = c;
}
*d = '\0';
return n;
}
static inline size_t backends_prometheus_label_copy(char *d, const char *s, size_t usable) {
size_t n;
// make sure we can escape one character without overflowing the buffer
usable--;
for(n = 0; *s && n < usable ; d++, s++, n++) {
register char c = *s;
if(unlikely(c == '"' || c == '\\' || c == '\n')) {
*d++ = '\\';
n++;
}
*d = c;
}
*d = '\0';
return n;
}
static inline char *backends_prometheus_units_copy(char *d, const char *s, size_t usable, int showoldunits) {
const char *sorig = s;
char *ret = d;
size_t n;
// Fix for issue 5227
if (unlikely(showoldunits)) {
static struct {
const char *newunit;
uint32_t hash;
const char *oldunit;
} units[] = {
{"KiB/s", 0, "kilobytes/s"}
, {"MiB/s", 0, "MB/s"}
, {"GiB/s", 0, "GB/s"}
, {"KiB" , 0, "KB"}
, {"MiB" , 0, "MB"}
, {"GiB" , 0, "GB"}
, {"inodes" , 0, "Inodes"}
, {"percentage" , 0, "percent"}
, {"faults/s" , 0, "page faults/s"}
, {"KiB/operation", 0, "kilobytes per operation"}
, {"milliseconds/operation", 0, "ms per operation"}
, {NULL, 0, NULL}
};
static int initialized = 0;
int i;
if(unlikely(!initialized)) {
for (i = 0; units[i].newunit; i++)
units[i].hash = simple_hash(units[i].newunit);
initialized = 1;
}
uint32_t hash = simple_hash(s);
for(i = 0; units[i].newunit ; i++) {
if(unlikely(hash == units[i].hash && !strcmp(s, units[i].newunit))) {
// info("matched extension for filename '%s': '%s'", filename, last_dot);
s=units[i].oldunit;
sorig = s;
break;
}
}
}
*d++ = '_';
for(n = 1; *s && n < usable ; d++, s++, n++) {
register char c = *s;
if(!isalnum(c)) *d = '_';
else *d = c;
}
if(n == 2 && sorig[0] == '%') {
n = 0;
d = ret;
s = "_percent";
for( ; *s && n < usable ; n++) *d++ = *s++;
}
else if(n > 3 && sorig[n-3] == '/' && sorig[n-2] == 's') {
n = n - 2;
d -= 2;
s = "_persec";
for( ; *s && n < usable ; n++) *d++ = *s++;
}
*d = '\0';
return ret;
}
#define PROMETHEUS_ELEMENT_MAX 256
#define PROMETHEUS_LABELS_MAX 1024
#define PROMETHEUS_VARIABLE_MAX 256
#define PROMETHEUS_LABELS_MAX_NUMBER 128
struct host_variables_callback_options {
RRDHOST *host;
BUFFER *wb;
BACKEND_OPTIONS backend_options;
BACKENDS_PROMETHEUS_OUTPUT_OPTIONS output_options;
const char *prefix;
const char *labels;
time_t now;
int host_header_printed;
char name[PROMETHEUS_VARIABLE_MAX+1];
};
static int print_host_variables(RRDVAR *rv, void *data) {
struct host_variables_callback_options *opts = data;
if(rv->options & (RRDVAR_OPTION_CUSTOM_HOST_VAR|RRDVAR_OPTION_CUSTOM_CHART_VAR)) {
if(!opts->host_header_printed) {
opts->host_header_printed = 1;
if(opts->output_options & BACKENDS_PROMETHEUS_OUTPUT_HELP) {
buffer_sprintf(opts->wb, "\n# COMMENT global host and chart variables\n");
}
}
calculated_number value = rrdvar2number(rv);
if(isnan(value) || isinf(value)) {
if(opts->output_options & BACKENDS_PROMETHEUS_OUTPUT_HELP)
buffer_sprintf(opts->wb, "# COMMENT variable \"%s\" is %s. Skipped.\n", rv->name, (isnan(value))?"NAN":"INF");
return 0;
}
char *label_pre = "";
char *label_post = "";
if(opts->labels && *opts->labels) {
label_pre = "{";
label_post = "}";
}
backends_prometheus_name_copy(opts->name, rv->name, sizeof(opts->name));
if(opts->output_options & BACKENDS_PROMETHEUS_OUTPUT_TIMESTAMPS)
buffer_sprintf(opts->wb
, "%s_%s%s%s%s " CALCULATED_NUMBER_FORMAT " %llu\n"
, opts->prefix
, opts->name
, label_pre
, opts->labels
, label_post
, value
, opts->now * 1000ULL
);
else
buffer_sprintf(opts->wb, "%s_%s%s%s%s " CALCULATED_NUMBER_FORMAT "\n"
, opts->prefix
, opts->name
, label_pre
, opts->labels
, label_post
, value
);
return 1;
}
return 0;
}
static void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER *wb, const char *prefix, BACKEND_OPTIONS backend_options, time_t after, time_t before, int allhosts, BACKENDS_PROMETHEUS_OUTPUT_OPTIONS output_options) {
rrdhost_rdlock(host);
char hostname[PROMETHEUS_ELEMENT_MAX + 1];
backends_prometheus_label_copy(hostname, host->hostname, PROMETHEUS_ELEMENT_MAX);
char labels[PROMETHEUS_LABELS_MAX + 1] = "";
if(allhosts) {
if(output_options & BACKENDS_PROMETHEUS_OUTPUT_TIMESTAMPS)
buffer_sprintf(wb, "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1 %llu\n", hostname, host->program_name, host->program_version, now_realtime_usec() / USEC_PER_MS);
else
buffer_sprintf(wb, "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1\n", hostname, host->program_name, host->program_version);
if(host->tags && *(host->tags)) {
if(output_options & BACKENDS_PROMETHEUS_OUTPUT_TIMESTAMPS) {
buffer_sprintf(wb, "netdata_host_tags_info{instance=\"%s\",%s} 1 %llu\n", hostname, host->tags, now_realtime_usec() / USEC_PER_MS);
// deprecated, exists only for compatibility with older queries
buffer_sprintf(wb, "netdata_host_tags{instance=\"%s\",%s} 1 %llu\n", hostname, host->tags, now_realtime_usec() / USEC_PER_MS);
}
else {
buffer_sprintf(wb, "netdata_host_tags_info{instance=\"%s\",%s} 1\n", hostname, host->tags);
// deprecated, exists only for compatibility with older queries
buffer_sprintf(wb, "netdata_host_tags{instance=\"%s\",%s} 1\n", hostname, host->tags);
}
}
snprintfz(labels, PROMETHEUS_LABELS_MAX, ",instance=\"%s\"", hostname);
}
else {
if(output_options & BACKENDS_PROMETHEUS_OUTPUT_TIMESTAMPS)
buffer_sprintf(wb, "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1 %llu\n", hostname, host->program_name, host->program_version, now_realtime_usec() / USEC_PER_MS);
else
buffer_sprintf(wb, "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"} 1\n", hostname, host->program_name, host->program_version);
if(host->tags && *(host->tags)) {
if(output_options & BACKENDS_PROMETHEUS_OUTPUT_TIMESTAMPS) {
buffer_sprintf(wb, "netdata_host_tags_info{%s} 1 %llu\n", host->tags, now_realtime_usec() / USEC_PER_MS);
// deprecated, exists only for compatibility with older queries
buffer_sprintf(wb, "netdata_host_tags{%s} 1 %llu\n", host->tags, now_realtime_usec() / USEC_PER_MS);
}
else {
buffer_sprintf(wb, "netdata_host_tags_info{%s} 1\n", host->tags);
// deprecated, exists only for compatibility with older queries
buffer_sprintf(wb, "netdata_host_tags{%s} 1\n", host->tags);
}
}
}
// send custom variables set for the host
if(output_options & BACKENDS_PROMETHEUS_OUTPUT_VARIABLES){
struct host_variables_callback_options opts = {
.host = host,
.wb = wb,
.labels = (labels[0] == ',')?&labels[1]:labels,
.backend_options = backend_options,
.output_options = output_options,
.prefix = prefix,
.now = now_realtime_sec(),
.host_header_printed = 0
};
foreach_host_variable_callback(host, print_host_variables, &opts);
}
// for each chart
RRDSET *st;
rrdset_foreach_read(st, host) {
char chart[PROMETHEUS_ELEMENT_MAX + 1];
char context[PROMETHEUS_ELEMENT_MAX + 1];
char family[PROMETHEUS_ELEMENT_MAX + 1];
char units[PROMETHEUS_ELEMENT_MAX + 1] = "";
backends_prometheus_label_copy(chart, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && st->name)?st->name:st->id, PROMETHEUS_ELEMENT_MAX);
backends_prometheus_label_copy(family, st->family, PROMETHEUS_ELEMENT_MAX);
backends_prometheus_name_copy(context, st->context, PROMETHEUS_ELEMENT_MAX);
if(likely(backends_can_send_rrdset(backend_options, st))) {
rrdset_rdlock(st);
int as_collected = (BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AS_COLLECTED);
int homogeneous = 1;
if(as_collected) {
if(rrdset_flag_check(st, RRDSET_FLAG_HOMOGENEOUS_CHECK))
rrdset_update_heterogeneous_flag(st);
if(rrdset_flag_check(st, RRDSET_FLAG_HETEROGENEOUS))
homogeneous = 0;
}
else {
if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AVERAGE && !(output_options & BACKENDS_PROMETHEUS_OUTPUT_HIDEUNITS))
backends_prometheus_units_copy(units, st->units, PROMETHEUS_ELEMENT_MAX, output_options & BACKENDS_PROMETHEUS_OUTPUT_OLDUNITS);
}
if(unlikely(output_options & BACKENDS_PROMETHEUS_OUTPUT_HELP))
buffer_sprintf(wb, "\n# COMMENT %s chart \"%s\", context \"%s\", family \"%s\", units \"%s\"\n"
, (homogeneous)?"homogeneous":"heterogeneous"
, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && st->name) ? st->name : st->id
, st->context
, st->family
, st->units
);
// for each dimension
RRDDIM *rd;
rrddim_foreach_read(rd, st) {
if(rd->collections_counter && !rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)) {
char dimension[PROMETHEUS_ELEMENT_MAX + 1];
char *suffix = "";
if (as_collected) {
// we need as-collected / raw data
if(unlikely(rd->last_collected_time.tv_sec < after))
continue;
const char *t = "gauge", *h = "gives";
if(rd->algorithm == RRD_ALGORITHM_INCREMENTAL ||
rd->algorithm == RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL) {
t = "counter";
h = "delta gives";
suffix = "_total";
}
if(homogeneous) {
// all the dimensions of the chart, has the same algorithm, multiplier and divisor
// we add all dimensions as labels
backends_prometheus_label_copy(dimension, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
if(unlikely(output_options & BACKENDS_PROMETHEUS_OUTPUT_HELP))
buffer_sprintf(wb
, "# COMMENT %s_%s%s: chart \"%s\", context \"%s\", family \"%s\", dimension \"%s\", value * " COLLECTED_NUMBER_FORMAT " / " COLLECTED_NUMBER_FORMAT " %s %s (%s)\n"
, prefix
, context
, suffix
, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && st->name) ? st->name : st->id
, st->context
, st->family
, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id
, rd->multiplier
, rd->divisor
, h
, st->units
, t
);
if(unlikely(output_options & BACKENDS_PROMETHEUS_OUTPUT_TYPES))
buffer_sprintf(wb, "# TYPE %s_%s%s %s\n"
, prefix
, context
, suffix
, t
);
if(output_options & BACKENDS_PROMETHEUS_OUTPUT_TIMESTAMPS)
buffer_sprintf(wb
, "%s_%s%s{chart=\"%s\",family=\"%s\",dimension=\"%s\"%s} " COLLECTED_NUMBER_FORMAT " %llu\n"
, prefix
, context
, suffix
, chart
, family
, dimension
, labels
, rd->last_collected_value
, timeval_msec(&rd->last_collected_time)
);
else
buffer_sprintf(wb
, "%s_%s%s{chart=\"%s\",family=\"%s\",dimension=\"%s\"%s} " COLLECTED_NUMBER_FORMAT "\n"
, prefix
, context
, suffix
, chart
, family
, dimension
, labels
, rd->last_collected_value
);
}
else {
// the dimensions of the chart, do not have the same algorithm, multiplier or divisor
// we create a metric per dimension
backends_prometheus_name_copy(dimension, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
if(unlikely(output_options & BACKENDS_PROMETHEUS_OUTPUT_HELP))
buffer_sprintf(wb
, "# COMMENT %s_%s_%s%s: chart \"%s\", context \"%s\", family \"%s\", dimension \"%s\", value * " COLLECTED_NUMBER_FORMAT " / " COLLECTED_NUMBER_FORMAT " %s %s (%s)\n"
, prefix
, context
, dimension
, suffix
, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && st->name) ? st->name : st->id
, st->context
, st->family
, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id
, rd->multiplier
, rd->divisor
, h
, st->units
, t
);
if(unlikely(output_options & BACKENDS_PROMETHEUS_OUTPUT_TYPES))
buffer_sprintf(wb, "# TYPE %s_%s_%s%s %s\n"
, prefix
, context
, dimension
, suffix
, t
);
if(output_options & BACKENDS_PROMETHEUS_OUTPUT_TIMESTAMPS)
buffer_sprintf(wb
, "%s_%s_%s%s{chart=\"%s\",family=\"%s\"%s} " COLLECTED_NUMBER_FORMAT " %llu\n"
, prefix
, context
, dimension
, suffix
, chart
, family
, labels
, rd->last_collected_value
, timeval_msec(&rd->last_collected_time)
);
else
buffer_sprintf(wb
, "%s_%s_%s%s{chart=\"%s\",family=\"%s\"%s} " COLLECTED_NUMBER_FORMAT "\n"
, prefix
, context
, dimension
, suffix
, chart
, family
, labels
, rd->last_collected_value
);
}
}
else {
// we need average or sum of the data
time_t first_t = after, last_t = before;
calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, backend_options, &first_t, &last_t);
if(!isnan(value) && !isinf(value)) {
if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AVERAGE)
suffix = "_average";
else if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_SUM)
suffix = "_sum";
backends_prometheus_label_copy(dimension, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
if (unlikely(output_options & BACKENDS_PROMETHEUS_OUTPUT_HELP))
buffer_sprintf(wb, "# COMMENT %s_%s%s%s: dimension \"%s\", value is %s, gauge, dt %llu to %llu inclusive\n"
, prefix
, context
, units
, suffix
, (output_options & BACKENDS_PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id
, st->units
, (unsigned long long)first_t
, (unsigned long long)last_t
);
if (unlikely(output_options & BACKENDS_PROMETHEUS_OUTPUT_TYPES))
buffer_sprintf(wb, "# TYPE %s_%s%s%s gauge\n"
, prefix
, context
, units
, suffix
);
if(output_options & BACKENDS_PROMETHEUS_OUTPUT_TIMESTAMPS)
buffer_sprintf(wb, "%s_%s%s%s{chart=\"%s\",family=\"%s\",dimension=\"%s\"%s} " CALCULATED_NUMBER_FORMAT " %llu\n"
, prefix
, context
, units
, suffix
, chart
, family
, dimension
, labels
, value
, last_t * MSEC_PER_SEC
);
else
buffer_sprintf(wb, "%s_%s%s%s{chart=\"%s\",family=\"%s\",dimension=\"%s\"%s} " CALCULATED_NUMBER_FORMAT "\n"
, prefix
, context
, units
, suffix
, chart
, family
, dimension
, labels
, value
);
}
}
}
}
rrdset_unlock(st);
}
}
rrdhost_unlock(host);
}
#if ENABLE_PROMETHEUS_REMOTE_WRITE
inline static void remote_write_split_words(char *str, char **words, int max_words) {
char *s = str;
int i = 0;
while(*s && i < max_words - 1) {
while(*s && isspace(*s)) s++; // skip spaces to the beginning of a tag name
if(*s)
words[i] = s;
while(*s && !isspace(*s) && *s != '=') s++; // find the end of the tag name
if(*s != '=') {
words[i] = NULL;
break;
}
*s = '\0';
s++;
i++;
while(*s && isspace(*s)) s++; // skip spaces to the beginning of a tag value
if(*s && *s == '"') s++; // strip an opening quote
if(*s)
words[i] = s;
while(*s && !isspace(*s) && *s != ',') s++; // find the end of the tag value
if(*s && *s != ',') {
words[i] = NULL;
break;
}
if(s != words[i] && *(s - 1) == '"') *(s - 1) = '\0'; // strip a closing quote
if(*s != '\0') {
*s = '\0';
s++;
i++;
}
}
}
void backends_rrd_stats_remote_write_allmetrics_prometheus(
RRDHOST *host
, const char *__hostname
, const char *prefix
, BACKEND_OPTIONS backend_options
, time_t after
, time_t before
, size_t *count_charts
, size_t *count_dims
, size_t *count_dims_skipped
) {
char hostname[PROMETHEUS_ELEMENT_MAX + 1];
backends_prometheus_label_copy(hostname, __hostname, PROMETHEUS_ELEMENT_MAX);
backends_add_host_info("netdata_info", hostname, host->program_name, host->program_version, now_realtime_usec() / USEC_PER_MS);
if(host->tags && *(host->tags)) {
char tags[PROMETHEUS_LABELS_MAX + 1];
strncpy(tags, host->tags, PROMETHEUS_LABELS_MAX);
char *words[PROMETHEUS_LABELS_MAX_NUMBER] = {NULL};
int i;
remote_write_split_words(tags, words, PROMETHEUS_LABELS_MAX_NUMBER);
backends_add_host_info("netdata_host_tags_info", hostname, NULL, NULL, now_realtime_usec() / USEC_PER_MS);
for(i = 0; words[i] != NULL && words[i + 1] != NULL && (i + 1) < PROMETHEUS_LABELS_MAX_NUMBER; i += 2) {
backends_add_tag(words[i], words[i + 1]);
}
}
// for each chart
RRDSET *st;
rrdset_foreach_read(st, host) {
char chart[PROMETHEUS_ELEMENT_MAX + 1];
char context[PROMETHEUS_ELEMENT_MAX + 1];
char family[PROMETHEUS_ELEMENT_MAX + 1];
char units[PROMETHEUS_ELEMENT_MAX + 1] = "";
backends_prometheus_label_copy(chart, (backend_options & BACKEND_OPTION_SEND_NAMES && st->name)?st->name:st->id, PROMETHEUS_ELEMENT_MAX);
backends_prometheus_label_copy(family, st->family, PROMETHEUS_ELEMENT_MAX);
backends_prometheus_name_copy(context, st->context, PROMETHEUS_ELEMENT_MAX);
if(likely(backends_can_send_rrdset(backend_options, st))) {
rrdset_rdlock(st);
(*count_charts)++;
int as_collected = (BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AS_COLLECTED);
int homogeneous = 1;
if(as_collected) {
if(rrdset_flag_check(st, RRDSET_FLAG_HOMOGENEOUS_CHECK))
rrdset_update_heterogeneous_flag(st);
if(rrdset_flag_check(st, RRDSET_FLAG_HETEROGENEOUS))
homogeneous = 0;
}
else {
if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AVERAGE)
backends_prometheus_units_copy(units, st->units, PROMETHEUS_ELEMENT_MAX, 0);
}
// for each dimension
RRDDIM *rd;
rrddim_foreach_read(rd, st) {
if(rd->collections_counter && !rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)) {
char name[PROMETHEUS_LABELS_MAX + 1];
char dimension[PROMETHEUS_ELEMENT_MAX + 1];
char *suffix = "";
if (as_collected) {
// we need as-collected / raw data
if(unlikely(rd->last_collected_time.tv_sec < after)) {
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);
(*count_dims_skipped)++;
continue;
}
if(homogeneous) {
// all the dimensions of the chart, has the same algorithm, multiplier and divisor
// we add all dimensions as labels
backends_prometheus_label_copy(dimension, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
snprintf(name, PROMETHEUS_LABELS_MAX, "%s_%s%s", prefix, context, suffix);
backends_add_metric(name, chart, family, dimension, hostname, rd->last_collected_value, timeval_msec(&rd->last_collected_time));
(*count_dims)++;
}
else {
// the dimensions of the chart, do not have the same algorithm, multiplier or divisor
// we create a metric per dimension
backends_prometheus_name_copy(dimension, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
snprintf(name, PROMETHEUS_LABELS_MAX, "%s_%s_%s%s", prefix, context, dimension, suffix);
backends_add_metric(name, chart, family, NULL, hostname, rd->last_collected_value, timeval_msec(&rd->last_collected_time));
(*count_dims)++;
}
}
else {
// we need average or sum of the data
time_t first_t = after, last_t = before;
calculated_number value = backend_calculate_value_from_stored_data(st, rd, after, before, backend_options, &first_t, &last_t);
if(!isnan(value) && !isinf(value)) {
if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AVERAGE)
suffix = "_average";
else if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_SUM)
suffix = "_sum";
backends_prometheus_label_copy(dimension, (backend_options & BACKEND_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id, PROMETHEUS_ELEMENT_MAX);
snprintf(name, PROMETHEUS_LABELS_MAX, "%s_%s%s%s", prefix, context, units, suffix);
backends_add_metric(name, chart, family, dimension, hostname, value, last_t * MSEC_PER_SEC);
(*count_dims)++;
}
}
}
}
rrdset_unlock(st);
}
}
}
#endif /* ENABLE_PROMETHEUS_REMOTE_WRITE */
static inline time_t prometheus_preparation(RRDHOST *host, BUFFER *wb, BACKEND_OPTIONS backend_options, const char *server, time_t now, BACKENDS_PROMETHEUS_OUTPUT_OPTIONS output_options) {
if(!server || !*server) server = "default";
time_t after = prometheus_server_last_access(server, host, now);
int first_seen = 0;
if(!after) {
after = now - global_backend_update_every;
first_seen = 1;
}
if(after > now) {
// oops! this should never happen
after = now - global_backend_update_every;
}
if(output_options & BACKENDS_PROMETHEUS_OUTPUT_HELP) {
char *mode;
if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AS_COLLECTED)
mode = "as collected";
else if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_AVERAGE)
mode = "average";
else if(BACKEND_OPTIONS_DATA_SOURCE(backend_options) == BACKEND_SOURCE_DATA_SUM)
mode = "sum";
else
mode = "unknown";
buffer_sprintf(wb, "# COMMENT netdata \"%s\" to %sprometheus \"%s\", source \"%s\", last seen %lu %s, time range %lu to %lu\n\n"
, host->hostname
, (first_seen)?"FIRST SEEN ":""
, server
, mode
, (unsigned long)((first_seen)?0:(now - after))
, (first_seen)?"never":"seconds ago"
, (unsigned long)after, (unsigned long)now
);
}
return after;
}
void backends_rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(RRDHOST *host, BUFFER *wb, const char *server, const char *prefix, BACKEND_OPTIONS backend_options, BACKENDS_PROMETHEUS_OUTPUT_OPTIONS output_options) {
time_t before = now_realtime_sec();
// we start at the point we had stopped before
time_t after = prometheus_preparation(host, wb, backend_options, server, before, output_options);
rrd_stats_api_v1_charts_allmetrics_prometheus(host, wb, prefix, backend_options, after, before, 0, output_options);
}
void backends_rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(RRDHOST *host, BUFFER *wb, const char *server, const char *prefix, BACKEND_OPTIONS backend_options, BACKENDS_PROMETHEUS_OUTPUT_OPTIONS output_options) {
time_t before = now_realtime_sec();
// we start at the point we had stopped before
time_t after = prometheus_preparation(host, wb, backend_options, server, before, output_options);
rrd_rdlock();
rrdhost_foreach_read(host) {
rrd_stats_api_v1_charts_allmetrics_prometheus(host, wb, prefix, backend_options, after, before, 1, output_options);
}
rrd_unlock();
}
#if ENABLE_PROMETHEUS_REMOTE_WRITE
int backends_process_prometheus_remote_write_response(BUFFER *b) {
if(unlikely(!b)) return 1;
const char *s = buffer_tostring(b);
int len = buffer_strlen(b);
// do nothing with HTTP responses 200 or 204
while(!isspace(*s) && len) {
s++;
len--;
}
s++;
len--;
if(likely(len > 4 && (!strncmp(s, "200 ", 4) || !strncmp(s, "204 ", 4))))
return 0;
else
return discard_response(b, "prometheus remote write");
}
#endif

View File

@ -1,37 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_BACKEND_PROMETHEUS_H
#define NETDATA_BACKEND_PROMETHEUS_H 1
#include "backends/backends.h"
typedef enum backends_prometheus_output_flags {
BACKENDS_PROMETHEUS_OUTPUT_NONE = 0,
BACKENDS_PROMETHEUS_OUTPUT_HELP = (1 << 0),
BACKENDS_PROMETHEUS_OUTPUT_TYPES = (1 << 1),
BACKENDS_PROMETHEUS_OUTPUT_NAMES = (1 << 2),
BACKENDS_PROMETHEUS_OUTPUT_TIMESTAMPS = (1 << 3),
BACKENDS_PROMETHEUS_OUTPUT_VARIABLES = (1 << 4),
BACKENDS_PROMETHEUS_OUTPUT_OLDUNITS = (1 << 5),
BACKENDS_PROMETHEUS_OUTPUT_HIDEUNITS = (1 << 6)
} BACKENDS_PROMETHEUS_OUTPUT_OPTIONS;
extern void backends_rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(RRDHOST *host, BUFFER *wb, const char *server, const char *prefix, BACKEND_OPTIONS backend_options, BACKENDS_PROMETHEUS_OUTPUT_OPTIONS output_options);
extern void backends_rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(RRDHOST *host, BUFFER *wb, const char *server, const char *prefix, BACKEND_OPTIONS backend_options, BACKENDS_PROMETHEUS_OUTPUT_OPTIONS output_options);
#if ENABLE_PROMETHEUS_REMOTE_WRITE
extern void backends_rrd_stats_remote_write_allmetrics_prometheus(
RRDHOST *host
, const char *__hostname
, const char *prefix
, BACKEND_OPTIONS backend_options
, time_t after
, time_t before
, size_t *count_charts
, size_t *count_dims
, size_t *count_dims_skipped
);
extern int backends_process_prometheus_remote_write_response(BUFFER *b);
#endif
#endif //NETDATA_BACKEND_PROMETHEUS_H

View File

@ -1,14 +0,0 @@
# SPDX-License-Identifier: GPL-3.0-or-later
AUTOMAKE_OPTIONS = subdir-objects
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
CLEANFILES = \
remote_write.pb.cc \
remote_write.pb.h \
$(NULL)
dist_noinst_DATA = \
remote_write.proto \
README.md \
$(NULL)

View File

@ -1,41 +0,0 @@
<!--
title: "Prometheus remote write backend"
custom_edit_url: https://github.com/netdata/netdata/edit/master/backends/prometheus/remote_write/README.md
-->
# Prometheus remote write backend
## Prerequisites
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.
## Configuration
An additional option in the backend configuration section is available for the remote write backend:
```conf
[backend]
remote write URL path = /receive
```
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
```conf
[backend]
destination = example.domain:example_port
remote write URL path = /storage/read
```
`buffered` and `lost` dimensions in the Netdata Backend Data Size operation monitoring chart estimate uncompressed
buffer size on failures.
## Notes
The remote write backend does not support `buffer on failures`

View File

@ -1,120 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include <snappy.h>
#include "exporting/prometheus/remote_write/remote_write.pb.h"
#include "remote_write.h"
using namespace prometheus;
static google::protobuf::Arena arena;
static WriteRequest *write_request;
void backends_init_write_request() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
write_request = google::protobuf::Arena::CreateMessage<WriteRequest>(&arena);
}
void backends_clear_write_request() {
write_request->clear_timeseries();
}
void backends_add_host_info(const char *name, const char *instance, const char *application, const char *version, const int64_t timestamp) {
TimeSeries *timeseries;
Sample *sample;
Label *label;
timeseries = write_request->add_timeseries();
label = timeseries->add_labels();
label->set_name("__name__");
label->set_value(name);
label = timeseries->add_labels();
label->set_name("instance");
label->set_value(instance);
if(application) {
label = timeseries->add_labels();
label->set_name("application");
label->set_value(application);
}
if(version) {
label = timeseries->add_labels();
label->set_name("version");
label->set_value(version);
}
sample = timeseries->add_samples();
sample->set_value(1);
sample->set_timestamp(timestamp);
}
// adds tag to the last created timeseries
void backends_add_tag(char *tag, char *value) {
TimeSeries *timeseries;
Label *label;
timeseries = write_request->mutable_timeseries(write_request->timeseries_size() - 1);
label = timeseries->add_labels();
label->set_name(tag);
label->set_value(value);
}
void backends_add_metric(const char *name, const char *chart, const char *family, const char *dimension, const char *instance, const double value, const int64_t timestamp) {
TimeSeries *timeseries;
Sample *sample;
Label *label;
timeseries = write_request->add_timeseries();
label = timeseries->add_labels();
label->set_name("__name__");
label->set_value(name);
label = timeseries->add_labels();
label->set_name("chart");
label->set_value(chart);
label = timeseries->add_labels();
label->set_name("family");
label->set_value(family);
if(dimension) {
label = timeseries->add_labels();
label->set_name("dimension");
label->set_value(dimension);
}
label = timeseries->add_labels();
label->set_name("instance");
label->set_value(instance);
sample = timeseries->add_samples();
sample->set_value(value);
sample->set_timestamp(timestamp);
}
size_t backends_get_write_request_size(){
#if GOOGLE_PROTOBUF_VERSION < 3001000
size_t size = (size_t)snappy::MaxCompressedLength(write_request->ByteSize());
#else
size_t size = (size_t)snappy::MaxCompressedLength(write_request->ByteSizeLong());
#endif
return (size < INT_MAX)?size:0;
}
int backends_pack_write_request(char *buffer, size_t *size) {
std::string uncompressed_write_request;
if(write_request->SerializeToString(&uncompressed_write_request) == false) return 1;
snappy::RawCompress(uncompressed_write_request.data(), uncompressed_write_request.size(), buffer, size);
return 0;
}
void backends_protocol_buffers_shutdown() {
google::protobuf::ShutdownProtobufLibrary();
}

View File

@ -1,30 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NETDATA_BACKEND_PROMETHEUS_REMOTE_WRITE_H
#define NETDATA_BACKEND_PROMETHEUS_REMOTE_WRITE_H
#ifdef __cplusplus
extern "C" {
#endif
void backends_init_write_request();
void backends_clear_write_request();
void backends_add_host_info(const char *name, const char *instance, const char *application, const char *version, const int64_t timestamp);
void backends_add_tag(char *tag, char *value);
void backends_add_metric(const char *name, const char *chart, const char *family, const char *dimension, const char *instance, const double value, const int64_t timestamp);
size_t backends_get_write_request_size();
int backends_pack_write_request(char *buffer, size_t *size);
void backends_protocol_buffers_shutdown();
#ifdef __cplusplus
}
#endif
#endif //NETDATA_BACKEND_PROMETHEUS_REMOTE_WRITE_H

View File

@ -1,29 +0,0 @@
syntax = "proto3";
package prometheus;
option cc_enable_arenas = true;
import "google/protobuf/descriptor.proto";
message WriteRequest {
repeated TimeSeries timeseries = 1 [(nullable) = false];
}
message TimeSeries {
repeated Label labels = 1 [(nullable) = false];
repeated Sample samples = 2 [(nullable) = false];
}
message Label {
string name = 1;
string value = 2;
}
message Sample {
double value = 1;
int64 timestamp = 2;
}
extend google.protobuf.FieldOptions {
bool nullable = 65001;
}

View File

@ -138,21 +138,6 @@
[cloud]
# cloud base url = https://netdata.cloud
[backend]
# host tags =
# enabled = no
# data source = average
# type = graphite
# destination = localhost
# prefix = netdata
# hostname = b073e16793c4
# update every = 10
# buffer on failures = 10
# timeout ms = 20000
# send names instead of ids = yes
# send charts matching = *
# send hosts matching = localhost *
[statsd]
# enabled = yes
# update every (flushInterval) = 1

View File

@ -40,10 +40,8 @@ our [collectors' configuration reference](/collectors/REFERENCE.md).
**[Dashboards](/web/README.md)**: Visualize your newly-collect metrics in real-time using Netdata's [built-in
dashboard](/web/gui/README.md).
**[Backends](/backends/README.md)**: Extend our built-in [database engine](/database/engine/README.md), which supports
long-term metrics storage, by archiving metrics to like Graphite, Prometheus, MongoDB, TimescaleDB, and more.
**[Exporting](/exporting/README.md)**: An experimental refactoring of our backends system with a modular system and
support for exporting metrics to multiple systems simultaneously.
**[Exporting](/exporting/README.md)**: Extend our built-in [database engine](/database/engine/README.md), which supports
long-term metrics storage, by archiving metrics to external databases like Graphite, Prometheus, MongoDB, TimescaleDB, and more.
It can export metrics to multiple databases simultaneously.

View File

@ -231,7 +231,7 @@ the template is:
- `options`
a space separated list of options, enclosed in quotes. 4 options are currently supported: `obsolete` to mark a chart as obsolete (Netdata will hide it and delete it after some time), `detail` to mark a chart as insignificant (this may be used by dashboards to make the charts smaller, or somehow visualize properly a less important chart), `store_first` to make Netdata store the first collected value, assuming there was an invisible previous value set to zero (this is used by statsd charts - if the first data collected value of incremental dimensions is not zero based, unrealistic spikes will appear with this option set) and `hidden` to perform all operations on a chart, but do not offer it on dashboards (the chart will be send to backends). `CHART` options have been added in Netdata v1.7 and the `hidden` option was added in 1.10.
a space separated list of options, enclosed in quotes. 4 options are currently supported: `obsolete` to mark a chart as obsolete (Netdata will hide it and delete it after some time), `detail` to mark a chart as insignificant (this may be used by dashboards to make the charts smaller, or somehow visualize properly a less important chart), `store_first` to make Netdata store the first collected value, assuming there was an invisible previous value set to zero (this is used by statsd charts - if the first data collected value of incremental dimensions is not zero based, unrealistic spikes will appear with this option set) and `hidden` to perform all operations on a chart, but do not offer it on dashboards (the chart will be send to external databases). `CHART` options have been added in Netdata v1.7 and the `hidden` option was added in 1.10.
- `plugin` and `module`
@ -252,7 +252,7 @@ the template is:
the `id` of this dimension (it is a text value, not numeric),
this will be needed later to add values to the dimension
We suggest to avoid using `.` in dimension ids. Backends expect metrics to be `.` separated and people will get confused if a dimension id contains a dot.
We suggest to avoid using `.` in dimension ids. External databases expect metrics to be `.` separated and people will get confused if a dimension id contains a dot.
- `name`

View File

@ -43,7 +43,7 @@
# When a plugin sends the obsolete flag, the charts are not deleted
# from netdata immediately.
# They will be hidden immediately (not offered to dashboard viewer,
# streamed upstream and archived to backends) and deleted one hour
# streamed upstream and archived to external databases) and deleted one hour
# later (configurable from netdata.conf).
# chart_cleanup: 10

View File

@ -35,7 +35,7 @@
# A chart is marked as obsolete if it has not been updated
# 'chart_cleanup' iterations in a row.
# They will be hidden immediately (not offered to dashboard viewer,
# streamed upstream and archived to backends) and deleted one hour
# streamed upstream and archived to external databases) and deleted one hour
# later (configurable from netdata.conf).
# -- For this plugin, cleanup MUST be disabled, otherwise we lose response
# time charts

View File

@ -35,7 +35,7 @@
# A chart is marked as obsolete if it has not been updated
# 'chart_cleanup' iterations in a row.
# They will be hidden immediately (not offered to dashboard viewer,
# streamed upstream and archived to backends) and deleted one hour
# streamed upstream and archived to external databases) and deleted one hour
# later (configurable from netdata.conf).
# -- For this plugin, cleanup MUST be disabled, otherwise we lose latency chart
chart_cleanup: 0

View File

@ -71,10 +71,10 @@ AC_ARG_ENABLE(
[enable_plugin_xenstat="detect"]
)
AC_ARG_ENABLE(
[backend-kinesis],
[AS_HELP_STRING([--enable-backend-kinesis], [enable kinesis backend @<:@default autodetect@:>@])],
[exporting-kinesis],
[AS_HELP_STRING([--enable-exporting-kinesis], [enable kinesis exporting connector @<:@default autodetect@:>@])],
,
[enable_backend_kinesis="detect"]
[enable_exporting_kinesis="detect"]
)
AC_ARG_ENABLE(
[exporting-pubsub],
@ -83,16 +83,16 @@ AC_ARG_ENABLE(
[enable_exporting_pubsub="detect"]
)
AC_ARG_ENABLE(
[backend-prometheus-remote-write],
[AS_HELP_STRING([--enable-backend-prometheus-remote-write], [enable prometheus remote write backend @<:@default autodetect@:>@])],
[exporting-prometheus-remote-write],
[AS_HELP_STRING([--enable-exporting-prometheus-remote-write], [enable prometheus remote write exporting connector @<:@default autodetect@:>@])],
,
[enable_backend_prometheus_remote_write="detect"]
[enable_exporting_prometheus_remote_write="detect"]
)
AC_ARG_ENABLE(
[backend-mongodb],
[AS_HELP_STRING([--enable-backend-mongodb], [enable mongodb backend @<:@default autodetect@:>@])],
[exporting-mongodb],
[AS_HELP_STRING([--enable-exporting-mongodb], [enable mongodb exporting @<:@default autodetect@:>@])],
,
[enable_backend_mongodb="detect"]
[enable_exporting_mongodb="detect"]
)
AC_ARG_ENABLE(
[pedantic],
@ -1246,7 +1246,7 @@ AM_CONDITIONAL([ENABLE_PLUGIN_SLABINFO], [test "${enable_plugin_slabinfo}" = "ye
# -----------------------------------------------------------------------------
# AWS Kinesis backend - libaws-cpp-sdk-kinesis, libaws-cpp-sdk-core, libssl, libcrypto, libcurl
# AWS Kinesis exporting connector - libaws-cpp-sdk-kinesis, libaws-cpp-sdk-core, libssl, libcrypto, libcurl
PKG_CHECK_MODULES(
[LIBCRYPTO],
@ -1298,39 +1298,39 @@ PKG_CHECK_MODULES(
[have_libaws_cpp_sdk_kinesis=no]
)
test "${enable_backend_kinesis}" = "yes" -a "${have_libaws_cpp_sdk_kinesis}" != "yes" && \
test "${enable_exporting_kinesis}" = "yes" -a "${have_libaws_cpp_sdk_kinesis}" != "yes" && \
AC_MSG_ERROR([libaws-cpp-sdk-kinesis required but not found. try installing AWS C++ SDK])
test "${enable_backend_kinesis}" = "yes" -a "${have_libaws_cpp_sdk_core}" != "yes" && \
test "${enable_exporting_kinesis}" = "yes" -a "${have_libaws_cpp_sdk_core}" != "yes" && \
AC_MSG_ERROR([libaws-cpp-sdk-core required but not found. try installing AWS C++ SDK])
test "${enable_backend_kinesis}" = "yes" -a "${have_libcurl}" != "yes" && \
test "${enable_exporting_kinesis}" = "yes" -a "${have_libcurl}" != "yes" && \
AC_MSG_ERROR([libcurl required but not found])
test "${enable_backend_kinesis}" = "yes" -a "${have_libssl}" != "yes" && \
test "${enable_exporting_kinesis}" = "yes" -a "${have_libssl}" != "yes" && \
AC_MSG_ERROR([libssl required but not found])
test "${enable_backend_kinesis}" = "yes" -a "${have_libcrypto}" != "yes" && \
test "${enable_exporting_kinesis}" = "yes" -a "${have_libcrypto}" != "yes" && \
AC_MSG_ERROR([libcrypto required but not found])
AC_MSG_CHECKING([if kinesis backend should be enabled])
if test "${enable_backend_kinesis}" != "no" -a "${have_libaws_cpp_sdk_kinesis}" = "yes" \
AC_MSG_CHECKING([if kinesis exporting connector should be enabled])
if test "${enable_exporting_kinesis}" != "no" -a "${have_libaws_cpp_sdk_kinesis}" = "yes" \
-a "${have_libaws_cpp_sdk_core}" = "yes" \
-a "${have_libcurl}" = "yes" \
-a "${have_libssl}" = "yes" \
-a "${have_libcrypto}" = "yes"; then
enable_backend_kinesis="yes"
enable_exporting_kinesis="yes"
AC_DEFINE([HAVE_KINESIS], [1], [libaws-cpp-sdk-kinesis usability])
OPTIONAL_KINESIS_CFLAGS="${LIBCRYPTO_CFLAGS} ${LIBSSL_CFLAGS} ${LIBCURL_CFLAGS}"
CXX11FLAG="${AWS_CPP_SDK_KINESIS_CFLAGS} ${AWS_CPP_SDK_CORE_CFLAGS}"
OPTIONAL_KINESIS_LIBS="${AWS_CPP_SDK_KINESIS_LIBS} ${AWS_CPP_SDK_CORE_LIBS} \
${LIBCRYPTO_LIBS} ${LIBSSL_LIBS} ${LIBCURL_LIBS}"
else
enable_backend_kinesis="no"
enable_exporting_kinesis="no"
fi
AC_MSG_RESULT([${enable_backend_kinesis}])
AM_CONDITIONAL([ENABLE_BACKEND_KINESIS], [test "${enable_backend_kinesis}" = "yes"])
AC_MSG_RESULT([${enable_exporting_kinesis}])
AM_CONDITIONAL([ENABLE_EXPORTING_KINESIS], [test "${enable_exporting_kinesis}" = "yes"])
# -----------------------------------------------------------------------------
@ -1365,7 +1365,7 @@ test "${enable_pubsub}" = "yes" -a "${have_grpc}" != "yes" && \
test "${enable_pubsub}" = "yes" -a "${have_pubsub_protos}" != "yes" && \
AC_MSG_ERROR([libgoogleapis_cpp_pubsub_protos required but not found. try installing googleapis])
test "${enable_backend_prometheus_remote_write}" = "yes" -a "${have_CXX_compiler}" != "yes" && \
test "${enable_exporting_prometheus_remote_write}" = "yes" -a "${have_CXX_compiler}" != "yes" && \
AC_MSG_ERROR([C++ compiler required but not found. try installing g++])
AC_MSG_CHECKING([if pubsub exporting connector should be enabled])
@ -1384,7 +1384,7 @@ AM_CONDITIONAL([ENABLE_EXPORTING_PUBSUB], [test "${enable_exporting_pubsub}" = "
# -----------------------------------------------------------------------------
# Prometheus remote write backend - libprotobuf, libsnappy, protoc
# Prometheus remote write exporting connector - libprotobuf, libsnappy, protoc
AC_MSG_CHECKING([for snappy::RawCompress in -lsnappy])
@ -1421,22 +1421,22 @@ AC_MSG_CHECKING([for snappy::RawCompress in -lsnappy])
AC_MSG_RESULT([${have_libsnappy}])
test "${enable_backend_prometheus_remote_write}" = "yes" -a "${have_libprotobuf}" != "yes" && \
test "${enable_exporting_prometheus_remote_write}" = "yes" -a "${have_libprotobuf}" != "yes" && \
AC_MSG_ERROR([libprotobuf required but not found. try installing protobuf])
test "${enable_backend_prometheus_remote_write}" = "yes" -a "${have_libsnappy}" != "yes" && \
test "${enable_exporting_prometheus_remote_write}" = "yes" -a "${have_libsnappy}" != "yes" && \
AC_MSG_ERROR([libsnappy required but not found. try installing snappy])
test "${enable_backend_prometheus_remote_write}" = "yes" -a "${have_protoc}" != "yes" && \
test "${enable_exporting_prometheus_remote_write}" = "yes" -a "${have_protoc}" != "yes" && \
AC_MSG_ERROR([protoc compiler required but not found. try installing protobuf])
test "${enable_backend_prometheus_remote_write}" = "yes" -a "${have_CXX_compiler}" != "yes" && \
test "${enable_exporting_prometheus_remote_write}" = "yes" -a "${have_CXX_compiler}" != "yes" && \
AC_MSG_ERROR([C++ compiler required but not found. try installing g++])
AC_MSG_CHECKING([if prometheus remote write backend should be enabled])
if test "${enable_backend_prometheus_remote_write}" != "no" -a "${have_libprotobuf}" = "yes" -a "${have_libsnappy}" = "yes" \
AC_MSG_CHECKING([if prometheus remote write exporting connector should be enabled])
if test "${enable_exporting_prometheus_remote_write}" != "no" -a "${have_libprotobuf}" = "yes" -a "${have_libsnappy}" = "yes" \
-a "${have_protoc}" = "yes" -a "${have_CXX_compiler}" = "yes"; then
enable_backend_prometheus_remote_write="yes"
enable_exporting_prometheus_remote_write="yes"
AC_DEFINE([ENABLE_PROMETHEUS_REMOTE_WRITE], [1], [Prometheus remote write API usability])
OPTIONAL_PROMETHEUS_REMOTE_WRITE_CFLAGS="${SNAPPY_CFLAGS} -I \$(abs_top_srcdir)/exporting/prometheus/remote_write"
CXX11FLAG="-std=c++11"
@ -1444,15 +1444,15 @@ if test "${enable_backend_prometheus_remote_write}" != "no" -a "${have_libprotob
OPTIONAL_PROTOBUF_CFLAGS="${PROTOBUF_CFLAGS}"
OPTIONAL_PROTOBUF_LIBS="${PROTOBUF_LIBS}"
else
enable_backend_prometheus_remote_write="no"
enable_exporting_prometheus_remote_write="no"
fi
AC_MSG_RESULT([${enable_backend_prometheus_remote_write}])
AM_CONDITIONAL([ENABLE_BACKEND_PROMETHEUS_REMOTE_WRITE], [test "${enable_backend_prometheus_remote_write}" = "yes"])
AC_MSG_RESULT([${enable_exporting_prometheus_remote_write}])
AM_CONDITIONAL([ENABLE_EXPORTING_PROMETHEUS_REMOTE_WRITE], [test "${enable_exporting_prometheus_remote_write}" = "yes"])
# -----------------------------------------------------------------------------
# MongoDB backend - libmongoc
# MongoDB exporting connector - libmongoc
PKG_CHECK_MODULES(
[LIBMONGOC],
@ -1461,21 +1461,21 @@ PKG_CHECK_MODULES(
[have_libmongoc=no]
)
test "${enable_backend_mongodb}" = "yes" -a "${have_libmongoc}" != "yes" && \
test "${enable_exporting_mongodb}" = "yes" -a "${have_libmongoc}" != "yes" && \
AC_MSG_ERROR([libmongoc required but not found. Try installing `mongoc`.])
AC_MSG_CHECKING([if mongodb backend should be enabled])
if test "${enable_backend_mongodb}" != "no" -a "${have_libmongoc}" = "yes"; then
enable_backend_mongodb="yes"
AC_MSG_CHECKING([if mongodb exporting connector should be enabled])
if test "${enable_exporting_mongodb}" != "no" -a "${have_libmongoc}" = "yes"; then
enable_exporting_mongodb="yes"
AC_DEFINE([HAVE_MONGOC], [1], [libmongoc usability])
OPTIONAL_MONGOC_CFLAGS="${LIBMONGOC_CFLAGS}"
OPTIONAL_MONGOC_LIBS="${LIBMONGOC_LIBS}"
else
enable_backend_mongodb="no"
enable_exporting_mongodb="no"
fi
AC_MSG_RESULT([${enable_backend_mongodb}])
AM_CONDITIONAL([ENABLE_BACKEND_MONGODB], [test "${enable_backend_mongodb}" = "yes"])
AC_MSG_RESULT([${enable_exporting_mongodb}])
AM_CONDITIONAL([ENABLE_EXPORTING_MONGODB], [test "${enable_exporting_mongodb}" = "yes"])
# -----------------------------------------------------------------------------
@ -1523,9 +1523,9 @@ AC_MSG_RESULT([${enable_lto}])
# -----------------------------------------------------------------------------
if test "${enable_backend_kinesis}" = "yes" -o \
if test "${enable_exporting_kinesis}" = "yes" -o \
"${enable_exporting_pubsub}" = "yes" -o \
"${enable_backend_prometheus_remote_write}" = "yes" -o \
"${enable_exporting_prometheus_remote_write}" = "yes" -o \
"${new_cloud_protocol}" = "yes" -o \
"${build_ml}" = "yes"; then
enable_cxx_linker="yes"
@ -1688,14 +1688,6 @@ AC_DEFINE_UNQUOTED(
AC_CONFIG_FILES([
Makefile
netdata.spec
backends/graphite/Makefile
backends/json/Makefile
backends/Makefile
backends/opentsdb/Makefile
backends/prometheus/Makefile
backends/prometheus/remote_write/Makefile
backends/aws_kinesis/Makefile
backends/mongodb/Makefile
collectors/Makefile
collectors/apps.plugin/Makefile
collectors/cgroups.plugin/Makefile

View File

@ -175,11 +175,11 @@ OTHER_OPTIONS+=" --enable-jsonc"
OTHER_OPTIONS+=" --enable-plugin-nfacct"
OTHER_OPTIONS+=" --enable-plugin-freeipmi"
OTHER_OPTIONS+=" --enable-plugin-cups"
OTHER_OPTIONS+=" --enable-backend-prometheus-remote-write"
OTHER_OPTIONS+=" --enable-exporting-prometheus-remote-write"
# TODO: enable these plugins too
#OTHER_OPTIONS+=" --enable-plugin-xenstat"
#OTHER_OPTIONS+=" --enable-backend-kinesis"
#OTHER_OPTIONS+=" --enable-backend-mongodb"
#OTHER_OPTIONS+=" --enable-exporting-kinesis"
#OTHER_OPTIONS+=" --enable-exporting-mongodb"
FOUND_OPTS="NO"
while [ -n "${1}" ]; do

View File

@ -51,9 +51,7 @@
// the registry is actually an API feature
#include "registry/registry.h"
// backends for archiving the metrics
#include "backends/backends.h"
// the new exporting engine for archiving the metrics
// exporting engine for archiving the metrics
#include "exporting/exporting_engine.h"
// the netdata API

View File

@ -19,10 +19,9 @@ This config file **is not needed by default**. Netdata works fine out of the box
settings.
4. `[health]` to [configure](#health-section-options) general settings for [health monitoring](/health/README.md)
5. `[registry]` for the [Netdata registry](/registry/README.md).
6. `[backend]` to set up [streaming and replication](/streaming/README.md) options.
7. `[statsd]` for the general settings of the [stats.d.plugin](/collectors/statsd.plugin/README.md).
8. `[plugin:NAME]` sections for each collector plugin, under the comment [Per plugin configuration](#per-plugin-configuration).
9. `[CHART_NAME]` sections for each chart defined, under the comment [Per chart configuration](#per-chart-configuration).
6. `[statsd]` for the general settings of the [stats.d.plugin](/collectors/statsd.plugin/README.md).
7. `[plugin:NAME]` sections for each collector plugin, under the comment [Per plugin configuration](#per-plugin-configuration).
8. `[CHART_NAME]` sections for each chart defined, under the comment [Per chart configuration](#per-chart-configuration).
The configuration file is a `name = value` dictionary. Netdata will not complain if you set options unknown to it. When you check the running configuration by accessing the URL `/netdata.conf` on your Netdata server, Netdata will add a comment on settings it does not currently use.
@ -129,10 +128,6 @@ monitoring](/health/README.md).
To understand what this section is and how it should be configured, please refer to the [registry documentation](/registry/README.md).
### [backend]
Refer to the [streaming and replication](/streaming/README.md) documentation.
## Per-plugin configuration
The configuration options for plugins appear in sections following the pattern `[plugin:NAME]`.

View File

@ -451,9 +451,6 @@ static void backwards_compatible_config() {
config_move(CONFIG_SECTION_GLOBAL, "web files group",
CONFIG_SECTION_WEB, "web files group");
config_move(CONFIG_SECTION_BACKEND, "opentsdb host tags",
CONFIG_SECTION_BACKEND, "host tags");
}
static void get_netdata_configured_variables() {

View File

@ -85,15 +85,6 @@ const struct netdata_static_thread static_threads_common[] = {
.init_routine = NULL,
.start_routine = statsd_main
},
{
.name = "BACKENDS",
.config_section = NULL,
.config_name = NULL,
.enabled = 1,
.thread = NULL,
.init_routine = NULL,
.start_routine = backends_main
},
{
.name = "EXPORTING",
.config_section = NULL,

View File

@ -1521,7 +1521,7 @@ static RRDHOST *dbengine_rrdhost_find_or_create(char *name)
, netdata_configured_timezone
, netdata_configured_abbrev_timezone
, netdata_configured_utc_offset
, config_get(CONFIG_SECTION_BACKEND, "host tags", "")
, ""
, program_name
, program_version
, default_rrd_update_every

View File

@ -461,23 +461,21 @@ typedef enum rrdset_flags {
// (the master data set should be the one that has the same family and is not detail)
RRDSET_FLAG_DEBUG = 1 << 2, // enables or disables debugging for a chart
RRDSET_FLAG_OBSOLETE = 1 << 3, // this is marked by the collector/module as obsolete
RRDSET_FLAG_EXPORTING_SEND = 1 << 4, // if set, this chart should be sent to Prometheus web API
RRDSET_FLAG_EXPORTING_IGNORE = 1 << 5, // if set, this chart should not be sent to Prometheus web API
RRDSET_FLAG_EXPORTING_SEND = 1 << 4, // if set, this chart should be sent to Prometheus web API and external databases
RRDSET_FLAG_EXPORTING_IGNORE = 1 << 5, // if set, this chart should not be sent to Prometheus web API and external databases
RRDSET_FLAG_UPSTREAM_SEND = 1 << 6, // if set, this chart should be sent upstream (streaming)
RRDSET_FLAG_UPSTREAM_IGNORE = 1 << 7, // if set, this chart should not be sent upstream (streaming)
RRDSET_FLAG_UPSTREAM_EXPOSED = 1 << 8, // if set, we have sent this chart definition to netdata parent (streaming)
RRDSET_FLAG_STORE_FIRST = 1 << 9, // if set, do not eliminate the first collection during interpolation
RRDSET_FLAG_HETEROGENEOUS = 1 << 10, // if set, the chart is not homogeneous (dimensions in it have multiple algorithms, multipliers or dividers)
RRDSET_FLAG_HOMOGENEOUS_CHECK = 1 << 11, // if set, the chart should be checked to determine if the dimensions are homogeneous
RRDSET_FLAG_HIDDEN = 1 << 12, // if set, do not show this chart on the dashboard, but use it for backends
RRDSET_FLAG_HIDDEN = 1 << 12, // if set, do not show this chart on the dashboard, but use it for exporting
RRDSET_FLAG_SYNC_CLOCK = 1 << 13, // if set, microseconds on next data collection will be ignored (the chart will be synced to now)
RRDSET_FLAG_OBSOLETE_DIMENSIONS = 1 << 14, // this is marked by the collector/module when a chart has obsolete dimensions
// No new values have been collected for this chart since agent start or it was marked RRDSET_FLAG_OBSOLETE at
// least rrdset_free_obsolete_time seconds ago.
RRDSET_FLAG_ARCHIVED = 1 << 15,
RRDSET_FLAG_ACLK = 1 << 16,
RRDSET_FLAG_BACKEND_SEND = 1 << 17, // if set, this chart should be sent to backends
RRDSET_FLAG_BACKEND_IGNORE = 1 << 18 // if set, this chart should not be sent to backends
} RRDSET_FLAGS;
#ifdef HAVE_C___ATOMIC
@ -632,8 +630,8 @@ typedef enum rrdhost_flags {
RRDHOST_FLAG_ORPHAN = 1 << 0, // this host is orphan (not receiving data)
RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS = 1 << 1, // delete files of obsolete charts
RRDHOST_FLAG_DELETE_ORPHAN_HOST = 1 << 2, // delete the entire host when orphan
RRDHOST_FLAG_BACKEND_SEND = 1 << 3, // send it to backends
RRDHOST_FLAG_BACKEND_DONT_SEND = 1 << 4, // don't send it to backends
RRDHOST_FLAG_EXPORTING_SEND = 1 << 3, // send it to external databases
RRDHOST_FLAG_EXPORTING_DONT_SEND = 1 << 4, // don't send it to external databases
RRDHOST_FLAG_ARCHIVED = 1 << 5, // The host is archived, no collected charts yet
RRDHOST_FLAG_MULTIHOST = 1 << 6, // Host belongs to localhost/megadb
} RRDHOST_FLAGS;

View File

@ -718,7 +718,7 @@ int rrd_init(char *hostname, struct rrdhost_system_info *system_info) {
, netdata_configured_timezone
, netdata_configured_abbrev_timezone
, netdata_configured_utc_offset
, config_get(CONFIG_SECTION_BACKEND, "host tags", "")
, ""
, program_name
, program_version
, default_rrd_update_every
@ -1233,50 +1233,6 @@ struct label *parse_json_tags(struct label *label_list, const char *tags)
return label_list;
}
static struct label *rrdhost_load_labels_from_tags(void)
{
if (!localhost->tags)
return NULL;
struct label *label_list = NULL;
BACKEND_TYPE type = BACKEND_TYPE_UNKNOWN;
if (config_exists(CONFIG_SECTION_BACKEND, "enabled")) {
if (config_get_boolean(CONFIG_SECTION_BACKEND, "enabled", CONFIG_BOOLEAN_NO) != CONFIG_BOOLEAN_NO) {
const char *type_name = config_get(CONFIG_SECTION_BACKEND, "type", "graphite");
type = backend_select_type(type_name);
}
}
switch (type) {
case BACKEND_TYPE_GRAPHITE:
label_list = parse_simple_tags(
label_list, localhost->tags, '=', ';', DO_NOT_STRIP_QUOTES, DO_NOT_STRIP_QUOTES,
DO_NOT_SKIP_ESCAPED_CHARACTERS);
break;
case BACKEND_TYPE_OPENTSDB_USING_TELNET:
label_list = parse_simple_tags(
label_list, localhost->tags, '=', ' ', DO_NOT_STRIP_QUOTES, DO_NOT_STRIP_QUOTES,
DO_NOT_SKIP_ESCAPED_CHARACTERS);
break;
case BACKEND_TYPE_OPENTSDB_USING_HTTP:
label_list = parse_simple_tags(
label_list, localhost->tags, ':', ',', STRIP_QUOTES, STRIP_QUOTES,
DO_NOT_SKIP_ESCAPED_CHARACTERS);
break;
case BACKEND_TYPE_JSON:
label_list = parse_json_tags(label_list, localhost->tags);
break;
default:
label_list = parse_simple_tags(
label_list, localhost->tags, '=', ',', DO_NOT_STRIP_QUOTES, STRIP_QUOTES,
DO_NOT_SKIP_ESCAPED_CHARACTERS);
break;
}
return label_list;
}
static struct label *rrdhost_load_kubernetes_labels(void)
{
struct label *l=NULL;
@ -1340,10 +1296,8 @@ void reload_host_labels(void)
struct label *from_auto = rrdhost_load_auto_labels();
struct label *from_k8s = rrdhost_load_kubernetes_labels();
struct label *from_config = rrdhost_load_config_labels();
struct label *from_tags = rrdhost_load_labels_from_tags();
struct label *new_labels = merge_label_lists(from_auto, from_k8s);
new_labels = merge_label_lists(new_labels, from_tags);
new_labels = merge_label_lists(new_labels, from_config);
rrdhost_rdlock(localhost);

View File

@ -190,8 +190,6 @@ int rrdset_set_name(RRDSET *st, const char *name) {
rrdset_flag_clear(st, RRDSET_FLAG_EXPORTING_SEND);
rrdset_flag_clear(st, RRDSET_FLAG_EXPORTING_IGNORE);
rrdset_flag_clear(st, RRDSET_FLAG_BACKEND_SEND);
rrdset_flag_clear(st, RRDSET_FLAG_BACKEND_IGNORE);
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_SEND);
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_IGNORE);
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
@ -872,8 +870,6 @@ RRDSET *rrdset_create_custom(
rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
rrdset_flag_clear(st, RRDSET_FLAG_EXPORTING_SEND);
rrdset_flag_clear(st, RRDSET_FLAG_EXPORTING_IGNORE);
rrdset_flag_clear(st, RRDSET_FLAG_BACKEND_SEND);
rrdset_flag_clear(st, RRDSET_FLAG_BACKEND_IGNORE);
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_SEND);
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_IGNORE);
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);

View File

@ -85,6 +85,5 @@ Graphite_](/docs/guides/export/export-netdata-metrics-graphite.md).
### Related reference documentation
- [Exporting engine reference](/exporting/README.md)
- [Backends reference (deprecated)](/backends/README.md)

View File

@ -86,7 +86,7 @@ They capture the following:
- What virtualization layer the system runs on top of, if any
- Whether the system is a streaming parent or child
If you want to organize your systems without manually creating host tags, try the automatic labels in some of the
If you want to organize your systems without manually creating host labels, try the automatic labels in some of the
features below.
## Host labels in streaming

View File

@ -20,12 +20,6 @@ the same time. You can have different update intervals and filters configured fo
When you enable the exporting engine and a connector, the Netdata Agent exports metrics _beginning from the time you
restart its process_, not the entire [database of long-term metrics](/docs/store/change-metrics-storage.md).
The exporting engine has its own configuration file `exporting.conf`. The configuration is almost similar to the
deprecated [backends](/backends/README.md#configuration) system. The most important difference is that type of a
connector should be specified in a section name before a colon and an instance name after the colon. Also, you can't use
`host tags` anymore. Set your labels using the [`[host labels]`](/docs/guides/using-host-labels.md) section in
`netdata.conf`.
Since Netdata collects thousands of metrics per server per second, which would easily congest any database server when
several Netdata servers are sending data to it, Netdata allows sending metrics at a lower frequency, by resampling them.
@ -271,12 +265,6 @@ Configure individual connectors and override any global settings with the follow
- `send automatic labels = yes | no` controls if automatically created labels, like `_os_name` or `_architecture`
should be sent to the external database
> Starting from Netdata v1.20 the host tags (defined in the `[backend]` section of `netdata.conf`) are parsed in
> accordance with a configured backend type and stored as host labels so that they can be reused in API responses and
> exporting connectors. The parsing is supported for graphite, json, opentsdb, and prometheus (default) backend types.
> 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

View File

@ -20,7 +20,7 @@ What's TimescaleDB? Here's how their team defines the project on their [GitHub p
To get started archiving metrics to TimescaleDB right away, check out Mahlon's [`netdata-timescale-relay`
repository](https://github.com/mahlonsmith/netdata-timescale-relay) on GitHub. Please be aware that backends subsystem
is deprecated and Netdata configuration should be moved to the new `exporting conf` configuration file. Use
was removed and Netdata configuration should be moved to the new `exporting.conf` configuration file. Use
```conf
[json:my_instance]
```

View File

@ -151,7 +151,7 @@ void aws_kinesis_connector_worker(void *instance_p)
char error_message[ERROR_LINE_MAX + 1] = "";
debug(
D_BACKEND,
D_EXPORTING,
"EXPORTING: kinesis_put_record(): dest = %s, id = %s, key = %s, stream = %s, partition_key = %s, \
buffer = %zu, record = %zu",
instance->config.destination,
@ -175,7 +175,7 @@ void aws_kinesis_connector_worker(void *instance_p)
// oops! we couldn't send (all or some of the) data
error("EXPORTING: %s", error_message);
error(
"EXPORTING: failed to write data to database backend '%s'. Willing to write %zu bytes, wrote %zu bytes.",
"EXPORTING: failed to write data to external database '%s'. Willing to write %zu bytes, wrote %zu bytes.",
instance->config.destination, sent_bytes, sent_bytes - lost_bytes);
stats->transmission_failures++;

View File

@ -16,19 +16,19 @@ int rrdhost_is_exportable(struct instance *instance, RRDHOST *host)
RRDHOST_FLAGS *flags = &host->exporting_flags[instance->index];
if (unlikely((*flags & (RRDHOST_FLAG_BACKEND_SEND | RRDHOST_FLAG_BACKEND_DONT_SEND)) == 0)) {
if (unlikely((*flags & (RRDHOST_FLAG_EXPORTING_SEND | RRDHOST_FLAG_EXPORTING_DONT_SEND)) == 0)) {
char *host_name = (host == localhost) ? "localhost" : host->hostname;
if (!instance->config.hosts_pattern || simple_pattern_matches(instance->config.hosts_pattern, host_name)) {
*flags |= RRDHOST_FLAG_BACKEND_SEND;
*flags |= RRDHOST_FLAG_EXPORTING_SEND;
info("enabled exporting of host '%s' for instance '%s'", host_name, instance->config.name);
} else {
*flags |= RRDHOST_FLAG_BACKEND_DONT_SEND;
*flags |= RRDHOST_FLAG_EXPORTING_DONT_SEND;
info("disabled exporting of host '%s' for instance '%s'", host_name, instance->config.name);
}
}
if (likely(*flags & RRDHOST_FLAG_BACKEND_SEND))
if (likely(*flags & RRDHOST_FLAG_EXPORTING_SEND))
return 1;
else
return 0;
@ -65,18 +65,18 @@ int rrdset_is_exportable(struct instance *instance, RRDSET *st)
*flags |= RRDSET_FLAG_EXPORTING_SEND;
else {
*flags |= RRDSET_FLAG_EXPORTING_IGNORE;
debug(D_BACKEND, "BACKEND: not sending chart '%s' of host '%s', because it is disabled for backends.", st->id, host->hostname);
debug(D_EXPORTING, "EXPORTING: not sending chart '%s' of host '%s', because it is disabled for exporting.", st->id, host->hostname);
return 0;
}
}
if(unlikely(!rrdset_is_available_for_exporting_and_alarms(st))) {
debug(D_BACKEND, "BACKEND: not sending chart '%s' of host '%s', because it is not available for backends.", st->id, host->hostname);
debug(D_EXPORTING, "EXPORTING: not sending chart '%s' of host '%s', because it is not available for exporting.", st->id, host->hostname);
return 0;
}
if(unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE && !(EXPORTING_OPTIONS_DATA_SOURCE(instance->config.options) == EXPORTING_SOURCE_DATA_AS_COLLECTED))) {
debug(D_BACKEND, "BACKEND: not sending chart '%s' of host '%s' because its memory mode is '%s' and the backend requires database access.", st->id, host->hostname, rrd_memory_mode_name(host->rrd_memory_mode));
debug(D_EXPORTING, "EXPORTING: not sending chart '%s' of host '%s' because its memory mode is '%s' and the exporting engine requires database access.", st->id, host->hostname, rrd_memory_mode_name(host->rrd_memory_mode));
return 0;
}

View File

@ -34,6 +34,9 @@ typedef enum exporting_options {
(EXPORTING_SOURCE_DATA_AS_COLLECTED | EXPORTING_SOURCE_DATA_AVERAGE | EXPORTING_SOURCE_DATA_SUM)
#define EXPORTING_OPTIONS_DATA_SOURCE(exporting_options) (exporting_options & EXPORTING_OPTIONS_SOURCE_BITS)
extern EXPORTING_OPTIONS global_exporting_options;
extern const char *global_exporting_prefix;
#define sending_labels_configured(instance) \
(instance->config.options & (EXPORTING_OPTION_SEND_CONFIGURED_LABELS | EXPORTING_OPTION_SEND_AUTOMATIC_LABELS))
@ -51,11 +54,11 @@ typedef enum exporting_connector_types {
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_PROMETHEUS_REMOTE_WRITE, // Send data using Prometheus remote write protocol
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
EXPORTING_CONNECTOR_TYPE_NUM // Number of backend types
EXPORTING_CONNECTOR_TYPE_NUM // Number of exporting connector types
} EXPORTING_CONNECTOR_TYPE;
struct engine;
@ -265,6 +268,8 @@ size_t exporting_name_copy(char *dst, const char *src, size_t max_len);
int rrdhost_is_exportable(struct instance *instance, RRDHOST *host);
int rrdset_is_exportable(struct instance *instance, RRDSET *st);
extern EXPORTING_OPTIONS exporting_parse_data_source(const char *source, EXPORTING_OPTIONS exporting_options);
calculated_number exporting_calculate_value_from_stored_data(
struct instance *instance,
RRDDIM *rd,

View File

@ -327,7 +327,7 @@ void mongodb_connector_worker(void *instance_p)
}
debug(
D_BACKEND,
D_EXPORTING,
"EXPORTING: mongodb_insert(): destination = %s, database = %s, collection = %s, data size = %zu",
instance->config.destination,
connector_specific_config->database,

View File

@ -2,17 +2,17 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# This is a simple backend database proxy, written in BASH, using the nc command.
# This is a simple exporting proxy, written in BASH, using the nc command.
# Run the script without any parameters for help.
MODE="${1}"
MY_PORT="${2}"
BACKEND_HOST="${3}"
BACKEND_PORT="${4}"
FILE="${NETDATA_NC_BACKEND_DIR-/tmp}/netdata-nc-backend-${MY_PORT}"
EXPORTING_HOST="${3}"
EXPORTING_PORT="${4}"
FILE="${NETDATA_NC_EXPORTING_DIR-/tmp}/netdata-nc-exporting-${MY_PORT}"
log() {
logger --stderr --id=$$ --tag "netdata-nc-backend" "${*}"
logger --stderr --id=$$ --tag "netdata-nc-exporting" "${*}"
}
mync() {
@ -28,7 +28,7 @@ mync() {
}
listen_save_replay_forever() {
local file="${1}" port="${2}" real_backend_host="${3}" real_backend_port="${4}" ret delay=1 started ended
local file="${1}" port="${2}" real_exporting_host="${3}" real_exporting_port="${4}" ret delay=1 started ended
while true
do
@ -40,23 +40,23 @@ listen_save_replay_forever() {
if [ -s "${file}" ]
then
if [ -n "${real_backend_host}" ] && [ -n "${real_backend_port}" ]
if [ -n "${real_exporting_host}" ] && [ -n "${real_exporting_port}" ]
then
log "Attempting to send the metrics to the real backend at ${real_backend_host}:${real_backend_port}"
log "Attempting to send the metrics to the real external database at ${real_exporting_host}:${real_exporting_port}"
mync "${real_backend_host}" "${real_backend_port}" <"${file}"
mync "${real_exporting_host}" "${real_exporting_port}" <"${file}"
ret=$?
if [ ${ret} -eq 0 ]
then
log "Successfully sent the metrics to ${real_backend_host}:${real_backend_port}"
log "Successfully sent the metrics to ${real_exporting_host}:${real_exporting_port}"
mv "${file}" "${file}.old"
touch "${file}"
else
log "Failed to send the metrics to ${real_backend_host}:${real_backend_port} (nc returned ${ret}) - appending more data to ${file}"
log "Failed to send the metrics to ${real_exporting_host}:${real_exporting_port} (nc returned ${ret}) - appending more data to ${file}"
fi
else
log "No backend configured - appending more data to ${file}"
log "No external database configured - appending more data to ${file}"
fi
fi
@ -92,7 +92,7 @@ if [ "${MODE}" = "start" ]
# save our PID to the lock file
echo "$$" >"${FILE}.lock"
listen_save_replay_forever "${FILE}" "${MY_PORT}" "${BACKEND_HOST}" "${BACKEND_PORT}"
listen_save_replay_forever "${FILE}" "${MY_PORT}" "${EXPORTING_HOST}" "${EXPORTING_PORT}"
ret=$?
log "listener exited."
@ -131,20 +131,20 @@ else
cat <<EOF
Usage:
"${0}" start|stop PORT [BACKEND_HOST BACKEND_PORT]
"${0}" start|stop PORT [EXPORTING_HOST EXPORTING_PORT]
PORT The port this script will listen
(configure netdata to use this as a second backend)
(configure netdata to use this as an external database)
BACKEND_HOST The real backend host
BACKEND_PORT The real backend port
EXPORTING_HOST The real host for the external database
EXPORTING_PORT The real port for the external database
This script can act as fallback backend for netdata.
This script can act as fallback database for netdata.
It will receive metrics from netdata, save them to
${FILE}
and once netdata reconnects to the real-backend, this script
will push all metrics collected to the real-backend too and
wait for a failure to happen again.
and once netdata reconnects to the real external database,
this script will push all metrics collected to the real
external database too and wait for a failure to happen again.
Only one netdata can connect to this script at a time.
If you need fallback for multiple netdata, run this script
@ -152,7 +152,7 @@ Usage:
You can run me in the background with this:
screen -d -m "${0}" start PORT [BACKEND_HOST BACKEND_PORT]
screen -d -m "${0}" start PORT [EXPORTING_HOST EXPORTING_PORT]
EOF
exit 1
fi

View File

@ -109,7 +109,7 @@ calculated_number exporting_calculate_value_from_stored_data(
if (unlikely(before < first_t || after > last_t)) {
// the chart has not been updated in the wanted timeframe
debug(
D_BACKEND,
D_EXPORTING,
"EXPORTING: %s.%s.%s: aligned timeframe %lu to %lu is outside the chart's database range %lu to %lu",
host->hostname,
st->id,
@ -143,7 +143,7 @@ calculated_number exporting_calculate_value_from_stored_data(
rd->state->query_ops.finalize(&handle);
if (unlikely(!counter)) {
debug(
D_BACKEND,
D_EXPORTING,
"EXPORTING: %s.%s.%s: no values stored in database for range %lu to %lu",
host->hostname,
st->id,

View File

@ -35,7 +35,7 @@ inline int can_send_rrdset(struct instance *instance, RRDSET *st)
else {
rrdset_flag_set(st, RRDSET_FLAG_EXPORTING_IGNORE);
debug(
D_BACKEND,
D_EXPORTING,
"EXPORTING: not sending chart '%s' of host '%s', because it is disabled for exporting.",
st->id,
host->hostname);
@ -45,7 +45,7 @@ inline int can_send_rrdset(struct instance *instance, RRDSET *st)
if (unlikely(!rrdset_is_available_for_exporting_and_alarms(st))) {
debug(
D_BACKEND,
D_EXPORTING,
"EXPORTING: not sending chart '%s' of host '%s', because it is not available for exporting.",
st->id,
host->hostname);
@ -56,7 +56,7 @@ inline int can_send_rrdset(struct instance *instance, RRDSET *st)
st->rrd_memory_mode == RRD_MEMORY_MODE_NONE &&
!(EXPORTING_OPTIONS_DATA_SOURCE(instance->config.options) == EXPORTING_SOURCE_DATA_AS_COLLECTED))) {
debug(
D_BACKEND,
D_EXPORTING,
"EXPORTING: not sending chart '%s' of host '%s' because its memory mode is '%s' and the exporting connector requires database access.",
st->id,
host->hostname,

View File

@ -236,7 +236,7 @@ int format_dimension_prometheus_remote_write(struct instance *instance, RRDDIM *
if (unlikely(rd->last_collected_time.tv_sec < instance->after)) {
debug(
D_BACKEND,
D_EXPORTING,
"EXPORTING: 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, rd->rrdset->id,

View File

@ -141,7 +141,7 @@ void pubsub_connector_worker(void *instance_p)
}
debug(
D_BACKEND, "EXPORTING: pubsub_publish(): project = %s, topic = %s, buffer = %zu",
D_EXPORTING, "EXPORTING: pubsub_publish(): project = %s, topic = %s, buffer = %zu",
connector_specific_config->project_id, connector_specific_config->topic_id, buffer_len);
if (pubsub_publish((void *)connector_specific_data, error_message, stats->buffered_metrics, buffer_len)) {

View File

@ -2,6 +2,9 @@
#include "exporting_engine.h"
EXPORTING_OPTIONS global_exporting_options = EXPORTING_SOURCE_DATA_AVERAGE | EXPORTING_OPTION_SEND_NAMES;
const char *global_exporting_prefix = "netdata";
struct config exporting_config = { .first_section = NULL,
.last_section = NULL,
.mutex = NETDATA_MUTEX_INITIALIZER,
@ -160,7 +163,7 @@ EXPORTING_CONNECTOR_TYPE exporting_select_type(const char *type)
return EXPORTING_CONNECTOR_TYPE_UNKNOWN;
}
EXPORTING_OPTIONS exporting_parse_data_source(const char *data_source, EXPORTING_OPTIONS exporting_options)
inline EXPORTING_OPTIONS exporting_parse_data_source(const char *data_source, EXPORTING_OPTIONS exporting_options)
{
if (!strcmp(data_source, "raw") || !strcmp(data_source, "as collected") || !strcmp(data_source, "as-collected") ||
!strcmp(data_source, "as_collected") || !strcmp(data_source, "ascollected")) {
@ -194,7 +197,7 @@ struct engine *read_exporting_config()
static struct engine *engine = NULL;
struct connector_instance_list {
struct connector_instance local_ci;
EXPORTING_CONNECTOR_TYPE backend_type;
EXPORTING_CONNECTOR_TYPE exporting_type;
struct connector_instance_list *next;
};
@ -238,21 +241,14 @@ struct engine *read_exporting_config()
prometheus_exporter_instance->config.update_every =
prometheus_config_get_number(EXPORTING_UPDATE_EVERY_OPTION_NAME, EXPORTING_UPDATE_EVERY_DEFAULT);
// wait for backend subsystem to be initialized
for (int retries = 0; !global_backend_source && retries < 1000; retries++)
sleep_usec(10000);
prometheus_exporter_instance->config.options |= global_exporting_options & EXPORTING_OPTIONS_SOURCE_BITS;
if (!global_backend_source)
global_backend_source = "average";
prometheus_exporter_instance->config.options |= global_backend_options & EXPORTING_OPTIONS_SOURCE_BITS;
char *data_source = prometheus_config_get("data source", global_backend_source);
char *data_source = prometheus_config_get("data source", "average");
prometheus_exporter_instance->config.options =
exporting_parse_data_source(data_source, prometheus_exporter_instance->config.options);
if (prometheus_config_get_boolean(
"send names instead of ids", global_backend_options & EXPORTING_OPTION_SEND_NAMES))
"send names instead of ids", global_exporting_options & EXPORTING_OPTION_SEND_NAMES))
prometheus_exporter_instance->config.options |= EXPORTING_OPTION_SEND_NAMES;
else
prometheus_exporter_instance->config.options &= ~EXPORTING_OPTION_SEND_NAMES;
@ -268,18 +264,17 @@ struct engine *read_exporting_config()
prometheus_exporter_instance->config.options &= ~EXPORTING_OPTION_SEND_AUTOMATIC_LABELS;
prometheus_exporter_instance->config.charts_pattern = simple_pattern_create(
prometheus_config_get("send charts matching", global_backend_send_charts_matching),
prometheus_config_get("send charts matching", "*"),
NULL,
SIMPLE_PATTERN_EXACT);
prometheus_exporter_instance->config.hosts_pattern = simple_pattern_create(
prometheus_config_get("send hosts matching", "localhost *"), NULL, SIMPLE_PATTERN_EXACT);
prometheus_exporter_instance->config.prefix = prometheus_config_get("prefix", global_backend_prefix);
prometheus_exporter_instance->config.prefix = prometheus_config_get("prefix", global_exporting_prefix);
prometheus_exporter_instance->config.initialized = 1;
}
// TODO: change BACKEND to EXPORTING
while (get_connector_instance(&local_ci)) {
info("Processing connector instance (%s)", local_ci.instance_name);
@ -290,7 +285,7 @@ struct engine *read_exporting_config()
tmp_ci_list = (struct connector_instance_list *)callocz(1, sizeof(struct connector_instance_list));
memcpy(&tmp_ci_list->local_ci, &local_ci, sizeof(local_ci));
tmp_ci_list->backend_type = exporting_select_type(local_ci.connector_name);
tmp_ci_list->exporting_type = exporting_select_type(local_ci.connector_name);
tmp_ci_list->next = tmp_ci_list_prev;
tmp_ci_list_prev = tmp_ci_list;
instances_to_activate++;
@ -320,34 +315,34 @@ struct engine *read_exporting_config()
info("Instance %s on %s", tmp_ci_list->local_ci.instance_name, tmp_ci_list->local_ci.connector_name);
if (tmp_ci_list->backend_type == EXPORTING_CONNECTOR_TYPE_UNKNOWN) {
if (tmp_ci_list->exporting_type == EXPORTING_CONNECTOR_TYPE_UNKNOWN) {
error("Unknown exporting connector type");
goto next_connector_instance;
}
#ifndef ENABLE_PROMETHEUS_REMOTE_WRITE
if (tmp_ci_list->backend_type == EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE) {
if (tmp_ci_list->exporting_type == EXPORTING_CONNECTOR_TYPE_PROMETHEUS_REMOTE_WRITE) {
error("Prometheus Remote Write support isn't compiled");
goto next_connector_instance;
}
#endif
#ifndef HAVE_KINESIS
if (tmp_ci_list->backend_type == EXPORTING_CONNECTOR_TYPE_KINESIS) {
if (tmp_ci_list->exporting_type == EXPORTING_CONNECTOR_TYPE_KINESIS) {
error("AWS Kinesis support isn't compiled");
goto next_connector_instance;
}
#endif
#ifndef ENABLE_EXPORTING_PUBSUB
if (tmp_ci_list->backend_type == EXPORTING_CONNECTOR_TYPE_PUBSUB) {
if (tmp_ci_list->exporting_type == EXPORTING_CONNECTOR_TYPE_PUBSUB) {
error("Google Cloud Pub/Sub support isn't compiled");
goto next_connector_instance;
}
#endif
#ifndef HAVE_MONGOC
if (tmp_ci_list->backend_type == EXPORTING_CONNECTOR_TYPE_MONGODB) {
if (tmp_ci_list->exporting_type == EXPORTING_CONNECTOR_TYPE_MONGODB) {
error("MongoDB support isn't compiled");
goto next_connector_instance;
}
@ -358,7 +353,7 @@ struct engine *read_exporting_config()
engine->instance_root = tmp_instance;
tmp_instance->engine = engine;
tmp_instance->config.type = tmp_ci_list->backend_type;
tmp_instance->config.type = tmp_ci_list->exporting_type;
instance_name = tmp_ci_list->local_ci.instance_name;

View File

@ -41,7 +41,7 @@ int exporting_discard_response(BUFFER *buffer, struct instance *instance) {
*d = '\0';
debug(
D_BACKEND,
D_EXPORTING,
"EXPORTING: received %zu bytes from %s connector instance. Ignoring them. Sample: '%s'",
buffer_strlen(buffer),
instance->config.name,

View File

@ -14,11 +14,6 @@ char *netdata_configured_hostname = "test_global_host";
char log_line[MAX_LOG_LINE + 1];
BACKEND_OPTIONS global_backend_options = 0;
const char *global_backend_source = "average";
const char *global_backend_prefix = "netdata";
const char *global_backend_send_charts_matching = "*";
void init_connectors_in_tests(struct engine *engine)
{
expect_function_call(__wrap_now_realtime_sec);
@ -235,7 +230,7 @@ static void test_rrdhost_is_exportable(void **state)
assert_string_equal(log_line, "enabled exporting of host 'localhost' for instance 'instance_name'");
assert_ptr_not_equal(localhost->exporting_flags, NULL);
assert_int_equal(localhost->exporting_flags[0], RRDHOST_FLAG_BACKEND_SEND);
assert_int_equal(localhost->exporting_flags[0], RRDHOST_FLAG_EXPORTING_SEND);
}
static void test_false_rrdhost_is_exportable(void **state)
@ -255,7 +250,7 @@ static void test_false_rrdhost_is_exportable(void **state)
assert_string_equal(log_line, "disabled exporting of host 'localhost' for instance 'instance_name'");
assert_ptr_not_equal(localhost->exporting_flags, NULL);
assert_int_equal(localhost->exporting_flags[0], RRDHOST_FLAG_BACKEND_DONT_SEND);
assert_int_equal(localhost->exporting_flags[0], RRDHOST_FLAG_EXPORTING_DONT_SEND);
}
static void test_rrdset_is_exportable(void **state)

View File

@ -27,7 +27,6 @@ dist_healthconfig_DATA = \
health.d/adaptec_raid.conf \
health.d/anomalies.conf \
health.d/apcupsd.conf \
health.d/backend.conf \
health.d/bcache.conf \
health.d/beanstalkd.conf \
health.d/bind_rndc.conf \

View File

@ -1,42 +0,0 @@
# Alert that backends subsystem will be disabled soon
alarm: backend_metrics_eol
on: netdata.backend_metrics
class: Errors
type: Netdata
component: Exporting engine
units: boolean
calc: $now - $last_collected_t
every: 1m
warn: $this > 0
delay: down 5m multiplier 1.5 max 1h
info: the backends subsystem is deprecated and will be removed soon. Migrate your configuration to exporting.conf.
to: sysadmin
# make sure we are sending data to backend
alarm: backend_last_buffering
on: netdata.backend_metrics
class: Latency
type: Netdata
component: Exporting engine
calc: $now - $last_collected_t
units: seconds ago
every: 10s
warn: $this > (($status >= $WARNING) ? ($update_every) : ( 5 * $update_every))
crit: $this > (($status == $CRITICAL) ? ($update_every) : (60 * $update_every))
delay: down 5m multiplier 1.5 max 1h
info: number of seconds since the last successful buffering of backend data
to: dba
alarm: backend_metrics_sent
on: netdata.backend_metrics
class: Workload
type: Netdata
component: Exporting engine
units: %
calc: abs($sent) * 100 / abs($buffered)
every: 10s
warn: $this != 100
delay: down 5m multiplier 1.5 max 1h
info: percentage of metrics sent to the backend server
to: dba

View File

@ -13,5 +13,4 @@ Also, they are super fast in printing and appending data to the string and its `
is just a lookup (it does not traverse the string).
Netdata uses `BUFFER`s for preparing web responses and buffering data to be sent upstream or
to backend databases.
to external databases.

View File

@ -591,7 +591,7 @@ int appconfig_load(struct config *root, char *filename, int overwrite_used, cons
int line = 0;
struct section *co = NULL;
int is_exporter_config = 0;
int _backends = 0; // number of backend sections we have
int _connectors = 0; // number of exporting connector sections we have
char working_instance[CONFIG_MAX_NAME + 1];
char working_connector[CONFIG_MAX_NAME + 1];
struct section *working_connector_section = NULL;
@ -641,8 +641,8 @@ int appconfig_load(struct config *root, char *filename, int overwrite_used, cons
strncpy(working_connector, s, CONFIG_MAX_NAME);
s = s + rc + 1;
if (unlikely(!(*s))) {
_backends++;
sprintf(buffer, "instance_%d", _backends);
_connectors++;
sprintf(buffer, "instance_%d", _connectors);
s = buffer;
}
strncpy(working_instance, s, CONFIG_MAX_NAME);
@ -793,7 +793,6 @@ void appconfig_generate(struct config *root, BUFFER *wb, int only_changed)
|| !strcmp(co->name, CONFIG_SECTION_CLOUD)
|| !strcmp(co->name, CONFIG_SECTION_REGISTRY)
|| !strcmp(co->name, CONFIG_SECTION_HEALTH)
|| !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)

View File

@ -89,7 +89,6 @@
#define CONFIG_SECTION_CLOUD "cloud"
#define CONFIG_SECTION_REGISTRY "registry"
#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"

View File

@ -36,7 +36,7 @@ extern "C" {
#define D_CONNECT_TO 0x0000000001000000
#define D_RRDHOST 0x0000000002000000
#define D_LOCKS 0x0000000004000000
#define D_BACKEND 0x0000000008000000
#define D_EXPORTING 0x0000000008000000
#define D_STATSD 0x0000000010000000
#define D_POLLFD 0x0000000020000000
#define D_STREAM 0x0000000040000000

View File

@ -245,14 +245,14 @@ USAGE: ${PROGRAM} [options]
--disable-plugin-nfacct Explicitly disable the nfacct plugin.
--enable-plugin-xenstat Enable the xenstat plugin. Default: enable it when libxenstat and libyajl are available.
--disable-plugin-xenstat Explicitly disable the xenstat plugin.
--enable-backend-kinesis Enable AWS Kinesis backend. Default: enable it when libaws_cpp_sdk_kinesis and its dependencies
are available.
--disable-backend-kinesis Explicitly disable AWS Kinesis backend.
--enable-backend-prometheus-remote-write Enable Prometheus remote write backend. Default: enable it when libprotobuf and
libsnappy are available.
--disable-backend-prometheus-remote-write Explicitly disable Prometheus remote write backend.
--enable-backend-mongodb Enable MongoDB backend. Default: enable it when libmongoc is available.
--disable-backend-mongodb Explicitly disable MongoDB backend.
--enable-exporting-kinesis Enable AWS Kinesis exporting connector. Default: enable it when libaws_cpp_sdk_kinesis
and its dependencies are available.
--disable-exporting-kinesis Explicitly disable AWS Kinesis exporting connector.
--enable-exporting-prometheus-remote-write Enable Prometheus remote write exporting connector. Default: enable it
when libprotobuf and libsnappy are available.
--disable-exporting-prometheus-remote-write Explicitly disable Prometheus remote write exporting connector.
--enable-exporting-mongodb Enable MongoDB exporting connector. Default: enable it when libmongoc is available.
--disable-exporting-mongodb Explicitly disable MongoDB exporting connector.
--enable-exporting-pubsub Enable Google Cloud PubSub exporting connector. Default: enable it when
libgoogle_cloud_cpp_pubsub_protos and its dependencies are available.
--disable-exporting-pubsub Explicitly disable Google Cloud PubSub exporting connector.
@ -345,15 +345,20 @@ while [ -n "${1}" ]; do
"--disable-plugin-nfacct") NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--disable-plugin-nfacct)}" | sed 's/$/ --disable-plugin-nfacct/g')" ;;
"--enable-plugin-xenstat") NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--enable-plugin-xenstat)}" | sed 's/$/ --enable-plugin-xenstat/g')" ;;
"--disable-plugin-xenstat") NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--disable-plugin-xenstat)}" | sed 's/$/ --disable-plugin-xenstat/g')" ;;
"--enable-backend-kinesis") NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--enable-backend-kinesis)}" | sed 's/$/ --enable-backend-kinesis/g')" ;;
"--disable-backend-kinesis") NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--disable-backend-kinesis)}" | sed 's/$/ --disable-backend-kinesis/g')" ;;
"--enable-backend-prometheus-remote-write") NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--enable-backend-prometheus-remote-write)}" | sed 's/$/ --enable-backend-prometheus-remote-write/g')" ;;
"--disable-backend-prometheus-remote-write")
NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--disable-backend-prometheus-remote-write)}" | sed 's/$/ --disable-backend-prometheus-remote-write/g')"
"--enable-exporting-kinesis" | "--enable-backend-kinesis")
NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--enable-exporting-kinesis)}" | sed 's/$/ --enable-exporting-kinesis/g')" ;;
"--disable-exporting-kinesis" | "--disable-backend-kinesis")
NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--disable-exporting-kinesis)}" | sed 's/$/ --disable-exporting-kinesis/g')" ;;
"--enable-exporting-prometheus-remote-write" | "--enable-backend-prometheus-remote-write")
NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--enable-exporting-prometheus-remote-write)}" | sed 's/$/ --enable-exporting-prometheus-remote-write/g')" ;;
"--disable-exporting-prometheus-remote-write" | "--disable-backend-prometheus-remote-write")
NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--disable-exporting-prometheus-remote-write)}" | sed 's/$/ --disable-exporting-prometheus-remote-write/g')"
NETDATA_DISABLE_PROMETHEUS=1
;;
"--enable-backend-mongodb") NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--enable-backend-mongodb)}" | sed 's/$/ --enable-backend-mongodb/g')" ;;
"--disable-backend-mongodb") NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--disable-backend-mongodb)}" | sed 's/$/ --disable-backend-mongodb/g')" ;;
"--enable-exporting-mongodb" | "--enable-backend-mongodb")
NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--enable-exporting-mongodb)}" | sed 's/$/ --enable-exporting-mongodb/g')" ;;
"--disable-exporting-mongodb" | "--disable-backend-mongodb")
NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--disable-exporting-mongodb)}" | sed 's/$/ --disable-exporting-mongodb/g')" ;;
"--enable-exporting-pubsub") NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--enable-exporting-pubsub)}" | sed 's/$/ --enable-exporting-pubsub/g')" ;;
"--disable-exporting-pubsub") NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--disable-exporting-pubsub)}" | sed 's/$/ --disable-exporting-pubsub/g')" ;;
"--enable-lto") NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--enable-lto)}" | sed 's/$/ --enable-lto/g')" ;;

View File

@ -93,12 +93,11 @@ The `netdata-updater.sh` script will update your Agent.
| `--disable-plugin-nfacct` | Disable nfacct plugin. Default: enable it when libmnl and libnetfilter_acct are available|
| `--enable-plugin-xenstat` | Enable the xenstat plugin. Default: enable it when libxenstat and libyajl are available|
| `--disable-plugin-xenstat` | Disable the xenstat plugin|
| `--enable-backend-kinesis` | Enable AWS Kinesis backend. Default: enable it when libaws_cpp_sdk_kinesis and libraries (it depends on are available)|
| `--disable-backend-kinesis` | Disable AWS Kinesis backend. Default: enable it when libaws_cpp_sdk_kinesis and libraries (it depends on are available)|
| `--enable-backend-prometheus-remote-write` | Enable Prometheus remote write backend. Default: enable it when libprotobuf and libsnappy are available|
| `--disable-backend-prometheus-remote-write` | Disable Prometheus remote write backend. Default: enable it when libprotobuf and libsnappy are available|
| `--enable-backend-mongodb` | Enable MongoDB backend. Default: enable it when libmongoc is available|
| `--disable-backend-mongodb` | Disable MongoDB backend|
| `--disable-exporting-kinesis` | Disable AWS Kinesis exporting connector. Default: enable it when libaws_cpp_sdk_kinesis and libraries (it depends on are available)|
| `--enable-exporting-prometheus-remote-write` | Enable Prometheus remote write exporting connector. Default: enable it when libprotobuf and libsnappy are available|
| `--disable-exporting-prometheus-remote-write` | Disable Prometheus remote write exporting connector. Default: enable it when libprotobuf and libsnappy are available|
| `--enable-exporting-mongodb` | Enable MongoDB exporting connector. Default: enable it when libmongoc is available|
| `--disable-exporting-mongodb` | Disable MongoDB exporting connector|
| `--enable-lto` | Enable Link-Time-Optimization. Default: enabled|
| `--disable-lto` | Disable Link-Time-Optimization. Default: enabled|
| `--disable-x86-sse` | Disable SSE instructions. By default SSE optimizations are enabled|

View File

@ -67,18 +67,18 @@ Alerts for the child can be triggered by any of the involved hosts that maintain
You can daisy-chain any number of Netdata, each with or without a database and
with or without alerts for the child metrics.
### Mix and match with backends
### Mix and match with exporting engine
All nodes that maintain a database can also send their data to a backend database.
All nodes that maintain a database can also send their data to an external database.
This allows quite complex setups.
Example:
1. Netdata nodes `A` and `B` do not maintain a database and stream metrics to Netdata node `C`(live streaming functionality).
2. Netdata node `C` maintains a database for `A`, `B`, `C` and archives all metrics to `graphite` with 10 second detail (backends functionality).
2. Netdata node `C` maintains a database for `A`, `B`, `C` and archives all metrics to `graphite` with 10 second detail (exporting functionality).
3. Netdata node `C` also streams data for `A`, `B`, `C` to Netdata `D`, which also collects data from `E`, `F` and `G` from another DMZ (live streaming functionality).
4. Netdata node `D` is just a proxy, without a database, that streams all data to a remote site at Netdata `H`.
5. Netdata node `H` maintains a database for `A`, `B`, `C`, `D`, `E`, `F`, `G`, `H` and sends all data to `opentsdb` with 5 seconds detail (backends functionality)
5. Netdata node `H` maintains a database for `A`, `B`, `C`, `D`, `E`, `F`, `G`, `H` and sends all data to `opentsdb` with 5 seconds detail (exporting functionality)
6. Alerts are triggered by `H` for all hosts.
7. Users can use all Netdata nodes that maintain a database to view metrics (i.e. at `H` all hosts can be viewed).
@ -107,15 +107,7 @@ This also disables the registry (there cannot be a registry without an API).
requests from its child nodes. 0 sets no limit, 1 means maximum once every second. If this is set, you may see error log
entries "... too busy to accept new streaming request. Will be allowed in X secs".
```
[backend]
enabled = yes | no
type = graphite | opentsdb
destination = IP:PORT ...
update every = 10
```
`[backend]` configures data archiving to a backend (it archives all databases maintained on
You can [use](docs/agent/exporting#configuration) the exporting engine to configure data archiving to an external database (it archives all databases maintained on
this host).
### Streaming configuration
@ -156,7 +148,7 @@ a proxy).
```
This is an overview of how these options can be combined:
| target|memory<br/>mode|web<br/>mode|stream<br/>enabled|backend|alarms|dashboard|
| target|memory<br/>mode|web<br/>mode|stream<br/>enabled|exporting|alarms|dashboard|
|------|:-------------:|:----------:|:----------------:|:-----:|:----:|:-------:|
| headless collector|`none`|`none`|`yes`|only for `data source = as collected`|not possible|no|
| headless proxy|`none`|not `none`|`yes`|only for `data source = as collected`|not possible|no|

View File

@ -6,14 +6,14 @@ validate_metrics() {
curl -sS "http://localhost:19999/api/v1/allmetrics?format=prometheus&prefix=nd&timestamps=no${params}" |
grep -E 'nd_system_|nd_cpu_|nd_system_|nd_net_|nd_disk_|nd_ip_|nd_ipv4_|nd_ipv6_|nd_mem_|nd_netdata_|nd_apps_|nd_services_' |
sed -ne 's/{.*//p' | sort | uniq > tests/backends/new-${fname}
diff tests/backends/${fname} tests/backends/new-${fname}
rm tests/backends/new-${fname}
sed -ne 's/{.*//p' | sort | uniq > tests/exportings/new-${fname}
diff tests/exportings/${fname} tests/exportings/new-${fname}
rm tests/exportings/new-${fname}
}
if [ ! -f .gitignore ]; then
echo "Need to run as ./tests/backends/$(basename "$0") from top level directory of git repository" >&2
echo "Need to run as ./tests/exportings/$(basename "$0") from top level directory of git repository" >&2
exit 1
fi

View File

@ -25,17 +25,17 @@ inline int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client
if (prometheus_exporter_instance)
prometheus_exporting_options = prometheus_exporter_instance->config.options;
else
prometheus_exporting_options = global_backend_options;
prometheus_exporting_options = global_exporting_options;
PROMETHEUS_OUTPUT_OPTIONS prometheus_output_options =
PROMETHEUS_OUTPUT_TIMESTAMPS |
((prometheus_exporting_options & BACKEND_OPTION_SEND_NAMES) ? PROMETHEUS_OUTPUT_NAMES : 0);
((prometheus_exporting_options & EXPORTING_OPTION_SEND_NAMES) ? PROMETHEUS_OUTPUT_NAMES : 0);
const char *prometheus_prefix;
if (prometheus_exporter_instance)
prometheus_prefix = prometheus_exporter_instance->config.prefix;
else
prometheus_prefix = global_backend_prefix;
prometheus_prefix = global_exporting_prefix;
while(url) {
char *value = mystrsep(&url, "&");
@ -64,7 +64,7 @@ inline int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client
prometheus_prefix = value;
}
else if(!strcmp(name, "data") || !strcmp(name, "source") || !strcmp(name, "data source") || !strcmp(name, "data-source") || !strcmp(name, "data_source") || !strcmp(name, "datasource")) {
prometheus_exporting_options = backend_parse_data_source(value, prometheus_exporting_options);
prometheus_exporting_options = exporting_parse_data_source(value, prometheus_exporting_options);
}
else {
int i;