Asterisk - The Open Source Telephony Project GIT-master-80b953f
Loading...
Searching...
No Matches
res_cdrel_custom.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2026, Sangoma Technologies Corporation
5 *
6 * George Joseph <gjoseph@sangoma.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*!
20 * \file
21 * \author George Joseph <gjoseph@sangoma.com>
22 *
23 * \brief Common logic for the CDR and CEL Custom Backends
24 *
25 * All source files are in the res/cdrel_custom directory.
26 *
27 * "config.c": Contains common configuration file parsing the ultimate goal
28 * of which is to create a vector of cdrel_config structures for each of
29 * the cdr_custom, cdr_sqlite3_custom, cel_custom and cel_sqlite3_custom
30 * modules. Each cdrel_config object represents an output file defined in
31 * their respective config files. Each one contains a vector of cdrel_field
32 * objects, one for each field in the output record, plus settings like
33 * the output file name, backend type (text file or database), config
34 * type ((legacy or advanced), the field separator and quote character to
35 * use.
36 *
37 * Each cdrel_field object contains an abstract field id that points to
38 * a ast_cdr structure member or CEL event field id along with an input
39 * type and an output type. The registry of cdrel_fields is located in
40 * registry.c.
41 *
42 * "loggers.c": Contains the common "cdrel_logger" entrypoint that the
43 * individual modules call to log a record. It takes the module's
44 * cdrel_configs vector and the record to log it got from the core
45 * cel.c and cdr.c. It then looks up and runs the logger implementation
46 * based on the backend type (text file or database) and config type
47 * (legacy or advanced).
48 *
49 * "getters_cdr.c", "getters_cel.c": Contain the getters that retrieve
50 * values from the ast_cdr or ast_event structures based on the field
51 * id and input type defined for that field and create a cdrel_value
52 * wrapper object for it.
53 *
54 * "writers.c": Contains common backend writers for the text file and
55 * database backends.
56 *
57 * The load-time flow...
58 *
59 * Each of the individual cdr/cel custom modules call the common
60 * cdrel_load_module function with their backend_type, record_type
61 * (cdr or cel), config file name, and the logging callback that
62 * should be registered with the core cdr or cel facility.
63 *
64 * cdrel_load_module calls the config load function appropriate for
65 * the backend type, each of which parses the config file and, if
66 * successful, registers the calling module with the cdr or cel core
67 * and creates a vector of cdrel_config objects that is passed
68 * back to the calling module. That vector contains the context for
69 * all future operations.
70 *
71 * The run-time flow...
72 *
73 * The core cdr and cel modules use their registries of backends and call
74 * the callback function registered by the 4 cdr and cel custom modules.
75 * No changes there.
76 *
77 * Each of those modules call the common cdrel_logger function with their
78 * cdrel_configs vector and the actual ast_cdr or ast_event structure to log.
79 * The cdrel_logger function iterates over the cdrel_configs vector and for
80 * each invokes the logger implementation specific to the backend type
81 * (text file or database) and config type (legacy or advanced).
82 *
83 * For legacy config types, the logger implementation simply calls
84 * ast_str_substitute_variables() on the whole opaque format and writes
85 * the result to the text file or database.
86 *
87 * For advanced configs, the logger implementation iterates over each field
88 * in the cdrel_config's fields vector and for each, calls the appropriate
89 * getter based on the record type (cdr or cel) and field id. Each getter
90 * call returns a cdrel_value object which is then passed to a field formatter
91 * looked up based on the field's data type (string, int32, etc). The formatter
92 * is also passed the cdrel_config object and the desired output type and
93 * returns the final value in another cdrel_value object formatted with any
94 * quoting, etc. needed. The logger accumulates the output cdrel_values
95 * (which are all now strings) in another vector and after all fields have
96 * been processed, hands the vector over to one of the backend writers.
97 *
98 * The backend writer concatenates the cdrel_values into an output record
99 * using the config's separator setting and writes it to the text file
100 * or database. For the JSON output format, it creates a simple
101 * name/value pair output record.
102 *
103 * The identification of field data types, field ids, record types and
104 * backend types is all done at config load time and saved in the
105 * cdrel_config and cdrel_field objects. The callbacks for getters, formatters
106 * and writers are also loaded when the res_cdrel_custom module loads
107 * and stored in arrays indexed by their enum values. The result is that
108 * at run time, simple array indexing is all that's needed to get the
109 * proper getter, formatter and writer for any logging request.
110 *
111 */
112
113/*** MODULEINFO
114 <depend>sqlite3</depend>
115 <support_level>core</support_level>
116 ***/
117
118
119#include "asterisk.h"
120
121#include "asterisk/module.h"
122#include "cdrel_custom/cdrel.h"
123
124/*
125 * Populated by cdrel_custom/getters_cdr.c and cdrel_custom/getters_cel.c.
126 */
128
129/*
130 * Populated by cdrel_custom/formatters.c.
131 */
133
134/*
135 * Populated by cdrel_custom/writers.c.
136 */
138
139/*
140 * Populated by cdrel_custom/getters_cdr.c and cdrel_custom/getters_cel.c.
141 */
143
144/*
145 * You must ensure that there's an entry for every value in the enum.
146 */
147
148const char *cdrel_record_type_map[] = {
149 [cdrel_record_cdr] = "CDR",
150 [cdrel_record_cel] = "CEL",
151 [cdrel_record_type_end] = "!!END!!",
152};
153
154const char *cdrel_module_type_map[] = {
155 [cdrel_backend_text] = "Custom ",
156 [cdrel_backend_db] = "SQLITE3 Custom",
157 [cdrel_backend_type_end] = "!!END!!",
158};
159
160const char *cdrel_data_type_map[] = {
161 [cdrel_type_string] = "string",
162 [cdrel_type_timeval] = "timeval",
163 [cdrel_type_literal] = "literal",
164 [cdrel_type_amaflags] = "amaflags",
165 [cdrel_type_disposition] = "disposition",
166 [cdrel_type_uservar] = "uservar",
167 [cdrel_type_event_type] = "event_type",
168 [cdrel_type_event_enum] = "event_enum",
169 [cdrel_type_cel_timefmt] = "cel_timefmt",
170 [cdrel_data_type_strings_end] = "!!STRINGS END!!",
171 [cdrel_type_int32] = "int32",
172 [cdrel_type_uint32] = "uint32",
173 [cdrel_type_int64] = "int64",
174 [cdrel_type_uint64] = "uint64",
175 [cdrel_type_double] = "double",
176 [cdrel_data_type_end] = "!!END!!",
177};
178
180{
181 enum cdrel_data_type data_type = 0;
182 for (data_type = 0; data_type < cdrel_data_type_end; data_type++) {
183 if (strcasecmp(cdrel_data_type_map[data_type], str) == 0) {
184 return data_type;
185 }
186
187 }
188 return cdrel_data_type_end;
189}
190
191static const char *cdrel_field_flags_map[] = {
192 [CDREL_FIELD_FLAG_QUOTE] = "quote",
193 [CDREL_FIELD_FLAG_NOQUOTE] = "noquote",
194 [CDREL_FIELD_FLAG_TYPE_FORCED] = "type_forced",
195 [CDREL_FIELD_FLAG_USERVAR] = "uservar",
196 [CDREL_FIELD_FLAG_LITERAL] = "literal",
197 [CDREL_FIELD_FLAG_FORMAT_SPEC] = "format_spec",
198 [CDREL_FIELD_FLAG_LAST] = "LAST",
199};
200
201const char *cdrel_get_field_flags(struct ast_flags *flags, struct ast_str **str)
202{
203 int ix = 0;
204 int res = 0;
205 int trues = 0;
206
207 for (ix = 0; ix < CDREL_FIELD_FLAG_LAST; ix++) {
208 if (ast_test_flag(flags, (1 << ix))) {
209 res = ast_str_append(str, -1, "%s%s", trues++ ? "," : "", cdrel_field_flags_map[ix]);
210 if (res < 0) {
211 return "";
212 }
213 }
214 }
215 return ast_str_buffer(*str);
216}
217
218
219const char *cdrel_basename(const char *path)
220{
221 int i = 0;
222 const char *basename = path;
223
224 if (ast_strlen_zero(path)) {
225 return path;
226 }
227 i = strlen(path) - 1;
228 while(i >= 0) {
229 if (path[i] == '/') {
230 basename = &path[i + 1];
231 break;
232 }
233 i--;
234 }
235 return basename;
236}
237
238static int unload_module(void)
239{
240 return 0;
241}
242
244{
245 load_cdr();
246 load_cel();
248 load_writers();
250}
251
253 "Combined logic for CDR/CEL Custom modules",
254 .support_level = AST_MODULE_SUPPORT_CORE,
255 .load = load_module,
256 .unload = unload_module,
257 .load_pri = AST_MODPRI_CDR_DRIVER,
const char * str
Definition app_jack.c:150
Asterisk main include file. File version handling, generic pbx functions.
Private header for res_cdrel_custom.
int load_cel(void)
int(* cdrel_field_formatter)(struct cdrel_config *config, struct cdrel_field *field, struct cdrel_value *input_value, struct cdrel_value *output_value)
Definition cdrel.h:226
#define CDREL_FIELD_FLAG_USERVAR
Definition cdrel.h:98
#define CDREL_FIELD_FLAG_LITERAL
Definition cdrel.h:99
#define CDREL_FIELD_FLAG_LAST
Definition cdrel.h:101
int load_cdr(void)
struct ast_channel *(* cdrel_dummy_channel_alloc)(struct cdrel_config *config, void *record)
Definition cdrel.h:265
#define CDREL_FIELD_FLAG_TYPE_FORCED
Definition cdrel.h:97
cdrel_data_type
Definition cdrel.h:72
@ cdrel_type_event_type
Definition cdrel.h:79
@ cdrel_data_type_strings_end
Definition cdrel.h:82
@ cdrel_type_cel_timefmt
Definition cdrel.h:81
@ cdrel_type_amaflags
Definition cdrel.h:76
@ cdrel_type_event_enum
Definition cdrel.h:80
@ cdrel_type_disposition
Definition cdrel.h:77
@ cdrel_type_uint64
Definition cdrel.h:86
@ cdrel_type_uservar
Definition cdrel.h:78
@ cdrel_type_double
Definition cdrel.h:87
@ cdrel_type_int64
Definition cdrel.h:85
@ cdrel_type_literal
Definition cdrel.h:75
@ cdrel_type_int32
Definition cdrel.h:83
@ cdrel_type_string
Definition cdrel.h:73
@ cdrel_data_type_end
Definition cdrel.h:88
@ cdrel_type_timeval
Definition cdrel.h:74
@ cdrel_type_uint32
Definition cdrel.h:84
#define CDREL_FIELD_FLAG_FORMAT_SPEC
Definition cdrel.h:100
@ cdrel_format_type_end
Definition cdrel.h:51
#define CDREL_FIELD_FLAG_QUOTE
Definition cdrel.h:95
int load_formatters(void)
Definition formatters.c:189
int(* cdrel_field_getter)(void *record, struct cdrel_config *config, struct cdrel_field *field, struct cdrel_value *value)
Definition cdrel.h:205
int(* cdrel_backend_writer)(struct cdrel_config *config, struct cdrel_values *values)
Definition cdrel.h:245
int load_writers(void)
Definition writers.c:221
#define CDREL_FIELD_FLAG_NOQUOTE
Definition cdrel.h:96
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition module.h:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition module.h:330
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition module.h:557
@ AST_MODPRI_CDR_DRIVER
Definition module.h:345
@ AST_MODULE_SUPPORT_CORE
Definition module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
ast_module_load_result
Definition module.h:68
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
const char * cdrel_basename(const char *path)
enum cdrel_data_type cdrel_data_type_from_str(const char *str)
static const char * cdrel_field_flags_map[]
static enum ast_module_load_result load_module(void)
cdrel_field_formatter cdrel_field_formatters[cdrel_data_type_end]
static int unload_module(void)
const char * cdrel_module_type_map[]
cdrel_dummy_channel_alloc cdrel_dummy_channel_allocators[cdrel_format_type_end]
cdrel_backend_writer cdrel_backend_writers[cdrel_format_type_end]
cdrel_field_getter cdrel_field_getters[cdrel_record_type_end][cdrel_data_type_end]
const char * cdrel_data_type_map[]
const char * cdrel_record_type_map[]
const char * cdrel_get_field_flags(struct ast_flags *flags, struct ast_str **str)
@ cdrel_backend_db
@ cdrel_backend_text
@ cdrel_backend_type_end
@ cdrel_record_cel
@ cdrel_record_cdr
@ cdrel_record_type_end
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
Structure used to handle boolean flags.
Definition utils.h:220
Support for dynamic strings.
Definition strings.h:623
#define ast_test_flag(p, flag)
Definition utils.h:64