]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_cdrel_custom: Resolve several formatting issues.
authorGeorge Joseph <gjoseph@sangoma.com>
Tue, 31 Mar 2026 16:16:48 +0000 (10:16 -0600)
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Wed, 1 Apr 2026 19:16:21 +0000 (19:16 +0000)
Several issues are resolved:

* Internally, floats were used for timestamp values but this could result
in wrapping so they've been changed to doubles.

* Historically, the default CEL eventtime format is `<seconds>.<microseconds>`
with `<microseconds>` always being 6 digits.  This should have continued to be
the case but res_cdrel_custom wasn't checking the `dateformat` setting in
cel.conf and was defaulting to `%F %T`.  res_cdrel_custom now gets the default
date format from cel.conf, which will be whatever the `dateformat` parameter
is set to or `<seconds>.<microseconds>` if not set.

* The timeval field formatter for both CDR and CEL wasn't handling custom
strftime format strings correctly.  This is now fixed so you should be able
to specifiy custom strftime format strings for the CEL `eventtime` and CDR
`start`, `answer` and `end` fields.  For example: `eventtime(%FT%T%z)`.

Resolves: #1844
Resolves: #1845

configs/samples/cdr_custom.conf.sample
configs/samples/cel_custom.conf.sample
res/cdrel_custom/cdrel.h
res/cdrel_custom/config.c
res/cdrel_custom/formatters.c
res/cdrel_custom/getters_cdr.c
res/cdrel_custom/registry.c
res/res_cdrel_custom.c

index 760c039ebab3f174b4992e235b8ad8417f8d0271..3a120428a3bded6caa446d85f158696e1c26d323 100644 (file)
     ;
     ; The default output format for the "start", "answer" and "end" timestamp fields
     ; is the "%Y-%m-%d %T" strftime string format however you can also format those
-    ; fields as an int64 or a float: `start(int64),answer(float),end`.
+    ; fields as an int64 or a double: `start(int64)` or `start(double)` or
+    ; provide your own strftime format string: `start(%FT%T%z)`.
     ;
     ; The "disposition" and "amaflags" are formatted as their string names like
     ; "ANSWERED" and "DOCUMENTATION" by default but if you just want the numbers and
index 03debc6e2939c4b00d9ea2d403e764e4c78bf9d1..e025dd6bf194223c1fbcdf6cb43f403d4eb20494 100644 (file)
     ; you can force the uniqueid field to not be quoted with `uniqueid(noquote)`. The
     ; example in fields above shows this.
     ;
-    ; The default output format for the "EventTime" timestamp field is the "%Y-%m-%d %T"
-    ; strftime string format however you can also format the field as an int64 or a
-    ; float: `eventtime(int64)` or `eventtime(float)`.
+    ; The default output format for the "EventTime" timestamp field is taken from the
+    ; "dateformat" parameter in cel.conf.  If that's not set, the default is
+    ; "<seconds>.<microseconds>" where "<microseconds>" is always 6 digits with
+    ; leading zeros.  You can also format the field as an int64 or a double:
+    ; `eventtime(int64)` or `eventtime(double)` or provide your own strftime
+    ; format string: `eventtime(%FT%T%z)`.
     ;
     ; Unlike CDRs, the "amaflags" field is output as its numerical value by default
     ; for historical reasons.  You can output it as its friendly string with
index 84787840e9a63cc8c464e19c6105c46b334d856e..e1542b7db4c8aa53a1a09b555780ee61ba2b96a8 100644 (file)
@@ -78,12 +78,13 @@ enum cdrel_data_type {
        cdrel_type_uservar,
        cdrel_type_event_type,
        cdrel_type_event_enum,
+       cdrel_type_cel_timefmt,
        cdrel_data_type_strings_end,
        cdrel_type_int32,
        cdrel_type_uint32,
        cdrel_type_int64,
        cdrel_type_uint64,
-       cdrel_type_float,
+       cdrel_type_double,
        cdrel_data_type_end
 };
 
@@ -180,7 +181,7 @@ struct cdrel_value {
                int64_t int64;
                uint64_t uint64;
                struct timeval tv;
-               float floater;
+               double doubler;
        } values;
 };
 
