Comma Separated Value CDR records. More...
#include "asterisk.h"
#include <time.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, 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 __MODULE_INFO_SECTION | __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Comma Separated Values CDR Backend" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } |
static ast_mutex_t | acf_lock = AST_MUTEX_INIT_VALUE |
static struct ast_module_info * | ast_module_info = &__mod_info |
static char * | config = "cdr.conf" |
static int | loaded = 0 |
static int | loguniqueid = 0 |
static int | loguserfield = 0 |
static ast_mutex_t | mf_lock = AST_MUTEX_INIT_VALUE |
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 45 of file cdr_csv.c.
Referenced by csv_log(), and writefile().
#define DATE_FORMAT "%Y-%m-%d %T" |
Definition at line 48 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 181 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 163 of file cdr_csv.c.
Referenced by build_csv_record().
static int append_string | ( | char * | buf, |
char * | s, | ||
size_t | bufsize | ||
) | [static] |
Definition at line 136 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 200 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 279 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, buf, 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 (!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 92 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; 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"); } 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 324 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 339 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 317 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 252 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 __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Comma Separated Values CDR Backend" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static] |
ast_mutex_t acf_lock = AST_MUTEX_INIT_VALUE [static] |
Definition at line 90 of file cdr_csv.c.
Referenced by writefile().
struct ast_module_info* ast_module_info = &__mod_info [static] |
char* config = "cdr.conf" [static] |
Definition at line 54 of file cdr_csv.c.
Referenced by ast_config_new(), ast_readconfig(), builtin_atxfer(), do_reload(), load_config(), load_module(), load_odbc_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 = AST_MUTEX_INIT_VALUE [static] |
int usegmtime = 0 [static] |
Definition at line 50 of file cdr_csv.c.
Referenced by load_config().