#include "asterisk.h"
#include "asterisk/paths.h"
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
Go to the source code of this file.
Defines | |
#define | CSV_LOG_DIR "/cdr-csv" |
#define | CSV_MASTER "/Master.csv" |
#define | DATE_FORMAT "%Y-%m-%d %T" |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | append_date (char *buf, struct timeval when, size_t bufsize) |
static int | append_int (char *buf, int s, size_t bufsize) |
static int | append_string (char *buf, const char *s, size_t bufsize) |
static int | build_csv_record (char *buf, size_t bufsize, struct ast_cdr *cdr) |
static int | csv_log (struct ast_cdr *cdr) |
static int | load_config (int reload) |
static int | load_module (void) |
static int | reload (void) |
static int | unload_module (void) |
static int | writefile (char *s, char *acc) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Comma Separated Values CDR Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } |
static int | accountlogs |
static ast_mutex_t | acf_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static const char | config [] = "cdr.conf" |
static int | loaded = 0 |
static int | loguniqueid = 0 |
static int | loguserfield = 0 |
static ast_mutex_t | mf_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
static char * | name = "csv" |
static int | usegmtime = 0 |
Definition in file cdr_csv.c.
#define CSV_LOG_DIR "/cdr-csv" |
static int append_date | ( | char * | buf, | |
struct timeval | when, | |||
size_t | bufsize | |||
) | [static] |
Definition at line 193 of file cdr_csv.c.
References append_string(), ast_localtime(), ast_strftime(), ast_tvzero(), and DATE_FORMAT.
Referenced by build_csv_record(), transmit_invite(), transmit_response_with_date(), transmit_response_with_minse(), and transmit_response_with_unsupported().
00194 { 00195 char tmp[80] = ""; 00196 struct ast_tm tm; 00197 00198 if (strlen(buf) > bufsize - 3) 00199 return -1; 00200 00201 if (ast_tvzero(when)) { 00202 strncat(buf, ",", bufsize - strlen(buf) - 1); 00203 return 0; 00204 } 00205 00206 ast_localtime(&when, &tm, usegmtime ? "GMT" : NULL); 00207 ast_strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm); 00208 00209 return append_string(buf, tmp, bufsize); 00210 }
static int append_int | ( | char * | buf, | |
int | s, | |||
size_t | bufsize | |||
) | [static] |
Definition at line 175 of file cdr_csv.c.
Referenced by build_csv_record().
00176 { 00177 char tmp[32]; 00178 int pos = strlen(buf); 00179 00180 snprintf(tmp, sizeof(tmp), "%d", s); 00181 00182 if (pos + strlen(tmp) > bufsize - 3) 00183 return -1; 00184 00185 strncat(buf, tmp, bufsize - strlen(buf) - 1); 00186 pos = strlen(buf); 00187 buf[pos++] = ','; 00188 buf[pos++] = '\0'; 00189 00190 return 0; 00191 }
static int append_string | ( | char * | buf, | |
const char * | s, | |||
size_t | bufsize | |||
) | [static] |
Definition at line 148 of file cdr_csv.c.
Referenced by append_date(), and build_csv_record().
00149 { 00150 int pos = strlen(buf), spos = 0, error = -1; 00151 00152 if (pos >= bufsize - 4) 00153 return -1; 00154 00155 buf[pos++] = '\"'; 00156 00157 while(pos < bufsize - 3) { 00158 if (!s[spos]) { 00159 error = 0; 00160 break; 00161 } 00162 if (s[spos] == '\"') 00163 buf[pos++] = '\"'; 00164 buf[pos++] = s[spos]; 00165 spos++; 00166 } 00167 00168 buf[pos++] = '\"'; 00169 buf[pos++] = ','; 00170 buf[pos++] = '\0'; 00171 00172 return error; 00173 }
static int build_csv_record | ( | char * | buf, | |
size_t | bufsize, | |||
struct ast_cdr * | cdr | |||
) | [static] |
Definition at line 212 of file cdr_csv.c.
References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr::answer, append_date(), append_int(), append_string(), ast_cdr_disp2str(), ast_cdr_flags2str(), ast_cdr::billsec, ast_cdr::channel, ast_cdr::clid, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_cdr::duration, ast_cdr::end, ast_cdr::lastapp, ast_cdr::lastdata, ast_cdr::src, ast_cdr::start, ast_cdr::uniqueid, and ast_cdr::userfield.
Referenced by csv_log().
00213 { 00214 00215 buf[0] = '\0'; 00216 /* Account code */ 00217 append_string(buf, cdr->accountcode, bufsize); 00218 /* Source */ 00219 append_string(buf, cdr->src, bufsize); 00220 /* Destination */ 00221 append_string(buf, cdr->dst, bufsize); 00222 /* Destination context */ 00223 append_string(buf, cdr->dcontext, bufsize); 00224 /* Caller*ID */ 00225 append_string(buf, cdr->clid, bufsize); 00226 /* Channel */ 00227 append_string(buf, cdr->channel, bufsize); 00228 /* Destination Channel */ 00229 append_string(buf, cdr->dstchannel, bufsize); 00230 /* Last Application */ 00231 append_string(buf, cdr->lastapp, bufsize); 00232 /* Last Data */ 00233 append_string(buf, cdr->lastdata, bufsize); 00234 /* Start Time */ 00235 append_date(buf, cdr->start, bufsize); 00236 /* Answer Time */ 00237 append_date(buf, cdr->answer, bufsize); 00238 /* End Time */ 00239 append_date(buf, cdr->end, bufsize); 00240 /* Duration */ 00241 append_int(buf, cdr->duration, bufsize); 00242 /* Billable seconds */ 00243 append_int(buf, cdr->billsec, bufsize); 00244 /* Disposition */ 00245 append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize); 00246 /* AMA Flags */ 00247 append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize); 00248 /* Unique ID */ 00249 if (loguniqueid) 00250 append_string(buf, cdr->uniqueid, bufsize); 00251 /* append the user field */ 00252 if(loguserfield) 00253 append_string(buf, cdr->userfield,bufsize); 00254 /* If we hit the end of our buffer, log an error */ 00255 if (strlen(buf) < bufsize - 5) { 00256 /* Trim off trailing comma */ 00257 buf[strlen(buf) - 1] = '\0'; 00258 strncat(buf, "\n", bufsize - strlen(buf) - 1); 00259 return 0; 00260 } 00261 return -1; 00262 }
static int csv_log | ( | struct ast_cdr * | cdr | ) | [static] |
Definition at line 291 of file cdr_csv.c.
References ast_cdr::accountcode, ast_cdr::amaflags, ast_cdr_disp2str(), ast_cdr_flags2str(), ast_config_AST_LOG_DIR, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), ast_cdr::billsec, build_csv_record(), ast_cdr::channel, CSV_LOG_DIR, CSV_MASTER, ast_cdr::disposition, ast_cdr::dst, ast_cdr::duration, errno, LOG_ERROR, LOG_WARNING, mf_lock, ast_cdr::src, and writefile().
Referenced by load_module().
00292 { 00293 FILE *mf = NULL; 00294 /* Make sure we have a big enough buf */ 00295 char buf[1024]; 00296 char csvmaster[PATH_MAX]; 00297 snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER); 00298 #if 0 00299 printf("[CDR] %s ('%s' -> '%s') Dur: %ds Bill: %ds Disp: %s Flags: %s Account: [%s]\n", cdr->channel, cdr->src, cdr->dst, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->accountcode); 00300 #endif 00301 if (build_csv_record(buf, sizeof(buf), cdr)) { 00302 ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes. CDR not recorded!\n", (int)sizeof(buf)); 00303 return 0; 00304 } 00305 00306 /* because of the absolutely unconditional need for the 00307 highest reliability possible in writing billing records, 00308 we open write and close the log file each time */ 00309 ast_mutex_lock(&mf_lock); 00310 if ((mf = fopen(csvmaster, "a"))) { 00311 fputs(buf, mf); 00312 fflush(mf); /* be particularly anal here */ 00313 fclose(mf); 00314 mf = NULL; 00315 ast_mutex_unlock(&mf_lock); 00316 } else { 00317 ast_mutex_unlock(&mf_lock); 00318 ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno)); 00319 } 00320 00321 if (accountlogs && !ast_strlen_zero(cdr->accountcode)) { 00322 if (writefile(buf, cdr->accountcode)) 00323 ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno)); 00324 } 00325 00326 return 0; 00327 }
static int load_config | ( | int | reload | ) | [static] |
Definition at line 95 of file cdr_csv.c.
References ast_config_destroy(), ast_config_load, ast_debug, ast_log(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_WARNING, and var.
00096 { 00097 struct ast_config *cfg; 00098 struct ast_variable *var; 00099 const char *tmp; 00100 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00101 00102 if (!(cfg = ast_config_load(config, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { 00103 ast_log(LOG_WARNING, "unable to load config: %s\n", config); 00104 return 0; 00105 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 00106 return 1; 00107 00108 accountlogs = 1; 00109 usegmtime = 0; 00110 loguniqueid = 0; 00111 loguserfield = 0; 00112 00113 if (!(var = ast_variable_browse(cfg, "csv"))) { 00114 ast_config_destroy(cfg); 00115 return 0; 00116 } 00117 00118 if ((tmp = ast_variable_retrieve(cfg, "csv", "usegmtime"))) { 00119 usegmtime = ast_true(tmp); 00120 if (usegmtime) 00121 ast_debug(1, "logging time in GMT\n"); 00122 } 00123 00124 /* Turn on/off separate files per accountcode. Default is on (as before) */ 00125 if ((tmp = ast_variable_retrieve(cfg, "csv", "accountlogs"))) { 00126 accountlogs = ast_true(tmp); 00127 if (accountlogs) { 00128 ast_debug(1, "logging in separate files per accountcode\n"); 00129 } 00130 } 00131 00132 if ((tmp = ast_variable_retrieve(cfg, "csv", "loguniqueid"))) { 00133 loguniqueid = ast_true(tmp); 00134 if (loguniqueid) 00135 ast_debug(1, "logging CDR field UNIQUEID\n"); 00136 } 00137 00138 if ((tmp = ast_variable_retrieve(cfg, "csv", "loguserfield"))) { 00139 loguserfield = ast_true(tmp); 00140 if (loguserfield) 00141 ast_debug(1, "logging CDR user-defined field\n"); 00142 } 00143 00144 ast_config_destroy(cfg); 00145 return 1; 00146 }
static int load_module | ( | void | ) | [static] |
Definition at line 336 of file cdr_csv.c.
References ast_cdr_register(), ast_log(), AST_MODULE_LOAD_DECLINE, csv_log(), load_config(), and LOG_ERROR.
00337 { 00338 int res; 00339 00340 if(!load_config(0)) 00341 return AST_MODULE_LOAD_DECLINE; 00342 00343 if ((res = ast_cdr_register(name, ast_module_info->description, csv_log))) { 00344 ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n"); 00345 } else { 00346 loaded = 1; 00347 } 00348 return res; 00349 }
static int reload | ( | void | ) | [static] |
Definition at line 351 of file cdr_csv.c.
References ast_cdr_unregister(), ast_log(), load_config(), and LOG_WARNING.
00352 { 00353 if (load_config(1)) { 00354 loaded = 1; 00355 } else { 00356 loaded = 0; 00357 ast_log(LOG_WARNING, "No [csv] section in cdr.conf. Unregistering backend.\n"); 00358 ast_cdr_unregister(name); 00359 } 00360 00361 return 0; 00362 }
static int unload_module | ( | void | ) | [static] |
Definition at line 329 of file cdr_csv.c.
References ast_cdr_unregister().
00330 { 00331 ast_cdr_unregister(name); 00332 loaded = 0; 00333 return 0; 00334 }
static int writefile | ( | char * | s, | |
char * | acc | |||
) | [static] |
Definition at line 264 of file cdr_csv.c.
References acf_lock, ast_config_AST_LOG_DIR, ast_log(), ast_mutex_lock, ast_mutex_unlock, CSV_LOG_DIR, errno, f, LOG_ERROR, and LOG_WARNING.
Referenced by csv_log().
00265 { 00266 char tmp[PATH_MAX]; 00267 FILE *f; 00268 00269 if (strchr(acc, '/') || (acc[0] == '.')) { 00270 ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc); 00271 return -1; 00272 } 00273 00274 snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc); 00275 00276 ast_mutex_lock(&acf_lock); 00277 if (!(f = fopen(tmp, "a"))) { 00278 ast_mutex_unlock(&acf_lock); 00279 ast_log(LOG_ERROR, "Unable to open file %s : %s\n", tmp, strerror(errno)); 00280 return -1; 00281 } 00282 fputs(s, f); 00283 fflush(f); 00284 fclose(f); 00285 ast_mutex_unlock(&acf_lock); 00286 00287 return 0; 00288 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Comma Separated Values CDR Backend" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CDR_DRIVER, } [static] |
int accountlogs [static] |
ast_mutex_t acf_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static] |
struct ast_module_info* ast_module_info = &__mod_info [static] |
const char config[] = "cdr.conf" [static] |
Definition at line 57 of file cdr_csv.c.
Referenced by add_features_datastores(), app_exec(), ast_bridge_call(), ast_bridge_timelimit(), ast_category_append(), ast_category_browse(), ast_category_exist(), ast_category_get(), ast_category_insert(), ast_category_root(), ast_channel_bridge(), ast_config_new(), ast_generic_bridge(), ast_get_cc_agent_dialstring(), ast_get_cc_agent_policy(), ast_get_cc_callback_macro(), ast_get_cc_max_agents(), ast_get_cc_max_monitors(), ast_get_cc_monitor_policy(), ast_get_cc_offer_timer(), ast_get_cc_recall_timer(), ast_get_ccbs_available_timer(), ast_get_ccnr_available_timer(), ast_readconfig(), ast_set_cc_agent_dialstring(), ast_set_cc_agent_policy(), ast_set_cc_callback_macro(), ast_set_cc_max_agents(), ast_set_cc_max_monitors(), ast_set_cc_monitor_policy(), ast_set_cc_offer_timer(), ast_set_cc_recall_timer(), ast_set_ccbs_available_timer(), ast_set_ccnr_available_timer(), ast_variable_browse(), ast_variable_retrieve(), build_peer(), builtin_atxfer(), category_get(), custom_log(), dial_exec_full(), do_monitor(), do_reload(), execute_cb(), feature_interpret(), feature_interpret_helper(), handle_t38_options(), load_config(), load_module(), load_odbc_config(), load_pktccops_config(), misdn_cfg_init(), odbc_load_module(), parked_call_exec(), parse_config(), read_config_maps(), reload_config(), set_bridge_features_on_config(), set_config(), set_config_flags(), and setup_dahdi_int().
int loguniqueid = 0 [static] |
int loguserfield = 0 [static] |
ast_mutex_t mf_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static] |
int usegmtime = 0 [static] |