summaryrefslogtreecommitdiffstats
path: root/collectors
diff options
context:
space:
mode:
Diffstat (limited to 'collectors')
-rw-r--r--collectors/apps.plugin/apps_plugin.c12
-rw-r--r--collectors/cgroups.plugin/cgroup-internals.h19
-rw-r--r--collectors/cgroups.plugin/cgroup-top.c46
-rw-r--r--collectors/cgroups.plugin/sys_fs_cgroup.c13
-rw-r--r--collectors/diskspace.plugin/plugin_diskspace.c30
-rw-r--r--collectors/ebpf.plugin/ebpf_functions.c9
-rw-r--r--collectors/freeipmi.plugin/freeipmi_plugin.c10
-rw-r--r--collectors/plugins.d/README.md216
-rw-r--r--collectors/plugins.d/gperf-config.txt36
-rw-r--r--collectors/plugins.d/gperf-hashtable.h184
-rw-r--r--collectors/plugins.d/plugins_d.h11
-rw-r--r--collectors/plugins.d/pluginsd_dyncfg.c620
-rw-r--r--collectors/plugins.d/pluginsd_dyncfg.h10
-rw-r--r--collectors/plugins.d/pluginsd_functions.c231
-rw-r--r--collectors/plugins.d/pluginsd_functions.h14
-rw-r--r--collectors/plugins.d/pluginsd_internals.c1
-rw-r--r--collectors/plugins.d/pluginsd_parser.c26
-rw-r--r--collectors/plugins.d/pluginsd_parser.h2
-rw-r--r--collectors/proc.plugin/proc_diskstats.c35
-rw-r--r--collectors/proc.plugin/proc_net_dev.c24
-rw-r--r--collectors/systemd-journal.plugin/systemd-internals.h15
-rw-r--r--collectors/systemd-journal.plugin/systemd-journal-dyncfg.c98
-rw-r--r--collectors/systemd-journal.plugin/systemd-journal-files.c10
-rw-r--r--collectors/systemd-journal.plugin/systemd-journal-watcher.c14
-rw-r--r--collectors/systemd-journal.plugin/systemd-journal.c3
-rw-r--r--collectors/systemd-journal.plugin/systemd-main.c24
-rw-r--r--collectors/systemd-journal.plugin/systemd-units.c4
27 files changed, 649 insertions, 1068 deletions
diff --git a/collectors/apps.plugin/apps_plugin.c b/collectors/apps.plugin/apps_plugin.c
index ae37b48f07..86c4b6da6b 100644
--- a/collectors/apps.plugin/apps_plugin.c
+++ b/collectors/apps.plugin/apps_plugin.c
@@ -4397,7 +4397,9 @@ static void apps_plugin_function_processes_help(const char *transaction) {
buffer_json_add_array_item_double(wb, _tmp); \
} while(0)
-static void function_processes(const char *transaction, char *function __maybe_unused, usec_t *stop_monotonic_ut __maybe_unused, bool *cancelled __maybe_unused) {
+static void function_processes(const char *transaction, char *function __maybe_unused,
+ usec_t *stop_monotonic_ut __maybe_unused, bool *cancelled __maybe_unused,
+ BUFFER *payload __maybe_unused, const char *source __maybe_unused, void *data __maybe_unused) {
struct pid_stat *p;
char *words[PLUGINSD_MAX_WORDS] = { NULL };
@@ -4459,8 +4461,8 @@ static void function_processes(const char *transaction, char *function __maybe_u
return;
}
else {
- char msg[PLUGINSD_LINE_MAX];
- snprintfz(msg, PLUGINSD_LINE_MAX, "Invalid parameter '%s'", keyword);
+ char msg[1024];
+ snprintfz(msg, sizeof(msg), "Invalid parameter '%s'", keyword);
pluginsd_function_json_error_to_stdout(transaction, HTTP_RESP_BAD_REQUEST, msg);
return;
}
@@ -4472,7 +4474,7 @@ static void function_processes(const char *transaction, char *function __maybe_u
unsigned int memory_divisor = 1024;
unsigned int io_divisor = 1024 * RATES_DETAIL;
- BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL);
+ BUFFER *wb = buffer_create(4096, NULL);
buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS);
buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
buffer_json_member_add_string(wb, "type", "table");
@@ -5348,7 +5350,7 @@ int main(int argc, char **argv) {
struct functions_evloop_globals *wg =
functions_evloop_init(1, "APPS", &apps_and_stdout_mutex, &apps_plugin_exit);
- functions_evloop_add_function(wg, "processes", function_processes, PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT);
+ functions_evloop_add_function(wg, "processes", function_processes, PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT, NULL);
// ------------------------------------------------------------------------
diff --git a/collectors/cgroups.plugin/cgroup-internals.h b/collectors/cgroups.plugin/cgroup-internals.h
index 2cd0673ae1..5fc7ca5e6d 100644
--- a/collectors/cgroups.plugin/cgroup-internals.h
+++ b/collectors/cgroups.plugin/cgroup-internals.h
@@ -454,23 +454,8 @@ static inline char *cgroup_chart_type(char *buffer, struct cgroup *cg) {
#define RRDFUNCTIONS_CGTOP_HELP "View running containers"
#define RRDFUNCTIONS_SYSTEMD_SERVICES_HELP "View systemd services"
-int cgroup_function_cgroup_top(uuid_t *transaction, BUFFER *wb,
- usec_t *stop_monotonic_ut, const char *function, void *collector_data,
- rrd_function_result_callback_t result_cb, void *result_cb_data,
- rrd_function_progress_cb_t progress_cb, void *progress_cb_data,
- rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data,
- rrd_function_register_canceller_cb_t register_canceller_cb, void *register_canceller_cb_data,
- rrd_function_register_progresser_cb_t register_progresser_cb,
- void *register_progresser_cb_data);
-
-int cgroup_function_systemd_top(uuid_t *transaction, BUFFER *wb,
- usec_t *stop_monotonic_ut, const char *function, void *collector_data,
- rrd_function_result_callback_t result_cb, void *result_cb_data,
- rrd_function_progress_cb_t progress_cb, void *progress_cb_data,
- rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data,
- rrd_function_register_canceller_cb_t register_canceller_cb, void *register_canceller_cb_data,
- rrd_function_register_progresser_cb_t register_progresser_cb,
- void *register_progresser_cb_data);
+int cgroup_function_cgroup_top(BUFFER *wb, const char *function);
+int cgroup_function_systemd_top(BUFFER *wb, const char *function);
void cgroup_netdev_link_init(void);
const DICTIONARY_ITEM *cgroup_netdev_get(struct cgroup *cg);
diff --git a/collectors/cgroups.plugin/cgroup-top.c b/collectors/cgroups.plugin/cgroup-top.c
index 0ab2fd5903..aa158a0102 100644
--- a/collectors/cgroups.plugin/cgroup-top.c
+++ b/collectors/cgroups.plugin/cgroup-top.c
@@ -97,17 +97,7 @@ void cgroup_netdev_get_bandwidth(struct cgroup *cg, NETDATA_DOUBLE *received, NE
*sent = t->sent[slot];
}
-int cgroup_function_cgroup_top(uuid_t *transaction __maybe_unused, BUFFER *wb,
- usec_t *stop_monotonic_ut __maybe_unused, const char *function __maybe_unused,
- void *collector_data __maybe_unused,
- rrd_function_result_callback_t result_cb, void *result_cb_data,
- rrd_function_progress_cb_t progress_cb __maybe_unused, void *progress_cb_data __maybe_unused,
- rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data,
- rrd_function_register_canceller_cb_t register_canceller_cb __maybe_unused,
- void *register_canceller_cb_data __maybe_unused,
- rrd_function_register_progresser_cb_t register_progresser_cb __maybe_unused,
- void *register_progresser_cb_data __maybe_unused) {
-
+int cgroup_function_cgroup_top(BUFFER *wb, const char *function __maybe_unused) {
buffer_flush(wb);
wb->content_type = CT_APPLICATION_JSON;
buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
@@ -334,29 +324,10 @@ int cgroup_function_cgroup_top(uuid_t *transaction __maybe_unused, BUFFER *wb,
buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
buffer_json_finalize(wb);
- int response = HTTP_RESP_OK;
- if(is_cancelled_cb && is_cancelled_cb(is_cancelled_cb_data)) {
- buffer_flush(wb);
- response = HTTP_RESP_CLIENT_CLOSED_REQUEST;
- }
-
- if(result_cb)
- result_cb(wb, response, result_cb_data);
-
- return response;
+ return HTTP_RESP_OK;
}
-int cgroup_function_systemd_top(uuid_t *transaction __maybe_unused, BUFFER *wb,
- usec_t *stop_monotonic_ut __maybe_unused, const char *function __maybe_unused,
- void *collector_data __maybe_unused,
- rrd_function_result_callback_t result_cb, void *result_cb_data,
- rrd_function_progress_cb_t progress_cb __maybe_unused, void *progress_cb_data __maybe_unused,
- rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data,
- rrd_function_register_canceller_cb_t register_canceller_cb __maybe_unused,
- void *register_canceller_cb_data __maybe_unused,
- rrd_function_register_progresser_cb_t register_progresser_cb __maybe_unused,
- void *register_progresser_cb_data __maybe_unused) {
-
+int cgroup_function_systemd_top(BUFFER *wb, const char *function __maybe_unused) {
buffer_flush(wb);
wb->content_type = CT_APPLICATION_JSON;
buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
@@ -514,14 +485,5 @@ int cgroup_function_systemd_top(uuid_t *transaction __maybe_unused, BUFFER *wb,
buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
buffer_json_finalize(wb);
- int response = HTTP_RESP_OK;
- if(is_cancelled_cb && is_cancelled_cb(is_cancelled_cb_data)) {
- buffer_flush(wb);
- response = HTTP_RESP_CLIENT_CLOSED_REQUEST;
- }
-
- if(result_cb)
- result_cb(wb, response, result_cb_data);
-
- return response;
+ return HTTP_RESP_OK;
}
diff --git a/collectors/cgroups.plugin/sys_fs_cgroup.c b/collectors/cgroups.plugin/sys_fs_cgroup.c
index faf5b54af6..7f686f8f97 100644
--- a/collectors/cgroups.plugin/sys_fs_cgroup.c
+++ b/collectors/cgroups.plugin/sys_fs_cgroup.c
@@ -1671,16 +1671,15 @@ void *cgroups_main(void *ptr) {
// we register this only on localhost
// for the other nodes, the origin server should register it
- rrd_collector_started(); // this creates a collector that runs for as long as netdata runs
cgroup_netdev_link_init();
- rrd_function_add(localhost, NULL, "containers-vms", 10, RRDFUNCTIONS_PRIORITY_DEFAULT / 2,
- RRDFUNCTIONS_CGTOP_HELP, "top", HTTP_ACCESS_ANY,
- true, cgroup_function_cgroup_top, NULL);
+ rrd_function_add_inline(localhost, NULL, "containers-vms", 10,
+ RRDFUNCTIONS_PRIORITY_DEFAULT / 2, RRDFUNCTIONS_CGTOP_HELP,
+ "top", HTTP_ACCESS_ANY, cgroup_function_cgroup_top);
- rrd_function_add(localhost, NULL, "systemd-services", 10, RRDFUNCTIONS_PRIORITY_DEFAULT / 3,
- RRDFUNCTIONS_SYSTEMD_SERVICES_HELP, "top", HTTP_ACCESS_ANY,
- true, cgroup_function_systemd_top, NULL);
+ rrd_function_add_inline(localhost, NULL, "systemd-services", 10,
+ RRDFUNCTIONS_PRIORITY_DEFAULT / 3, RRDFUNCTIONS_SYSTEMD_SERVICES_HELP,
+ "top", HTTP_ACCESS_ANY, cgroup_function_systemd_top);
heartbeat_t hb;
heartbeat_init(&hb);
diff --git a/collectors/diskspace.plugin/plugin_diskspace.c b/collectors/diskspace.plugin/plugin_diskspace.c
index 78d7d5af2b..fc9efb68f2 100644
--- a/collectors/diskspace.plugin/plugin_diskspace.c
+++ b/collectors/diskspace.plugin/plugin_diskspace.c
@@ -636,17 +636,7 @@ static void diskspace_main_cleanup(void *ptr) {
#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 3
#endif
-int diskspace_function_mount_points(uuid_t *transaction __maybe_unused, BUFFER *wb,
- usec_t *stop_monotonic_ut __maybe_unused, const char *function __maybe_unused,
- void *collector_data __maybe_unused,
- rrd_function_result_callback_t result_cb, void *result_cb_data,
- rrd_function_progress_cb_t progress_cb __maybe_unused, void *progress_cb_data __maybe_unused,
- rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data,
- rrd_function_register_canceller_cb_t register_canceller_cb __maybe_unused,
- void *register_canceller_cb_data __maybe_unused,
- rrd_function_register_progresser_cb_t register_progresser_cb __maybe_unused,
- void *register_progresser_cb_data __maybe_unused) {
-
+int diskspace_function_mount_points(BUFFER *wb, const char *function __maybe_unused) {
buffer_flush(wb);
wb->content_type = CT_APPLICATION_JSON;
buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
@@ -850,16 +840,7 @@ int diskspace_function_mount_points(uuid_t *transaction __maybe_unused, BUFFER *
buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
buffer_json_finalize(wb);
- int response = HTTP_RESP_OK;
- if(is_cancelled_cb && is_cancelled_cb(is_cancelled_cb_data)) {
- buffer_flush(wb);
- response = HTTP_RESP_CLIENT_CLOSED_REQUEST;
- }
-
- if(result_cb)
- result_cb(wb, response, result_cb_data);
-
- return response;
+ return HTTP_RESP_OK;
}
void *diskspace_main(void *ptr) {
@@ -868,10 +849,9 @@ void *diskspace_main(void *ptr) {
worker_register_job_name(WORKER_JOB_MOUNTPOINT, "mountpoint");
worker_register_job_name(WORKER_JOB_CLEANUP, "cleanup");
- rrd_collector_started();
- rrd_function_add(localhost, NULL, "mount-points", 10, RRDFUNCTIONS_PRIORITY_DEFAULT, RRDFUNCTIONS_DISKSPACE_HELP,
- "top", HTTP_ACCESS_ANY,
- true, diskspace_function_mount_points, NULL);
+ rrd_function_add_inline(localhost, NULL, "mount-points", 10,
+ RRDFUNCTIONS_PRIORITY_DEFAULT, RRDFUNCTIONS_DISKSPACE_HELP,
+ "top", HTTP_ACCESS_ANY, diskspace_function_mount_points);
netdata_thread_cleanup_push(diskspace_main_cleanup, ptr);
diff --git a/collectors/ebpf.plugin/ebpf_functions.c b/collectors/ebpf.plugin/ebpf_functions.c
index e9e721a2a5..b881cba2ab 100644
--- a/collectors/ebpf.plugin/ebpf_functions.c
+++ b/collectors/ebpf.plugin/ebpf_functions.c
@@ -277,7 +277,10 @@ void ebpf_socket_read_open_connections(BUFFER *buf, struct ebpf_module *em)
static void ebpf_function_socket_manipulation(const char *transaction,
char *function __maybe_unused,
usec_t *stop_monotonic_ut __maybe_unused,
- bool *cancelled __maybe_unused)
+ bool *cancelled __maybe_unused,
+ BUFFER *payload __maybe_unused,
+ const char *source __maybe_unused,
+ void *data __maybe_unused)
{
ebpf_module_t *em = &ebpf_modules[EBPF_MODULE_SOCKET_IDX];
@@ -434,7 +437,7 @@ for (int i = 1; i < PLUGINSD_MAX_WORDS; i++) {
}
pthread_mutex_unlock(&ebpf_exit_cleanup);
- BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL);
+ BUFFER *wb = buffer_create(4096, NULL);
buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS);
buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
buffer_json_member_add_string(wb, "type", "table");
@@ -684,7 +687,7 @@ void *ebpf_function_thread(void *ptr)
&ebpf_plugin_exit);
functions_evloop_add_function(
- wg, EBPF_FUNCTION_SOCKET, ebpf_function_socket_manipulation, PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT);
+ wg, EBPF_FUNCTION_SOCKET, ebpf_function_socket_manipulation, PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT, NULL);
pthread_mutex_lock(&lock);
int i;
diff --git a/collectors/freeipmi.plugin/freeipmi_plugin.c b/collectors/freeipmi.plugin/freeipmi_plugin.c
index 72bf6dd755..8537c93c73 100644
--- a/collectors/freeipmi.plugin/freeipmi_plugin.c
+++ b/collectors/freeipmi.plugin/freeipmi_plugin.c
@@ -1471,10 +1471,12 @@ static const char *get_sensor_function_priority(struct sensor *sn) {
}
}
-static void freeimi_function_sensors(const char *transaction, char *function __maybe_unused, usec_t *stop_monotonic_ut __maybe_unused, bool *cancelled __maybe_unused) {
+static void freeimi_function_sensors(const char *transaction, char *function __maybe_unused,
+ usec_t *stop_monotonic_ut __maybe_unused, bool *cancelled __maybe_unused,
+ BUFFER *payload __maybe_unused, const char *source __maybe_unused, void *data __maybe_unused) {
time_t expires = now_realtime_sec() + update_every;
- BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL);
+ BUFFER *wb = buffer_create(4096, NULL);
buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS);
buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
buffer_json_member_add_string(wb, "type", "table");
@@ -1973,7 +1975,7 @@ int main (int argc, char **argv) {
size_t iteration = 0;
usec_t step = 100 * USEC_PER_MS;
bool global_chart_created = false;
- bool tty = isatty(fileno(stderr)) == 1;
+ bool tty = isatty(fileno(stdout)) == 1;
heartbeat_t hb;
heartbeat_init(&hb);
@@ -2045,7 +2047,7 @@ int main (int argc, char **argv) {
struct functions_evloop_globals *wg =
functions_evloop_init(1, "FREEIPMI", &stdout_mutex, &function_plugin_should_exit);
functions_evloop_add_function(
- wg, "ipmi-sensors", freeimi_function_sensors, PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT);
+ wg, "ipmi-sensors", freeimi_function_sensors, PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT, NULL);
FREEIPMI_GLOBAL_FUNCTION_SENSORS();
}
diff --git a/collectors/plugins.d/README.md b/collectors/plugins.d/README.md
index c2d8e14579..a62ed4c5a1 100644
--- a/collectors/plugins.d/README.md
+++ b/collectors/plugins.d/README.md
@@ -136,7 +136,8 @@ Netdata parses lines starting with:
- `FUNCTION` - define functions
- `FUNCTION_PROGRESS` - report the progress of a function execution
- `FUNCTION_RESULT_BEGIN` - to initiate the transmission of function results
-- `FUNCTION_RESULT_END` - to end the transmission of function results
+- `FUNCTION_RESULT_END` - to end the transmission of function result
+- `CONFIG` - to define dynamic configuration entities
a single program can produce any number of charts with any number of dimensions each.
@@ -147,7 +148,8 @@ Netdata may send the following commands to the plugin's `stdin`:
- `FUNCTION` - to call a specific function, with all parameters inline
- `FUNCTION_PAYLOAD` - to call a specific function, with a payload of parameters
- `FUNCTION_PAYLOAD_END` - to end the payload of parameters
-- `FUNCTION_CANCEL` - cancel a running function transaction
+- `FUNCTION_CANCEL` - to cancel a running function transaction - no response is required
+- `FUNCTION_PROGRESS` - to report that a user asked the progress of running function call - no response is required
### Command line parameters
@@ -471,43 +473,41 @@ The plugin can register functions to Netdata, like this:
> FUNCTION [GLOBAL] "name and parameters of the function" timeout "help string for users" "tags" "access"
- Tags currently recognized are either `top` or `logs` (or both, space separated).
-- Access is one of `any`, `members`, or `admins`.
+- Access is one of `any`, `member`, or `admin`:
+ - `any` to offer the function to all users of Netdata, even if they are not authenticated.
+ - `member` to offer the function to all authenticated members of Netdata.
+ - `admin` to offer the function only to authenticated administrators.
A function can be used by users to ask for more information from the collector. Netdata maintains a registry of functions in 2 levels:
- per node
- per chart
-Both node and chart functions are exactly the same, but chart functions allow Netdata to relate functions with charts and therefore present a context sensitive menu of functions related to the chart the user is using.
-
-A function is identified by a string. The allowed characters in the function definition are:
-
-| Character | Symbol | In Functions |
-|-------------------|:------:|:------------:|
-| UTF-8 character | UTF-8 | keep |
-| Lower case letter | [a-z] | keep |
-| Upper case letter | [A-Z] | keep |
-| Digit | [0-9] | keep |
-| Underscore | _ | keep |
-| Comma | , | keep |
-| Minus | - | keep |
-| Period | . | keep |
-| Colon | : | keep |
-| Slash | / | keep |
-| Space | ' ' | keep |
-| Semicolon | ; | : |
-| Equal | = | : |
-| Backslash | \ | / |
-| Anything else | | _ |
-
-Uses can get a list of all the registered functions using the `/api/v1/functions` end point of Netdata.
-
-Users can call functions using the `/api/v1/function` end point of Netdata.
+Both node and chart functions are exactly the same, but chart functions allow Netdata to relate functions with charts and therefore present a context-sensitive menu of functions related to the chart the user is using.
+
+Users can get a list of all the registered functions using the `/api/v1/functions` endpoint of Netdata and call functions using the `/api/v1/function` API call of Netdata.
+
Once a function is called, the plugin will receive at its standard input a command that looks like this:
-> FUNCTION transaction_id timeout "name and parameters of the function"
+> FUNCTION transaction_id timeout "name and parameters of the function as one quoted parameter" "source of request"
+
+When the function to be called is to receive a payload of parameters, the call looks like this:
+
+> FUNCTION_PAYLOAD transaction_id timeout "name and parameters of the function as one quoted parameter" "source of request" "content/type"
+> body of the payload, formatted according to content/type
+> FUNCTION PAYLOAD END
+
+In this case, Netdata will send:
-The plugin is expected to parse and validate `name and parameters of the function`. Netdata allows users to edit this string, append more parameters or even change the ones the plugin originally exposed. To minimize the security risk, Netdata guarantees that only the characters shown above are accepted in function definitions, but still the plugin should carefully inspect the `name and parameters of the function` to ensure that it is valid and not harmful.
+- A line starting with `FUNCTION_PAYLOAD` together with the required metadata for the function, like the transaction id, the function name and its parameters, the timeout and the content type. This line ends with a newline.
+- Then, the payload itself (which may or may not have newlines in it). The payload should be parsed according to the content type parameter.
+- Finally, a line starting with `FUNCTION_PAYLOAD_END`, so it is expected like `\nFUNCTION_PAYLOAD_END\n`.
+
+Note 1: The plugins.d protocol allows parameters without single or double quotes if they don't contain spaces. However, the plugin should be able to parse parameters even if they are enclosed in single or double quotes. If the first character of a parameter is a single quote, its last character should also be a single quote too, and similarly for double quotes.
+
+Note 2: Netdata always sends the function and its parameters enclosed in double quotes. If the function command and its parameters contain quotes, they are converted to single quotes.
+
+The plugin is expected to parse and validate `name and parameters of the function as one quotes parameter`. Netdata allows the user interface to manipulate this string by appending more parameters.
If the plugin rejects the request, it should respond with this:
@@ -522,12 +522,12 @@ FUNCTION_RESULT_END
If the plugin prepares a response, it should send (via its standard output, together with the collected data, but not interleaved with them):
-> FUNCTION_RESULT_BEGIN transaction_id http_error_code content_type expiration
+> FUNCTION_RESULT_BEGIN transaction_id http_response_code content_type expiration
Where:
- `transaction_id` is the transaction id that Netdata sent for this function execution
- - `http_error` is the http error code Netdata should respond with, 200 is the "ok" response
+ - `http_response_code` is the http error code Netdata should respond with, 200 is the "ok" response
- `content_type` is the content type of the response
- `expiration` is the absolute timestamp (number, unix epoch) this response expires
@@ -543,6 +543,158 @@ This defines the end of the message. `FUNCTION_RESULT_END` should appear in a li
After this line, Netdata resumes processing collected metrics from the plugin.
+The maximum uncompressed payload size Netdata will accept is 100MB.
+
+##### Functions cancellation
+
+Netdata is able to detect when a user made an API request, but abandoned it before it was completed. If this happens to an API called for a function served by the plugin, Netdata will generate a `FUNCTION_CANCEL` request to let the plugin know that it can stop processing the query.
+
+After receiving such a command, the plugin **must still send a response for the original function request**, to wake up any waiting threads before they timeout. The http response code is not important, since the response will be discarded, however for auditing reasons we suggest to send back a 499 http response code. This is not a standard response code according to the HTTP protocol, but web servers like `nginx` are using it to indicate that a request was abandoned by a user.
+
+##### Functions progress
+
+When a request takes too long to be processed, Netdata allows the plugin to report progress to Netdata, which in turn will report progress to the caller.
+
+The plugin can send `FUNCTION_PROGRESS` like this:
+
+> FUNCTION_PROGRESS transaction_id done all
+
+Where:
+
+- `transaction_id` is the transaction id of the function request
+- `done` is an integer value indicating the amount of work done
+- `all` is an integer value indicating the total amount of work to be done
+
+Netdata supports two kinds of progress:
+- progress as a percentage, which is calculated as `done * 100 / all`
+- progress without knowing the total amount of work to be done, which is enabled when the plugin reports `all` as zero.
+
+##### Functions timeout
+
+All functions calls specify a timeout, at which all the intermediate routing nodes (parents, web server threads) will time out and abort the call.
+
+However, all intermediate routing nodes are configured to extend the timeout when the caller asks for progress. This works like this:
+
+When a progress request is received, if the expected timeout of the request is less than or equal to 10 seconds, the expected timeout is extended by 10 seconds.
+
+Usually, the user interface asks for a progress every second. So, during the last 10 seconds of the timeout, every progress request made shifts the timeout 10 seconds to the future.
+
+To accomplish this, when Netdata receives a progress request by a user, it generates progress requests to the plugin, updating all the intermediate nodes to extend their timeout if necessary.
+
+The plugin will receive progress requests like this:
+
+> FUNCTION_PROGRESS transaction_id
+
+There is no need to respond to this command. It is only there to let the plugin know that a user is still waiting for the query to finish.
+
+#### CONFIG
+
+`CONFIG` commands sent from the plugin to Netdata define dynamic configuration entities. These configurable entities are exposed to the user interface, allowing users to change configuration at runtime.
+
+Dynamically configurations made this way are saved to disk by Netdata and are replayed automatically when Netdata or the plugin restarts.
+
+`CONFIG` commands look like this:
+
+> CONFIG id action ...
+
+Where:
+
+- `id` is a unique identifier for the configurable entity. This should by design be unique across Netdata. It should be something like `plugin:module:jobs`, e.g. `go.d:postgresql:jobs:masterdb`. This is assumed to be colon-separated with the last part (`masterdb` in our example), being the one displayed to users when there ano conflicts under the same configuration path.
+- `action` can be:
+ - `create`, to declare the dynamic configuration entity
+ - `delete`, to delete the dynamic configuration entity - this does not delete user configuration, we if an entity with the same id is created in the future, the saved configuration will be given to it.
+ - `status`, to update the dynamic configuration entity status
+
+> IMPORTANT:<br/>
+> The plugin should blindly create, delete and update the status of its dynamic configuration entities, without any special logic applied to it. Netdata needs to be updated of what is actually happening at the plugin. Keep in mind that creating dynamic configuration entities triggers responses from Netdata, depending on its type and status. Re-creating a job, triggers the same responses every time.
+
+
+When the `action` is `create`, the following additional parameters are expected:
+
+> CONFIG id action status type "path" source_type "source" "supported commands"
+
+Where:
+
+- `action` should be `create`
+- `status` can be:
+ - `accepted`, the plugin accepted the configuration, but it is not running yet.
+ - `running`, the plugin accepted and runs the configuration.
+ - `failed`, the plugin tries to run the configuration but it fails.
+ - `incomplete`, the plugin needs additional settings to run this configuration. This is usually used for the cases the plugin discovered a job, but important information is missing for it to work.
+ - `disabled`, the configuration has been disabled by a user.
+ - `orphan`, the configuration is not claimed by any plugin. This is used internally by Netdata to mark the configuration nodes available, for which there is no plugin related to them. Do not use in plugins directly.
+- `type` can be `single`, `template` or `job`:
+ - `single` is used when the configurable entity is fixed and users should never be able to add or delete it.
+ - `template` is used to define a template based on which users can add multiple configurations, like adding data collection jobs. So, the plugin defines the template of the jobs and users are presented with a `[+]` button to add such configuration jobs. The plugin can define multiple templates by giving different `id`s to them.
+ - `job` is used to define a job of a template. The plugin should always add all its jobs, independently of the way they have been discovered. It is important to note the relation between `template` and `job` when it comes it the `id`: The `id` of the template should be the prefix of the `job`'s `id`. For example, if the template is `go.d:postgresql:jobs`, then all its jobs be like `go.d:postgresql:jobs:jobname`.
+- `path` is the absolute path of the configurable entity inside the tree of Netdata configurations. Usually, this is should be `/collectors`.
+- `source` can be `internal`, `stock`, `user`, `discovered` or `dyncfg`:
+ - `internal` is used for configurations that are based on internal code settings
+ - `stock` is used for default configurations
+ - `discovered` is used for dynamic configurations the plugin discovers by its own
+ - `user` is used for user configurations, usually via a configuration file
+ - `dyncfg` is used for configuration received via this dynamic configuration mechanism
+- `source` should provide more details about the exact source of the configuration, like `line@file`, or `user@ip`, etc.
+- `supported_commands` is a space separated list of the following keywords, enclosed in single or double quotes. These commands are used by the user interface to determine the actions the users can take:
+ - `schema`, to expose the JSON schema for the user interface. This is mandatory for all configurable entities. When `schema` requests are received, Netdata will first attempt to load the schema from `/etc/netdata/schema.d/` and `/var/lib/netdata/conf.d/schema.d`. For jobs, it will serve the schema of their template. If no schema is found for the required `id`, the `schema` request will be forwarded to the plugin, which is expected to send back the relevant schema.
+ - `get`, to expose the current configuration values, according the schema defined. `templates` cannot support `get`, since they don't maintain any data.
+ - `update`, to receive configuration updates for this entity. `templates` cannot support `update`, since they don't maintain any data.
+ - `test`, like `update` but only test the configuration and report success or failure.
+ - `add`, to receive job creation commands for templates. Only `templates` should support this command.
+ - `remove`, to remove a configuration. Only `jobs` should support this command.
+ - `enable` and `disable`, to receive user requests to enable and disable this entity. Adding only one of `enable` or `disable` to the supported commands, Netdata will add both of them. The plugin should expose these commands on `templates` only when it wants to receive `enable` and `disable` commands for all the `jobs` of this `template`.
+ - `restart`