Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

config parsers #17238

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,9 @@ set(LIBNETDATA_FILES
src/libnetdata/dictionary/dictionary-callbacks.h
src/libnetdata/linked-lists.h
src/libnetdata/storage-point.h
src/libnetdata/bitmap64.h
src/libnetdata/bitmap.h
src/libnetdata/parsers/parsers.h
src/libnetdata/parsers/time.c
)

if(ENABLE_PLUGIN_EBPF)
Expand Down
2 changes: 1 addition & 1 deletion src/libnetdata/libnetdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ extern char *netdata_configured_host_prefix;
#include "inlined.h"
#include "line_splitter/line_splitter.h"
#include "clocks/clocks.h"
#include "parsers/parsers.h"
#include "datetime/iso8601.h"
#include "datetime/rfc3339.h"
#include "datetime/rfc7231.h"
Expand Down Expand Up @@ -576,7 +577,6 @@ void timing_action(TIMING_ACTION action, TIMING_STEP step);
int hash256_string(const unsigned char *string, size_t size, char *hash);

extern bool unittest_running;
#define API_RELATIVE_TIME_MAX (3 * 365 * 86400)

bool rrdr_relative_window_to_absolute(time_t *after, time_t *before, time_t now);
bool rrdr_relative_window_to_absolute_query(time_t *after, time_t *before, time_t *now_ptr, bool unittest);
Expand Down
37 changes: 37 additions & 0 deletions src/libnetdata/parsers/parsers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef NETDATA_PARSERS_H
#define NETDATA_PARSERS_H

#include "../libnetdata.h"

typedef struct {
time_t after;
time_t before;
} TIMEFRAME;

#define API_RELATIVE_TIME_MAX (3 * 365 * 86400)

#define API_RELATIVE_TIME_INVALID (-1000000000)

#define API_RELATIVE_TIME_THIS_MINUTE (API_RELATIVE_TIME_INVALID - 1) // this minute at 00 seconds
#define API_RELATIVE_TIME_THIS_HOUR (API_RELATIVE_TIME_INVALID - 2) // this hour at 00 minutes, 00 seconds
#define API_RELATIVE_TIME_TODAY (API_RELATIVE_TIME_INVALID - 3) // today at 00:00:00
#define API_RELATIVE_TIME_THIS_WEEK (API_RELATIVE_TIME_INVALID - 4) // this Monday, 00:00:00
#define API_RELATIVE_TIME_THIS_MONTH (API_RELATIVE_TIME_INVALID - 5) // this month's 1st at 00:00:00
#define API_RELATIVE_TIME_THIS_YEAR (API_RELATIVE_TIME_INVALID - 6) // this year's Jan 1st, at 00:00:00
#define API_RELATIVE_TIME_LAST_MONTH (API_RELATIVE_TIME_INVALID - 7) // last month's 1st, at 00:00:00
#define API_RELATIVE_TIME_LAST_YEAR (API_RELATIVE_TIME_INVALID - 8) // last year's Jan 1st, at 00:00:00

#define TIMEFRAME_INVALID (TIMEFRAME){ .after = API_RELATIVE_TIME_INVALID, .before = API_RELATIVE_TIME_INVALID }

nsec_t duration_to_nsec_t(const char *duration, nsec_t default_value, const char *default_unit);
usec_t duration_to_usec_t(const char *duration, usec_t default_value, const char *default_unit);
time_t duration_to_time_t(const char *duration, time_t default_value, const char *default_unit);

// return number of bytes written to dst
size_t duration_from_nsec_t(char *dst, size_t size, nsec_t value, const char *default_unit);
size_t duration_from_usec_t(char *dst, size_t size, usec_t value, const char *default_unit);
size_t duration_from_time_t(char *dst, size_t size, time_t value, const char *default_unit);

#endif //NETDATA_PARSERS_H
242 changes: 242 additions & 0 deletions src/libnetdata/parsers/time.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
// SPDX-License-Identifier: GPL-3.0-or-later

#include "parsers.h"

