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

Time releated fixes #466

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Time releated fixes #466

wants to merge 6 commits into from

Conversation

bshifter
Copy link
Member

A bunch of datetime releated fixes:

  • dump functions for wallclock time and unixtime (they were extermely useful, so i kept them)
  • fix: filterx datetime string formatting error: unnecessary dash removed
  • prepartion for nano second precision support: timeutils/misc extended, typo fixed
  • fix: unix_time_to_unix_epoch calculation
  • fix: otel nanosecond-precision fields setter/getter
  • unit test for otel nanosec precision and timezone information

@@ -69,8 +69,6 @@ _convert_unix_time_to_string(const UnixTime *ut, GString *result, gboolean inclu
{
if (ut->ut_gmtoff >= 0)
g_string_append_c(result, '+');
else
g_string_append_c(result, '-');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch. a unit test for this would be great somewhere.

@@ -69,6 +69,37 @@ unix_time_is_timezone_set(const UnixTime *self)
return self->ut_gmtoff != -1;
}

static inline
void dump_unix_time(const UnixTime *ut, GString *output)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you move the return value type to the previous line? that's the convention we are using, e.g.

static inline void
dump_unix_time(...)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, we might hide this in the .c file, I don't see why this should be inline.

#else
g_string_append_printf(output, " GMT Offset: %ld\n", wct->wct_gmtoff);
g_string_append_printf(output, " Timezone: %s\n", wct->wct_zone ? wct->wct_zone : "(null)");
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the difference in these two cases. The idea was to always have wct_gmtoff and wct_zone in WallClockTime so that we have those on all platforms. I don't think we need the conditional compilation.

@@ -124,6 +124,33 @@ struct _WallClockTime

#endif

static inline
void dump_wall_clock_time(const WallClockTime *wct, GString *output)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, this can go to the implementation file and please move "void" to the previous line.

@@ -371,7 +371,7 @@ guint64
unix_time_to_unix_epoch(const UnixTime ut)
Copy link
Member

@bazsi bazsi Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function name is misleading for me. I know this patch does not introduce these, but for me "time since unix epoch" is in seconds and not in any particular resolution (msec, usecs or nsecs).

I would rename these to unix_time_from_unix_epoch_usec() and unix_time_to_unix_epoch_usec() to show the
granularity.

Later (if needed we can add the sec/msec/nsec variants as well).

@@ -371,7 +371,7 @@ guint64
unix_time_to_unix_epoch(const UnixTime ut)
{
gint32 gmtoff = (ut.ut_gmtoff != - 1) ? ut.ut_gmtoff : 0;
return (guint64)((ut.ut_sec + gmtoff) * USEC_PER_SEC + ut.ut_usec);
return (guint64)((ut.ut_sec - gmtoff) * USEC_PER_SEC + ut.ut_usec);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unit tests for this would be dearly needed.

@@ -269,7 +272,7 @@ class OtelDatetimeConverter : public ProtobufField
FilterXObject *FilterXObjectGetter(Message *message, ProtoReflectors reflectors)
{
uint64_t val = reflectors.reflection->GetUInt64(*message, reflectors.fieldDescriptor);
UnixTime utime = unix_time_from_unix_epoch(val);
UnixTime utime = unix_time_from_unix_epoch(NSEC_TO_USEC(val));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with this, I'd probably introduce the unix_time_from_unix_epoch_nsec() function, so we can push the NSEC_TO_USEC to be within the function body and not here.

@@ -279,7 +282,7 @@ class OtelDatetimeConverter : public ProtobufField
if (filterx_object_extract_datetime(object, &utime))
{
uint64_t unix_epoch = unix_time_to_unix_epoch(utime);
reflectors.reflection->SetUInt64(message, reflectors.fieldDescriptor, unix_epoch);
reflectors.reflection->SetUInt64(message, reflectors.fieldDescriptor, unix_epoch * NSEC_PER_USEC);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

likewise, unix_time_unix_epoch_nsec() could do the multiplication

Removed unnecessary `-` to prevent double dashes in the output.

Padding negative numbers requires some revise.

Signed-off-by: shifter <[email protected]>
@bshifter bshifter force-pushed the time-fixes branch 2 times, most recently from 7896aca to 964fb28 Compare January 24, 2025 09:56
{
gint32 gmtoff = (ut.ut_gmtoff != - 1) ? ut.ut_gmtoff : 0;
return (guint64)((ut.ut_sec + gmtoff) * USEC_PER_SEC + ut.ut_usec);
return (guint64)((ut.ut_sec - gmtoff) * USEC_PER_SEC + ut.ut_usec);
Copy link
Member

@alltilla alltilla Jan 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should subtract the GMT offset here. UnixTime's ut_sec and ut_usec fields are storing values that correspond to UTC already, the GMT offset is a hint to the original timezone. If you change the timezone in a UnixTime object, you don't need to modify ut_sec and ut_usec.

Let me demonstrate this with a config:

log {
  source { example-msg-generator(num(1)); };

  filterx {
    dt = isodate("2025-01-01T04:00:00-03:00");
    $logmsg = dt;
    $js = json({"dt": dt});
    $repr = string(dt);
    $int = int(dt);
    $double = double(dt);

    log = otel_logrecord();
    log.time_unix_nano = dt;
    $otel_dt_as_int = int(log.time_unix_nano);
    $otel_dt_as_double = double(log.time_unix_nano);

    log.attributes.int = dt;
    $otel_int = log.attributes.int;
  };

  destination {
    stdout(template("$logmsg\n$js\n$repr\n$int\n$double\n$otel_dt_as_int\n$otel_dt_as_double\n$otel_int\n"));
  };
};

$ ./install/sbin/syslog-ng -Fe
[2025-01-24T10:54:56.623207] Setting current version as config version; version='4.9'
[2025-01-24T10:54:56.623207] syslog-ng starting up; version='4.9.0.155.g8aed412.dirty'
1735714800.000000-3:00
{"dt":"1735714800.000000"}
2025-01-01T04:00:00.000-03:00
1735714800000000
1735714800
1735725600000000
1735725600
1735725600000000

From https://greenwichmeantime.com/articles/clocks/iso/ we can see that 1735714800 is the correct value.
image

We can deduce 2 things from this output:

  1. We are not using the same logic for otel and the rest of the filterx code.
  2. The otel logic is erroneous.

We should fix both. Let's fix this function and use it everywhere:

  • datetime -> logmsg (marshal())
  • datetime -> json (map_to_json())
  • datetime -> string (repr())
  • datetime -> int (typecast_integer())
  • datetime -> double (typecast_double())
  • datetime -> otel int (u64Field, i64Field)
  • datetime -> otel_datetime (OtelDatetimeConverter)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wildly agree. Sorry that I missed this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh gosh! My bad, i've missed the concept of Unixtime, and thought this was a bug whole time. Let me clean up my mess!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants