From cc5542e753aeb85c420698ab6797066ea8da8148 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 31 Mar 2026 10:16:48 -0600 Subject: [PATCH] res_cdrel_custom: Resolve several formatting issues. 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 `.` with `` 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 `.` 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 | 3 ++- configs/samples/cel_custom.conf.sample | 9 ++++++--- res/cdrel_custom/cdrel.h | 5 +++-- res/cdrel_custom/config.c | 14 +++++++++++++- res/cdrel_custom/formatters.c | 23 ++++++++++++++++------- res/cdrel_custom/getters_cdr.c | 4 ++-- res/cdrel_custom/registry.c | 2 +- res/res_cdrel_custom.c | 3 ++- 8 files changed, 45 insertions(+), 18 deletions(-) diff --git a/configs/samples/cdr_custom.conf.sample b/configs/samples/cdr_custom.conf.sample index 760c039eba..3a120428a3 100644 --- a/configs/samples/cdr_custom.conf.sample +++ b/configs/samples/cdr_custom.conf.sample @@ -106,7 +106,8 @@ ; ; 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 diff --git a/configs/samples/cel_custom.conf.sample b/configs/samples/cel_custom.conf.sample index 03debc6e29..e025dd6bf1 100644 --- a/configs/samples/cel_custom.conf.sample +++ b/configs/samples/cel_custom.conf.sample @@ -111,9 +111,12 @@ ; 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 + ; "." where "" 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 diff --git a/res/cdrel_custom/cdrel.h b/res/cdrel_custom/cdrel.h index 84787840e9..e1542b7db4 100644 --- a/res/cdrel_custom/cdrel.h +++ b/res/cdrel_custom/cdrel.h @@ -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; }; diff --git a/res/cdrel_custom/config.c b/res/cdrel_custom/config.c index d4655f0792..49543df3d2 100644 --- a/res/cdrel_custom/config.c +++ b/res/cdrel_custom/config.c @@ -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)); diff --git a/res/cdrel_custom/formatters.c b/res/cdrel_custom/formatters.c index fc4e22a5dc..2be6d26cb6 100644 --- a/res/cdrel_custom/formatters.c +++ b/res/cdrel_custom/formatters.c @@ -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; diff --git a/res/cdrel_custom/getters_cdr.c b/res/cdrel_custom/getters_cdr.c index 45667db57e..8e87cb25a1 100644 --- a/res/cdrel_custom/getters_cdr.c +++ b/res/cdrel_custom/getters_cdr.c @@ -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; diff --git a/res/cdrel_custom/registry.c b/res/cdrel_custom/registry.c index 472b147c45..da678aee03 100644 --- a/res/cdrel_custom/registry.c +++ b/res/cdrel_custom/registry.c @@ -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), diff --git a/res/res_cdrel_custom.c b/res/res_cdrel_custom.c index 179db87acc..773007a345 100644 --- a/res/res_cdrel_custom.c +++ b/res/res_cdrel_custom.c @@ -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!!", };