#define MINUTE_IN_SECONDS (60)
#define HOUR_IN_SECONDS (MINUTE_IN_SECONDS * 60)
#define DAY_IN_SECONDS (HOUR_IN_SECONDS * 24)
#define WEEK_IN_SECONDS (DAY_IN_SECONDS * 7)
#define YEAR_IN_SECONDS (DAY_IN_SECONDS * 365)
#define MONTH_IN_SECONDS (YEAR_IN_SECONDS / 12)
#define QUARTER_IN_SECONDS (YEAR_IN_SECONDS / 4)

// Define a structure to map time units to their multipliers
struct {
const char *unit;
nsec_t multiplier;
} units[] = {
{ .unit = "ns", .multiplier = 1 }, // UCUM
{ .unit = "us", .multiplier = 1 * NSEC_PER_USEC }, // UCUM
{ .unit = "ms", .multiplier = 1 * USEC_PER_MS * NSEC_PER_USEC }, // UCUM
{ .unit = "s", .multiplier = 1 * NSEC_PER_SEC }, // UCUM
{ .unit = "m", .multiplier = MINUTE_IN_SECONDS * NSEC_PER_SEC }, // -
{ .unit = "min", .multiplier = MINUTE_IN_SECONDS * NSEC_PER_SEC }, // UCUM
{ .unit = "h", .multiplier = HOUR_IN_SECONDS * NSEC_PER_SEC }, // UCUM
{ .unit = "d", .multiplier = DAY_IN_SECONDS * NSEC_PER_SEC }, // UCUM
{ .unit = "w", .multiplier = WEEK_IN_SECONDS * NSEC_PER_SEC }, // -
{ .unit = "wk", .multiplier = WEEK_IN_SECONDS * NSEC_PER_SEC }, // UCUM
{ .unit = "mo", .multiplier = MONTH_IN_SECONDS * NSEC_PER_SEC }, // UCUM
{ .unit = "q", .multiplier = QUARTER_IN_SECONDS * NSEC_PER_SEC }, // -
{ .unit = "y", .multiplier = YEAR_IN_SECONDS * NSEC_PER_SEC }, // -
{ .unit = "a", .multiplier = YEAR_IN_SECONDS * NSEC_PER_SEC }, // UCUM
};

// -------------------------------------------------------------------------------------------------------------------
// parse a duration string

nsec_t duration_to_nsec_t(const char *duration, nsec_t default_value, const char *default_unit) {
if(!duration || !*duration)
return default_value;

if(!default_unit)
default_unit = "ns";

const char *end = NULL;
double value = strtod(duration, (char **)&end);

if (!end || end == duration)
return default_value;

while(isspace(*end))
end++;

if (!*end)
end = default_unit;

for (size_t i = 0; i < sizeof(units) / sizeof(units[0]); i++) {
if (strcmp(end, units[i].unit) == 0)
return (nsec_t)(value * (double)units[i].multiplier);
}

return (nsec_t)value;
}

usec_t duration_to_usec_t(const char *duration, usec_t default_value, const char *default_unit) {
if(!default_unit)
default_unit = "us";

return (time_t)(duration_to_nsec_t(duration, default_value, default_unit) / NSEC_PER_USEC);
}

time_t duration_to_time_t(const char *duration, time_t default_value, const char *default_unit) {
if(!default_unit)
default_unit = "s";

return (time_t)(duration_to_nsec_t(duration, default_value, default_unit) / NSEC_PER_SEC);
}

// --------------------------------------------------------------------------------------------------------------------
// generate a string to represent a duration

size_t duration_from_nsec_t(char *dst, size_t size, nsec_t value, const char *default_unit) {
if (!dst || !size) return 0;
if (size == 1) {
*dst = '\0';
return 0;
}

if(!default_unit)
default_unit = "ns";

for (int i = sizeof(units) / sizeof(units[0]) - 1; i >= 0; i--) {
if ((value % units[i].multiplier) == 0) {
uint64_t num_units = value / units[i].multiplier;
return snprintf(dst, size, "%"PRIu64"%s", num_units, units[i].unit);
}
}

for (size_t i = 0; i < sizeof(units) / sizeof(units[0]); i++) {
if (strcmp(default_unit, units[i].unit) == 0) {
double num_units = (double)value / (double)units[i].multiplier;
return snprintf(dst, size, "%.2f%s", num_units, units[i].unit);
}
}

// If no suitable unit is found, default to nanoseconds
return snprintf(dst, size, "%"PRIu64"ns", (uint64_t)value);
}

