Fri Aug 17 00:17:27 2018

Asterisk developer's documentation


cdr_csv.c File Reference

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 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)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,"Comma Separated Values CDR Backend",.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CDR_DRIVER,)
 AST_MUTEX_DEFINE_STATIC (acf_lock)
 AST_MUTEX_DEFINE_STATIC (mf_lock)
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 int accountlogs
static const char config [] = "cdr.conf"
static int loaded = 0
static int loguniqueid = 0
static int loguserfield = 0
static char * name = "csv"
static int usegmtime = 0

Detailed Description

Comma Separated Value CDR records.

Author:
Mark Spencer <markster@digium.com>

Definition in file cdr_csv.c.


Define Documentation

#define CSV_LOG_DIR   "/cdr-csv"

Definition at line 47 of file cdr_csv.c.

Referenced by csv_log(), and writefile().

#define CSV_MASTER   "/Master.csv"

Definition at line 48 of file cdr_csv.c.

Referenced by csv_log().

#define DATE_FORMAT   "%Y-%m-%d %T"

Definition at line 50 of file cdr_csv.c.


Function Documentation

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().

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 }

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_LOAD_ORDER  ,
"Comma Separated Values CDR Backend"  ,
load = load_module,
unload = unload_module,
reload = reload,
load_pri = AST_MODPRI_CDR_DRIVER 
)
AST_MUTEX_DEFINE_STATIC ( acf_lock   ) 
AST_MUTEX_DEFINE_STATIC ( mf_lock   ) 
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, 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.

Referenced by load_module(), and reload().

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 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 }


Variable Documentation

int accountlogs [static]

Definition at line 53 of file cdr_csv.c.

const char config[] = "cdr.conf" [static]
int loaded = 0 [static]

Definition at line 56 of file cdr_csv.c.

int loguniqueid = 0 [static]

Definition at line 54 of file cdr_csv.c.

int loguserfield = 0 [static]

Definition at line 55 of file cdr_csv.c.

char* name = "csv" [static]

Definition at line 90 of file cdr_csv.c.

int usegmtime = 0 [static]

Definition at line 52 of file cdr_csv.c.

Referenced by load_config().


Generated on 17 Aug 2018 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1