index d4655f0792c19880ff993df78b859b11a40b6808..49543df3d289e12731b10fcb7715ac17f5c54b13 100644 (file)
@@ -432,6 +432,7 @@ static struct cdrel_field *field_alloc(struct cdrel_config *config, const char *
                        if (strchr(qualifier, '%') != NULL) {
                                data_swap = ast_strdupa(qualifier);
                                ast_set_flag(&field_flags, cdrel_flag_format_spec);
+                               forced_output_data_type = cdrel_type_string;
                                ast_debug(3, "   Using qualifier '%s' for field '%s' flags: %s\n", qualifier,
                                        field_name, ast_str_tmp(128, cdrel_get_field_flags(&field_flags, &STR_TMP)));
                        }
@@ -466,6 +467,17 @@ static struct cdrel_field *field_alloc(struct cdrel_config *config, const char *
                return NULL;
        }
 
+       if (ast_test_flag(&field_flags, cdrel_flag_format_spec)
+               && registered_field->input_data_type != cdrel_type_timeval) {
+               ast_log(LOG_WARNING, "%s->%s: Custom format '%s' ignored for field '%s'."
+                       " Only timeval types can use custom format strings.\n",
+                       cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
+                       data, field_name);
+               forced_output_data_type = cdrel_data_type_end;
+               ast_clear_flag(&field_flags, cdrel_flag_format_spec);
+               data = NULL;
+       }
+
        field = ast_calloc(1, sizeof(*registered_field) + strlen(input_field_template) + 1);
        if (!field) {
                return NULL;
@@ -1127,7 +1139,7 @@ static struct cdrel_config *load_text_file_legacy_config(enum cdrel_record_type
                return NULL;
        }
 
-       ast_log(LOG_NOTICE, "%s->%s: Logging %s records\n",
+       ast_log(LOG_NOTICE, "%s->%s: Logging legacy %s records as advanced\n",
                cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
                RECORD_TYPE_STR(config->record_type));
 
index fc4e22a5dcfa7a933b7c54b705e6b5508af85e90..2be6d26cb62cfce306f10ee02b424e74099a232e 100644 (file)
@@ -118,7 +118,7 @@ DEFINE_FORMATTER(uint32, uint32, uint32_t, "%u")
 DEFINE_FORMATTER(int32, int32, int32_t, "%d")
 DEFINE_FORMATTER(uint64, uint64, uint64_t, "%lu")
 DEFINE_FORMATTER(int64, int64, int64_t, "%ld")
-DEFINE_FORMATTER(float, floater, float, "%.1f")
+DEFINE_FORMATTER(double, doubler, double, "%.6f")
 
 static int format_timeval(struct cdrel_config *config,
        struct cdrel_field *field, struct cdrel_value *input_value, struct cdrel_value *output_value)
@@ -134,11 +134,20 @@ static int format_timeval(struct cdrel_config *config,
                output_value->data_type = cdrel_type_int64;
                output_value->values.int64 = input_value->values.tv.tv_sec;
                return format_int64(config, field, output_value, output_value);
-       } else if (field->output_data_type == cdrel_type_float) {
-               output_value->data_type = cdrel_type_float;
-               output_value->values.floater = ((float)input_value->values.tv.tv_sec) + ((float)input_value->values.tv.tv_usec) / 1000000.0;
-               return format_float(config, field, output_value, output_value);
-       } else  if (!ast_strlen_zero(field->data)) {
+       } else if (field->output_data_type == cdrel_type_double) {
+               output_value->data_type = cdrel_type_double;
+               output_value->values.doubler = ((double)input_value->values.tv.tv_sec) + ((double)input_value->values.tv.tv_usec) / 1000000.0;
+               return format_double(config, field, output_value, output_value);
+       } else if (field->output_data_type == cdrel_type_cel_timefmt) {
+               res = ast_cel_format_eventtime(input_value->values.tv, tempbuf, 64);
+               if (res != 0) {
+                       return res;
+               }
+               input_value->values.string = tempbuf;
+               input_value->data_type = cdrel_type_string;
+               output_value->data_type = cdrel_type_string;
+               return format_string(config, field, input_value, output_value);
+       } else if (!ast_strlen_zero(field->data)) {
                format = field->data;
        }
 
@@ -186,7 +195,7 @@ int load_formatters(void)
        cdrel_field_formatters[cdrel_type_int64] = format_int64;
        cdrel_field_formatters[cdrel_type_uint64] = format_uint64;
        cdrel_field_formatters[cdrel_type_timeval] = format_timeval;
-       cdrel_field_formatters[cdrel_type_float] = format_float;
+       cdrel_field_formatters[cdrel_type_double] = format_double;
        cdrel_field_formatters[cdrel_type_amaflags] = format_amaflags;
        cdrel_field_formatters[cdrel_type_disposition] = format_disposition;
 
index 45667db57ee84ecffab44525fb1a07cfef01208d..8e87cb25a12d49a6d9ab8c9e41dcea28cebf4b8f 100644 (file)
@@ -53,7 +53,7 @@ DEFINE_CDR_GETTER(uint32, uint32, uint32_t)
 DEFINE_CDR_GETTER(int64, int64, int64_t)
 DEFINE_CDR_GETTER(uint64, uint64, uint64_t)
 DEFINE_CDR_GETTER(tv, timeval, struct timeval)
-DEFINE_CDR_GETTER(floater, float, float)
+DEFINE_CDR_GETTER(doubler, double, double)
 
 static int cdr_get_literal(void *record, struct cdrel_config *config,
        struct cdrel_field *field, struct cdrel_value *value)
@@ -108,7 +108,7 @@ int load_cdr(void)
        cdrel_field_getters[cdrel_record_cdr][cdrel_type_int64] = cdr_get_int64;
        cdrel_field_getters[cdrel_record_cdr][cdrel_type_uint64] = cdr_get_uint64;
        cdrel_field_getters[cdrel_record_cdr][cdrel_type_timeval] = cdr_get_timeval;
-       cdrel_field_getters[cdrel_record_cdr][cdrel_type_float] = cdr_get_float;
+       cdrel_field_getters[cdrel_record_cdr][cdrel_type_double] = cdr_get_double;
        cdrel_field_getters[cdrel_record_cdr][cdrel_type_uservar] = cdr_get_uservar;
        cdrel_dummy_channel_allocators[cdrel_record_cdr] = dummy_chan_alloc_cdr;
 
index 472b147c45bf849a8081212c1c346dd15c8e65e6..da678aee03523ba9486ff7cd4abbf27a942eb31d 100644 (file)
@@ -47,7 +47,7 @@
 static const struct cdrel_field cdrel_field_registry[] = {
        REGISTER_FIELD(cdrel_record_cel, AST_EVENT_IE_CEL_EVENT_ENUM, "eventenum", cdrel_type_event_enum, cdrel_type_string),
        REGISTER_FIELD(cdrel_record_cel, AST_EVENT_IE_CEL_EVENT_TYPE, "eventtype", cdrel_type_event_type, cdrel_type_string),
-       REGISTER_FIELD(cdrel_record_cel, AST_EVENT_IE_CEL_EVENT_TIME, "eventtime", cdrel_type_timeval, cdrel_type_string),
+       REGISTER_FIELD(cdrel_record_cel, AST_EVENT_IE_CEL_EVENT_TIME, "eventtime", cdrel_type_timeval, cdrel_type_cel_timefmt),
        REGISTER_FIELD(cdrel_record_cel, AST_EVENT_IE_CEL_EVENT_TIME_USEC, "eventtimeusec", cdrel_type_uint32, cdrel_type_uint32),
        REGISTER_FIELD(cdrel_record_cel, AST_EVENT_IE_CEL_USEREVENT_NAME, "usereventname", cdrel_type_string, cdrel_type_string),
        REGISTER_FIELD(cdrel_record_cel, AST_EVENT_IE_CEL_USEREVENT_NAME, "userdeftype", cdrel_type_string, cdrel_type_string),
index 179db87acccc97c14a97af1406dad60ea974c370..773007a345f217b208d0a032bf1414232a3f6311 100644 (file)
@@ -166,12 +166,13 @@ const char *cdrel_data_type_map[] = {
        [cdrel_type_uservar] = "uservar",
        [cdrel_type_event_type] = "event_type",
        [cdrel_type_event_enum] = "event_enum",
+       [cdrel_type_cel_timefmt] = "cel_timefmt",
        [cdrel_data_type_strings_end] = "!!STRINGS END!!",
        [cdrel_type_int32] = "int32",
        [cdrel_type_uint32] = "uint32",
        [cdrel_type_int64] = "int64",
        [cdrel_type_uint64] = "uint64",
-       [cdrel_type_float] = "float",
+       [cdrel_type_double] = "double",
        [cdrel_data_type_end] = "!!END!!",
 };