size_t duration_from_usec_t(char *dst, size_t size, usec_t value, const char *default_unit) {
if(!default_unit) default_unit = "us";
return duration_from_nsec_t(dst, size, value * NSEC_PER_USEC, default_unit);
}

size_t duration_from_time_t(char *dst, size_t size, time_t value, const char *default_unit) {
if(!default_unit) default_unit = "s";
return duration_from_nsec_t(dst, size, value * NSEC_PER_SEC, default_unit);
}

// --------------------------------------------------------------------------------------------------------------------
// timeframe
/*
TIMEFRAME timeframe_parse(const char *txt) {
if(!txt || !*txt)
return TIMEFRAME_INVALID;

char buf[strlen(txt) + 1];
memcpy(buf, txt, strlen(txt) + 1);
char *s = trim_all(buf);
if(!s)
return TIMEFRAME_INVALID;

while(isspace(*s)) s++;

if(strcasecmp(s, "this minute") == 0) {
return (TIMEFRAME) {
.after = API_RELATIVE_TIME_THIS_MINUTE,
.before = 0,
};
}
if(strcasecmp(s, "this hour") == 0) {
return (TIMEFRAME) {
.after = API_RELATIVE_TIME_THIS_HOUR,
.before = 0,
};
}
if(strcasecmp(s, "today") == 0) {
return (TIMEFRAME) {
.after = API_RELATIVE_TIME_TODAY,
.before = 0,
};
}
if(strcasecmp(s, "this week") == 0) {
return (TIMEFRAME) {
.after = API_RELATIVE_TIME_THIS_WEEK,
.before = 0,
};
}
if(strcasecmp(s, "this month") == 0) {
return (TIMEFRAME) {
.after = API_RELATIVE_TIME_THIS_MONTH,
.before = 0,
};
}
if(strcasecmp(s, "this year") == 0) {
return (TIMEFRAME) {
.after = API_RELATIVE_TIME_THIS_YEAR,
.before = 0,
};
}

if(strcasecmp(s, "last minute") == 0) {
return (TIMEFRAME) {
.after = -60,
.before = API_RELATIVE_TIME_THIS_MINUTE,
};
}
if(strcasecmp(s, "last hour") == 0) {
return (TIMEFRAME) {
.after = -3600,
.before = API_RELATIVE_TIME_THIS_HOUR,
};
}
if(strcasecmp(s, "yesterday") == 0) {
return (TIMEFRAME) {
.after = -86400,
.before = API_RELATIVE_TIME_TODAY,
};
}
if(strcasecmp(s, "this week") == 0) {
return (TIMEFRAME) {
.after = -86400 * 7,
.before = API_RELATIVE_TIME_THIS_WEEK,
};
}
if(strcasecmp(s, "this month") == 0) {
return (TIMEFRAME) {
.after = API_RELATIVE_TIME_LAST_MONTH,
.before = API_RELATIVE_TIME_THIS_MONTH,
};
}
if(strcasecmp(s, "this year") == 0) {
return (TIMEFRAME) {
.after = API_RELATIVE_TIME_LAST_YEAR,
.before = API_RELATIVE_TIME_THIS_YEAR,
};
}

const char *end;
double after = strtondd(s, (char **)&end);

if(end == s)
return TIMEFRAME_INVALID;

s = end;
while(isspace(*s)) s++;

time_t multiplier = 1;
if(!isdigit(*s) && *s != '-') {
// after has units
bool found = false;

for (size_t i = 0; i < sizeof(units) / sizeof(units[0]); i++) {
size_t len = strlen(units[i].unit);

if (units[i].multiplier >= 1 * NSEC_PER_USEC &&
strncmp(s, units[i].unit, len) == 0 &&
(isspace(s[len]) || s[len] == '-')) {
multiplier = units[i].multiplier / NSEC_PER_SEC;
found = true;
s += len;
}
}

if(!found)
return TIMEFRAME_INVALID;
}

const char *dash = strchr(s, '-');
if(!dash) return TIMEFRAME_INVALID;

}
*/