mirror of
https://github.com/netdata/netdata.git
synced 2025-04-13 01:08:11 +00:00

* cleanup of logging - wip
* first working iteration
* add errno annotator
* replace old logging functions with netdata_logger()
* cleanup
* update error_limit
* fix remanining error_limit references
* work on fatal()
* started working on structured logs
* full cleanup
* default logging to files; fix all plugins initialization
* fix formatting of numbers
* cleanup and reorg
* fix coverity issues
* cleanup obsolete code
* fix formatting of numbers
* fix log rotation
* fix for older systems
* add detection of systemd journal via stderr
* finished on access.log
* remove left-over transport
* do not add empty fields to the logs
* journal get compact uuids; X-Transaction-ID header is added in web responses
* allow compiling on systems without memfd sealing
* added libnetdata/uuid directory
* move datetime formatters to libnetdata
* add missing files
* link the makefiles in libnetdata
* added uuid_parse_flexi() to parse UUIDs with and without hyphens; the web server now read X-Transaction-ID and uses it for functions and web responses
* added stream receiver, sender, proc plugin and pluginsd log stack
* iso8601 advanced usage; line_splitter module in libnetdata; code cleanup
* add message ids to streaming inbound and outbound connections
* cleanup line_splitter between lines to avoid logging garbage; when killing children, kill them with SIGABRT if internal checks is enabled
* send SIGABRT to external plugins only if we are not shutting down
* fix cross cleanup in pluginsd parser
* fatal when there is a stack error in logs
* compile netdata with -fexceptions
* do not kill external plugins with SIGABRT
* metasync info logs to debug level
* added severity to logs
* added json output; added options per log output; added documentation; fixed issues mentioned
* allow memfd only on linux
* moved journal low level functions to journal.c/h
* move health logs to daemon.log with proper priorities
* fixed a couple of bugs; health log in journal
* updated docs
* systemd-cat-native command to push structured logs to journal from the command line
* fix makefiles
* restored NETDATA_LOG_SEVERITY_LEVEL
* fix makefiles
* systemd-cat-native can also work as the logger of Netdata scripts
* do not require a socket to systemd-journal to log-as-netdata
* alarm notify logs in native format
* properly compare log ids
* fatals log alerts; alarm-notify.sh working
* fix overflow warning
* alarm-notify.sh now logs the request (command line)
* anotate external plugins logs with the function cmd they run
* added context, component and type to alarm-notify.sh; shell sanitization removes control character and characters that may be expanded by bash
* reformatted alarm-notify logs
* unify cgroup-network-helper.sh
* added quotes around params
* charts.d.plugin switched logging to journal native
* quotes for logfmt
* unify the status codes of streaming receivers and senders
* alarm-notify: dont log anything, if there is nothing to do
* all external plugins log to stderr when running outside netdata; alarm-notify now shows an error when notifications menthod are needed but are not available
* migrate cgroup-name.sh to new logging
* systemd-cat-native now supports messages with newlines
* socket.c logs use priority
* cleanup log field types
* inherit the systemd set INVOCATION_ID if found
* allow systemd-cat-native to send messages to a systemd-journal-remote URL
* log2journal command that can convert structured logs to journal export format
* various fixes and documentation of log2journal
* updated log2journal docs
* updated log2journal docs
* updated documentation of fields
* allow compiling without libcurl
* do not use socket as format string
* added version information to newly added tools
* updated documentation and help messages
* fix the namespace socket path
* print errno with error
* do not timeout
* updated docs
* updated docs
* updated docs
* log2journal updated docs and params
* when talking to a remote journal, systemd-cat-native batches the messages
* enable lz4 compression for systemd-cat-native when sending messages to a systemd-journal-remote
* Revert "enable lz4 compression for systemd-cat-native when sending messages to a systemd-journal-remote"
This reverts commit b079d53c11
.
* note about uncompressed traffic
* log2journal: code reorg and cleanup to make modular
* finished rewriting log2journal
* more comments
* rewriting rules support
* increased limits
* updated docs
* updated docs
* fix old log call
* use journal only when stderr is connected to journal
* update netdata.spec for libcurl, libpcre2 and log2journal
* pcre2-devel
* do not require pcre2 in centos < 8, amazonlinux < 2023, open suse
* log2journal only on systems pcre2 is available
* ignore log2journal in .gitignore
* avoid log2journal on centos 7, amazonlinux 2 and opensuse
* add pcre2-8 to static build
* undo last commit
* Bundle to static
Signed-off-by: Tasos Katsoulas <tasos@netdata.cloud>
* Add build deps for deb packages
Signed-off-by: Tasos Katsoulas <tasos@netdata.cloud>
* Add dependencies; build from source
Signed-off-by: Tasos Katsoulas <tasos@netdata.cloud>
* Test build for amazon linux and centos expect to fail for suse
Signed-off-by: Tasos Katsoulas <tasos@netdata.cloud>
* fix minor oversight
Signed-off-by: Tasos Katsoulas <tasos@netdata.cloud>
* Reorg code
* Add the install from source (deps) as a TODO
* Not enable the build on suse ecosystem
Signed-off-by: Tasos Katsoulas <tasos@netdata.cloud>
---------
Signed-off-by: Tasos Katsoulas <tasos@netdata.cloud>
Co-authored-by: Tasos Katsoulas <tasos@netdata.cloud>
295 lines
7.6 KiB
C
295 lines
7.6 KiB
C
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include "cli.h"
|
|
#include "daemon/pipename.h"
|
|
|
|
void netdata_logger(ND_LOG_SOURCES source, ND_LOG_FIELD_PRIORITY priority, const char *file, const char *function, unsigned long line, const char *fmt, ... ) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vfprintf(stderr, fmt, args );
|
|
va_end(args);
|
|
}
|
|
|
|
#ifdef NETDATA_INTERNAL_CHECKS
|
|
|
|
uint64_t debug_flags;
|
|
|
|
void netdata_logger_fatal( const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, const char *fmt __maybe_unused, ... )
|
|
{
|
|
abort();
|
|
};
|
|
#endif
|
|
|
|
#ifdef NETDATA_TRACE_ALLOCATIONS
|
|
void *callocz_int(size_t nmemb, size_t size, const char *file __maybe_unused, const char *function __maybe_unused, size_t line __maybe_unused)
|
|
{
|
|
void *p = calloc(nmemb, size);
|
|
if (unlikely(!p)) {
|
|
netdata_log_error("Cannot allocate %zu bytes of memory.", nmemb * size);
|
|
exit(1);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
void *mallocz_int(size_t size, const char *file __maybe_unused, const char *function __maybe_unused, size_t line __maybe_unused)
|
|
{
|
|
void *p = malloc(size);
|
|
if (unlikely(!p)) {
|
|
netdata_log_error("Cannot allocate %zu bytes of memory.", size);
|
|
exit(1);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
void *reallocz_int(void *ptr, size_t size, const char *file __maybe_unused, const char *function __maybe_unused, size_t line __maybe_unused)
|
|
{
|
|
void *p = realloc(ptr, size);
|
|
if (unlikely(!p)) {
|
|
netdata_log_error("Cannot allocate %zu bytes of memory.", size);
|
|
exit(1);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
void freez_int(void *ptr, const char *file __maybe_unused, const char *function __maybe_unused, size_t line __maybe_unused)
|
|
{
|
|
free(ptr);
|
|
}
|
|
#else
|
|
void freez(void *ptr) {
|
|
free(ptr);
|
|
}
|
|
|
|
void *mallocz(size_t size) {
|
|
void *p = malloc(size);
|
|
if (unlikely(!p)) {
|
|
netdata_log_error("Cannot allocate %zu bytes of memory.", size);
|
|
exit(1);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
void *callocz(size_t nmemb, size_t size) {
|
|
void *p = calloc(nmemb, size);
|
|
if (unlikely(!p)) {
|
|
netdata_log_error("Cannot allocate %zu bytes of memory.", nmemb * size);
|
|
exit(1);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
void *reallocz(void *ptr, size_t size) {
|
|
void *p = realloc(ptr, size);
|
|
if (unlikely(!p)) {
|
|
netdata_log_error("Cannot allocate %zu bytes of memory.", size);
|
|
exit(1);
|
|
}
|
|
return p;
|
|
}
|
|
#endif
|
|
|
|
int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args) {
|
|
if(unlikely(!n)) return 0;
|
|
|
|
int size = vsnprintf(dst, n, fmt, args);
|
|
dst[n - 1] = '\0';
|
|
|
|
if (unlikely((size_t) size > n)) size = (int)n;
|
|
|
|
return size;
|
|
}
|
|
|
|
static uv_pipe_t client_pipe;
|
|
static uv_write_t write_req;
|
|
static uv_shutdown_t shutdown_req;
|
|
|
|
static char command_string[MAX_COMMAND_LENGTH];
|
|
static unsigned command_string_size;
|
|
|
|
static int exit_status;
|
|
|
|
struct command_context {
|
|
uv_work_t work;
|
|
uv_stream_t *client;
|
|
cmd_t idx;
|
|
char *args;
|
|
char *message;
|
|
cmd_status_t status;
|
|
};
|
|
|
|
static void parse_command_reply(BUFFER *buf)
|
|
{
|
|
char *response_string = (char *) buffer_tostring(buf);
|
|
unsigned response_string_size = buffer_strlen(buf);
|
|
FILE *stream = NULL;
|
|
char *pos;
|
|
int syntax_error = 0;
|
|
|
|
for (pos = response_string ;
|
|
pos < response_string + response_string_size && !syntax_error ;
|
|
++pos) {
|
|
/* Skip white-space characters */
|
|
for ( ; isspace(*pos) && ('\0' != *pos); ++pos) {;}
|
|
|
|
if ('\0' == *pos)
|
|
continue;
|
|
|
|
switch (*pos) {
|
|
case CMD_PREFIX_EXIT_CODE:
|
|
exit_status = atoi(++pos);
|
|
break;
|
|
case CMD_PREFIX_INFO:
|
|
stream = stdout;
|
|
break;
|
|
case CMD_PREFIX_ERROR:
|
|
stream = stderr;
|
|
break;
|
|
default:
|
|
syntax_error = 1;
|
|
fprintf(stderr, "Syntax error, failed to parse command response.\n");
|
|
break;
|
|
}
|
|
if (stream) {
|
|
fprintf(stream, "%s\n", ++pos);
|
|
pos += strlen(pos);
|
|
stream = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void pipe_read_cb(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf)
|
|
{
|
|
BUFFER *response = client->data;
|
|
|
|
if (0 == nread)
|
|
fprintf(stderr, "%s: Zero bytes read by command pipe.\n", __func__);
|
|
else if (UV_EOF == nread)
|
|
parse_command_reply(response);
|
|
else if (nread < 0) {
|
|
fprintf(stderr, "%s: %s\n", __func__, uv_strerror(nread));
|
|
(void)uv_read_stop((uv_stream_t *)client);
|
|
}
|
|
else
|
|
buffer_fast_rawcat(response, buf->base, nread);
|
|
|
|
if (buf && buf->len)
|
|
free(buf->base);
|
|
}
|
|
|
|
static void alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
|
|
{
|
|
(void)handle;
|
|
|
|
buf->base = malloc(suggested_size);
|
|
buf->len = suggested_size;
|
|
}
|
|
|
|
static void shutdown_cb(uv_shutdown_t* req, int status)
|
|
{
|
|
int ret;
|
|
|
|
(void)req;
|
|
(void)status;
|
|
|
|
/* receive reply */
|
|
client_pipe.data = req->data;
|
|
|
|
ret = uv_read_start((uv_stream_t *)&client_pipe, alloc_cb, pipe_read_cb);
|
|
if (ret) {
|
|
fprintf(stderr, "uv_read_start(): %s\n", uv_strerror(ret));
|
|
uv_close((uv_handle_t *)&client_pipe, NULL);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void pipe_write_cb(uv_write_t* req, int status)
|
|
{
|
|
int ret;
|
|
|
|
(void)status;
|
|
|
|
uv_pipe_t *clientp = req->data;
|
|
shutdown_req.data = clientp->data;
|
|
|
|
ret = uv_shutdown(&shutdown_req, (uv_stream_t *)&client_pipe, shutdown_cb);
|
|
if (ret) {
|
|
fprintf(stderr, "uv_shutdown(): %s\n", uv_strerror(ret));
|
|
uv_close((uv_handle_t *)&client_pipe, NULL);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void connect_cb(uv_connect_t* req, int status)
|
|
{
|
|
int ret;
|
|
uv_buf_t write_buf;
|
|
char *s;
|
|
|
|
(void)req;
|
|
if (status) {
|
|
fprintf(stderr, "uv_pipe_connect(): %s\n", uv_strerror(status));
|
|
fprintf(stderr, "Make sure the netdata service is running.\n");
|
|
exit(-1);
|
|
}
|
|
if (0 == command_string_size) {
|
|
s = fgets(command_string, MAX_COMMAND_LENGTH - 1, stdin);
|
|
}
|
|
(void)s; /* We don't need input to communicate with the server */
|
|
command_string_size = strlen(command_string);
|
|
client_pipe.data = req->data;
|
|
|
|
write_req.data = &client_pipe;
|
|
write_buf.base = command_string;
|
|
write_buf.len = command_string_size;
|
|
ret = uv_write(&write_req, (uv_stream_t *)&client_pipe, &write_buf, 1, pipe_write_cb);
|
|
if (ret) {
|
|
fprintf(stderr, "uv_write(): %s\n", uv_strerror(ret));
|
|
}
|
|
// fprintf(stderr, "COMMAND: Sending command: \"%s\"\n", command_string);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int ret, i;
|
|
static uv_loop_t* loop;
|
|
uv_connect_t req;
|
|
|
|
exit_status = -1; /* default status for when there is no command response from server */
|
|
|
|
loop = uv_default_loop();
|
|
|
|
ret = uv_pipe_init(loop, &client_pipe, 1);
|
|
if (ret) {
|
|
fprintf(stderr, "uv_pipe_init(): %s\n", uv_strerror(ret));
|
|
return exit_status;
|
|
}
|
|
|
|
command_string_size = 0;
|
|
command_string[0] = '\0';
|
|
for (i = 1 ; i < argc ; ++i) {
|
|
size_t to_copy;
|
|
|
|
to_copy = MIN(strlen(argv[i]), MAX_COMMAND_LENGTH - 1 - command_string_size);
|
|
strncpy(command_string + command_string_size, argv[i], to_copy);
|
|
command_string_size += to_copy;
|
|
command_string[command_string_size] = '\0';
|
|
|
|
if (command_string_size < MAX_COMMAND_LENGTH - 1) {
|
|
command_string[command_string_size++] = ' ';
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
req.data = buffer_create(128, NULL);
|
|
|
|
const char *pipename = daemon_pipename();
|
|
uv_pipe_connect(&req, &client_pipe, pipename, connect_cb);
|
|
|
|
uv_run(loop, UV_RUN_DEFAULT);
|
|
|
|
uv_close((uv_handle_t *)&client_pipe, NULL);
|
|
buffer_free(client_pipe.data);
|
|
|
|
return exit_status;
|
|
}
|