Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
writers.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 Backend output functions.
24 *
25 * The writers all take a vector of cdrel_value objects and write them to the output
26 * file or database.
27 *
28 */
29
30#include "cdrel.h"
31
32/*
33 * We can save some time and ast_str memory allocation work by allocating a single
34 * thread-local buffer and re-using it.
35 */
37
38/*!
39 * \internal
40 * \brief Write a record to a text file
41 *
42 * Besides being used here, this function is also used by the legacy loggers
43 * that shortcut the advanced stuff.
44 *
45 * \param config The configuration object.
46 * \param record The data to write.
47 * \retval 0 on success
48 * \retval -1 on failure
49 */
50int write_record_to_file(struct cdrel_config *config, struct ast_str *record)
51{
52 FILE *out;
53 int res = 0;
54
55 ast_mutex_lock(&config->lock);
56 if ((out = fopen(config->output_filename, "a"))) {
57 res = fputs(ast_str_buffer(record), out);
58 fputs("\n", out);
59 fclose(out);
60 }
62
63 if (!out || res < 0) {
64 ast_log(LOG_ERROR, "Unable to write %s to file %s : %s\n",
65 RECORD_TYPE_STR(config->record_type), config->output_filename, strerror(errno));
66 return -1;
67 }
68 return 0;
69}
70
71/*!
72 * \internal
73 * \brief Concatenate and append a list of values to an ast_str
74 *
75 * \param config Config object
76 * \param values A vector of values
77 * \param str The ast_str to append to
78 * \retval 0 on success
79 * \retval -1 on failure
80 */
81static int dsv_appender(struct cdrel_config *config, struct cdrel_values *values, struct ast_str **str)
82{
83 int ix = 0;
84 int res = 0;
85
86 for (ix = 0; ix < AST_VECTOR_SIZE(values); ix++) {
88 ast_assert(value->data_type == cdrel_type_string);
89
90 res = ast_str_append(str, -1, "%s%s", ix == 0 ? "" : config->separator, value->values.string);
91 if (res < 0) {
92 return -1;
93 }
94 }
95
96 return res;
97}
98
99/*!
100 * \internal
101 * \brief Write a DSV list of values to a text file
102 *
103 * \param config Config object
104 * \param values A vector of values
105 * \retval 0 on success
106 * \retval -1 on failure
107 */
109{
110 int res = 0;
111 struct ast_str *str = ast_str_thread_get(&custom_buf, 1024);
112
114
115 res = dsv_appender(config, values, &str);
116 if (res < 0) {
117 return -1;
118 }
119
121}
122
123/*!
124 * \internal
125 * \brief Write a list of values as a JSON object to a text file
126 *
127 * \param config Config object
128 * \param values A vector of values
129 * \retval 0 on success
130 * \retval -1 on failure
131 *
132 * \note We are intentionally NOT using the ast_json APIs here because
133 * they're expensive and these are simple objects.
134 */
135static int json_writer(struct cdrel_config *config, struct cdrel_values *values)
136{
137 int ix = 0;
138 int res = 0;
139 /*
140 * Since JSON records include the field names, the actual record size can be quite
141 * lengthy and since the thread-local backed ast_str used by the DSV writer can't be
142 * extended, we need to use a regular, extendable ast_str.
143 */
144 RAII_VAR(struct ast_str *, str, ast_str_create(1024), ast_free);
145
146 if (!str) {
147 return -1;
148 }
149
150 ast_str_set(&str, -1, "%s", "{");
151
152 for (ix = 0; ix < AST_VECTOR_SIZE(values); ix++) {
153 struct cdrel_value *value = AST_VECTOR_GET(values, ix);
154 ast_assert(value->data_type == cdrel_type_string);
155
156 res = ast_str_append(&str, -1, "%s\"%s\":%s", ix == 0 ? "" : config->separator, value->field_name, value->values.string);
157 if (res < 0) {
158 return -1;
159 }
160 }
161 ast_str_append(&str, -1, "%s", "}");
162
164}
165
166/*!
167 * \internal
168 * \brief Write a record to a database
169 *
170 * Besides being used here, this function is also used by the legacy loggers
171 * that shortcut the advanced stuff.
172 *
173 * \param config The configuration object.
174 * \param record The data to write.
175 * \retval 0 on success
176 * \retval -1 on failure
177 */
179{
180 int res = 0;
181 int ix;
182
183 ast_mutex_lock(&config->lock);
184 for (ix = 0; ix < AST_VECTOR_SIZE(values); ix++) {
185 struct cdrel_value *value = AST_VECTOR_GET(values, ix);
186 ast_assert(value->data_type == cdrel_type_string);
187 ast_debug(6, "%s '%s'\n", value->field_name, value->values.string);
188 res = sqlite3_bind_text(config->insert, ix + 1, value->values.string, -1, SQLITE_STATIC);
189 if (res != SQLITE_OK) {
190 ast_log(LOG_ERROR, "Unable to write %s to database %s. SQL bind for field %s:'%s'. Error: %s\n",
191 RECORD_TYPE_STR(config->record_type), config->output_filename,
192 value->field_name, value->values.string,
193 sqlite3_errmsg(config->db));
194 sqlite3_reset(config->insert);
195 ast_mutex_unlock(&config->lock);
196 return -1;
197 }
198 }
199
200 res = sqlite3_step(config->insert);
201 if (res != SQLITE_DONE) {
202 ast_log(LOG_ERROR, "Unable to write %s to database %s. Error: %s\n",
203 RECORD_TYPE_STR(config->record_type), config->output_filename,
204 sqlite3_errmsg(config->db));
205 sqlite3_reset(config->insert);
206 ast_mutex_unlock(&config->lock);
207 return -1;
208 }
209
210 sqlite3_reset(config->insert);
211 ast_mutex_unlock(&config->lock);
212
213 return res;
214}
215
216/*!
217 * \internal
218 * \brief Write a list of values to a database
219 *
220 * \param config Config object
221 * \param values A vector of values
222 * \retval 0 on success
223 * \retval -1 on failure
224 */
226{
228}
229
239
const char * str
Definition app_jack.c:150
#define ast_free(a)
Definition astmm.h:180
#define ast_log
Definition astobj2.c:42
Private header for res_cdrel_custom.
@ cdrel_type_string
Definition cdrel.h:73
#define RECORD_TYPE_STR(_rt)
Definition cdrel.h:42
@ cdrel_format_json
Definition cdrel.h:49
@ cdrel_format_dsv
Definition cdrel.h:48
@ cdrel_format_sql
Definition cdrel.h:50
cdrel_backend_writer cdrel_backend_writers[cdrel_format_type_end]
static const char config[]
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_mutex_unlock(a)
Definition lock.h:197
#define ast_mutex_lock(a)
Definition lock.h:196
int errno
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
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition strings.h:693
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition strings.h:909
Support for dynamic strings.
Definition strings.h:623
union cdrel_value::@454 values
int value
Definition syslog.c:37
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
FILE * out
Definition utils/frame.c:33
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:637
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:708
static int dsv_writer(struct cdrel_config *config, struct cdrel_values *values)
Definition writers.c:108
int write_record_to_database(struct cdrel_config *config, struct cdrel_values *values)
Definition writers.c:178
int write_record_to_file(struct cdrel_config *config, struct ast_str *record)
Definition writers.c:50
static int json_writer(struct cdrel_config *config, struct cdrel_values *values)
Definition writers.c:135
static int database_writer(struct cdrel_config *config, struct cdrel_values *values)
Definition writers.c:225
static int dsv_appender(struct cdrel_config *config, struct cdrel_values *values, struct ast_str **str)
Definition writers.c:81
int load_writers(void)
Definition writers.c:230