Comma Separated Value CDR records. More...
#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 = AST_BUILDOPT_SUM, .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 |
Comma Separated Value CDR records.
Definition in file cdr_csv.c.
| #define CSV_LOG_DIR "/cdr-csv" |
Definition at line 47 of file cdr_csv.c.
Referenced by csv_log(), and writefile().
| #define DATE_FORMAT "%Y-%m-%d %T" |
Definition at line 50 of file cdr_csv.c.
Referenced by append_date().
| 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().
{
char tmp[80] = "";
struct ast_tm tm;
if (strlen(buf) > bufsize - 3)
return -1;
if (ast_tvzero(when)) {
strncat(buf, ",", bufsize - strlen(buf) - 1);
return 0;
}
ast_localtime(&when, &tm, usegmtime ? "GMT" : NULL);
ast_strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm);
return append_string(buf, tmp, bufsize);
}
| 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().
{
char tmp[32];
int pos = strlen(buf);
snprintf(tmp, sizeof(tmp), "%d", s);
if (pos + strlen(tmp) > bufsize - 3)
return -1;
strncat(buf, tmp, bufsize - strlen(buf) - 1);
pos = strlen(buf);
buf[pos++] = ',';
buf[pos++] = '\0';
return 0;
}
| 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().
{
int pos = strlen(buf), spos = 0, error = -1;
if (pos >= bufsize - 4)
return -1;
buf[pos++] = '\"';
while(pos < bufsize - 3) {
if (!s[spos]) {
error = 0;
break;
}
if (s[spos] == '\"')
buf[pos++] = '\"';
buf[pos++] = s[spos];
spos++;
}
buf[pos++] = '\"';
buf[pos++] = ',';
buf[pos++] = '\0';
return error;
}
| 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().
{
buf[0] = '\0';
/* Account code */
append_string(buf, cdr->accountcode, bufsize);
/* Source */
append_string(buf, cdr->src, bufsize);
/* Destination */
append_string(buf, cdr->dst, bufsize);
/* Destination context */
append_string(buf, cdr->dcontext, bufsize);
/* Caller*ID */
append_string(buf, cdr->clid, bufsize);
/* Channel */
append_string(buf, cdr->channel, bufsize);
/* Destination Channel */
append_string(buf, cdr->dstchannel, bufsize);
/* Last Application */
append_string(buf, cdr->lastapp, bufsize);
/* Last Data */
append_string(buf, cdr->lastdata, bufsize);
/* Start Time */
append_date(buf, cdr->start, bufsize);
/* Answer Time */
append_date(buf, cdr->answer, bufsize);
/* End Time */
append_date(buf, cdr->end, bufsize);
/* Duration */
append_int(buf, cdr->duration, bufsize);
/* Billable seconds */
append_int(buf, cdr->billsec, bufsize);
/* Disposition */
append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize);
/* AMA Flags */
append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize);
/* Unique ID */
if (loguniqueid)
append_string(buf, cdr->uniqueid, bufsize);
/* append the user field */
if(loguserfield)
append_string(buf, cdr->userfield,bufsize);
/* If we hit the end of our buffer, log an error */
if (strlen(buf) < bufsize - 5) {
/* Trim off trailing comma */
buf[strlen(buf) - 1] = '\0';
strncat(buf, "\n", bufsize - strlen(buf) - 1);
return 0;
}
return -1;
}
| 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().
{
FILE *mf = NULL;
/* Make sure we have a big enough buf */
char buf[1024];
char csvmaster[PATH_MAX];
snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER);
#if 0
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);
#endif
if (build_csv_record(buf, sizeof(buf), cdr)) {
ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes. CDR not recorded!\n", (int)sizeof(buf));
return 0;
}
/* because of the absolutely unconditional need for the
highest reliability possible in writing billing records,
we open write and close the log file each time */
ast_mutex_lock(&mf_lock);
if ((mf = fopen(csvmaster, "a"))) {
fputs(buf, mf);
fflush(mf); /* be particularly anal here */
fclose(mf);
mf = NULL;
ast_mutex_unlock(&mf_lock);
} else {
ast_mutex_unlock(&mf_lock);
ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno));
}
if (accountlogs && !ast_strlen_zero(cdr->accountcode)) {
if (writefile(buf, cdr->accountcode))
ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno));
}
return 0;
}
| 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.
Referenced by load_module(), and reload().
{
struct ast_config *cfg;
struct ast_variable *var;
const char *tmp;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
if (!(cfg = ast_config_load(config, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_WARNING, "unable to load config: %s\n", config);
return 0;
} else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
return 1;
accountlogs = 1;
usegmtime = 0;
loguniqueid = 0;
loguserfield = 0;
if (!(var = ast_variable_browse(cfg, "csv"))) {
ast_config_destroy(cfg);
return 0;
}
if ((tmp = ast_variable_retrieve(cfg, "csv", "usegmtime"))) {
usegmtime = ast_true(tmp);
if (usegmtime)
ast_debug(1, "logging time in GMT\n");
}
/* Turn on/off separate files per accountcode. Default is on (as before) */
if ((tmp = ast_variable_retrieve(cfg, "csv", "accountlogs"))) {
accountlogs = ast_true(tmp);
if (accountlogs) {
ast_debug(1, "logging in separate files per accountcode\n");
}
}
if ((tmp = ast_variable_retrieve(cfg, "csv", "loguniqueid"))) {
loguniqueid = ast_true(tmp);
if (loguniqueid)
ast_debug(1, "logging CDR field UNIQUEID\n");
}
if ((tmp = ast_variable_retrieve(cfg, "csv", "loguserfield"))) {
loguserfield = ast_true(tmp);
if (loguserfield)
ast_debug(1, "logging CDR user-defined field\n");
}
ast_config_destroy(cfg);
return 1;
}
| 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(), ast_module_info::description, load_config(), and LOG_ERROR.
{
int res;
if(!load_config(0))
return AST_MODULE_LOAD_DECLINE;
if ((res = ast_cdr_register(name, ast_module_info->description, csv_log))) {
ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n");
} else {
loaded = 1;
}
return res;
}
| 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.
{
if (load_config(1)) {
loaded = 1;
} else {
loaded = 0;
ast_log(LOG_WARNING, "No [csv] section in cdr.conf. Unregistering backend.\n");
ast_cdr_unregister(name);
}
return 0;
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 329 of file cdr_csv.c.
References ast_cdr_unregister().
{
ast_cdr_unregister(name);
loaded = 0;
return 0;
}
| 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().
{
char tmp[PATH_MAX];
FILE *f;
if (strchr(acc, '/') || (acc[0] == '.')) {
ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc);
return -1;
}
snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc);
ast_mutex_lock(&acf_lock);
if (!(f = fopen(tmp, "a"))) {
ast_mutex_unlock(&acf_lock);
ast_log(LOG_ERROR, "Unable to open file %s : %s\n", tmp, strerror(errno));
return -1;
}
fputs(s, f);
fflush(f);
fclose(f);
ast_mutex_unlock(&acf_lock);
return 0;
}
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 = AST_BUILDOPT_SUM, .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] |
Definition at line 93 of file cdr_csv.c.
Referenced by writefile().
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 ast_config_new(), ast_readconfig(), builtin_atxfer(), custom_log(), do_reload(), load_config(), load_module(), load_odbc_config(), load_pktccops_config(), misdn_cfg_init(), parse_config(), read_config_maps(), and reload_config().
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] |
Definition at line 52 of file cdr_csv.c.
Referenced by load_config().