Sun Jun 12 16:37:52 2011

Asterisk developer's documentation


cdr_csv.c File Reference

Comma Separated Value CDR records. More...

#include "asterisk.h"
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"

Include dependency graph for cdr_csv.c:

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 tv, 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)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Comma Separated Values CDR Backend",.load=load_module,.unload=unload_module,.reload=reload,)
 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 (void)
static int load_module (void)
static int reload (void)
static int unload_module (void)
static int writefile (char *s, char *acc)

Variables

static 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 52 of file cdr_csv.c.

Referenced by csv_log(), and writefile().

#define CSV_MASTER   "/Master.csv"

Definition at line 53 of file cdr_csv.c.

Referenced by csv_log().

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


Function Documentation

static int append_date ( char *  buf,
struct timeval  tv,
size_t  bufsize 
) [static]

Definition at line 189 of file cdr_csv.c.

References append_string(), ast_localtime(), DATE_FORMAT, and t.

00190 {
00191    char tmp[80] = "";
00192    struct tm tm;
00193    time_t t;
00194    t = tv.tv_sec;
00195    if (strlen(buf) > bufsize - 3)
00196       return -1;
00197    if (ast_tvzero(tv)) {
00198       strncat(buf, ",", bufsize - strlen(buf) - 1);
00199       return 0;
00200    }
00201    if (usegmtime) {
00202       gmtime_r(&t,&tm);
00203    } else {
00204       ast_localtime(&t, &tm, NULL);
00205    }
00206    strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm);
00207    return append_string(buf, tmp, bufsize);
00208 }

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    snprintf(tmp, sizeof(tmp), "%d", s);
00180    if (pos + strlen(tmp) > bufsize - 3)
00181       return -1;
00182    strncat(buf, tmp, bufsize - strlen(buf) - 1);
00183    pos = strlen(buf);
00184    buf[pos++] = ',';
00185    buf[pos++] = '\0';
00186    return 0;
00187 }

static int append_string ( char *  buf,
char *  s,
size_t  bufsize 
) [static]

Definition at line 150 of file cdr_csv.c.

References error().

Referenced by append_date(), and build_csv_record().

00151 {
00152    int pos = strlen(buf);
00153    int spos = 0;
00154    int error = 0;
00155    if (pos >= bufsize - 4)
00156       return -1;
00157    buf[pos++] = '\"';
00158    error = -1;
00159    while(pos < bufsize - 3) {
00160       if (!s[spos]) {
00161          error = 0;
00162          break;
00163       }
00164       if (s[spos] == '\"')
00165          buf[pos++] = '\"';
00166       buf[pos++] = s[spos];
00167       spos++;
00168    }
00169    buf[pos++] = '\"';
00170    buf[pos++] = ',';
00171    buf[pos++] = '\0';
00172    return error;
00173 }

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT  ,
"Comma Separated Values CDR Backend"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

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

00211 {
00212 
00213    buf[0] = '\0';
00214    /* Account code */
00215    append_string(buf, cdr->accountcode, bufsize);
00216    /* Source */
00217    append_string(buf, cdr->src, bufsize);
00218    /* Destination */
00219    append_string(buf, cdr->dst, bufsize);
00220    /* Destination context */
00221    append_string(buf, cdr->dcontext, bufsize);
00222    /* Caller*ID */
00223    append_string(buf, cdr->clid, bufsize);
00224    /* Channel */
00225    append_string(buf, cdr->channel, bufsize);
00226    /* Destination Channel */
00227    append_string(buf, cdr->dstchannel, bufsize);
00228    /* Last Application */
00229    append_string(buf, cdr->lastapp, bufsize);
00230    /* Last Data */
00231    append_string(buf, cdr->lastdata, bufsize);
00232    /* Start Time */
00233    append_date(buf, cdr->start, bufsize);
00234    /* Answer Time */
00235    append_date(buf, cdr->answer, bufsize);
00236    /* End Time */
00237    append_date(buf, cdr->end, bufsize);
00238    /* Duration */
00239    append_int(buf, cdr->duration, bufsize);
00240    /* Billable seconds */
00241    append_int(buf, cdr->billsec, bufsize);
00242    /* Disposition */
00243    append_string(buf, ast_cdr_disp2str(cdr->disposition), bufsize);
00244    /* AMA Flags */
00245    append_string(buf, ast_cdr_flags2str(cdr->amaflags), bufsize);
00246    /* Unique ID */
00247    if (loguniqueid)
00248       append_string(buf, cdr->uniqueid, bufsize);
00249    /* append the user field */
00250    if(loguserfield)
00251       append_string(buf, cdr->userfield,bufsize);  
00252    /* If we hit the end of our buffer, log an error */
00253    if (strlen(buf) < bufsize - 5) {
00254       /* Trim off trailing comma */
00255       buf[strlen(buf) - 1] = '\0';
00256       strncat(buf, "\n", bufsize - strlen(buf) - 1);
00257       return 0;
00258    }
00259    return -1;
00260 }

static int csv_log ( struct ast_cdr cdr  )  [static]

Definition at line 288 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().

00289 {
00290    FILE *mf = NULL;
00291    /* Make sure we have a big enough buf */
00292    char buf[1024];
00293    char csvmaster[PATH_MAX];
00294    snprintf(csvmaster, sizeof(csvmaster),"%s/%s/%s", ast_config_AST_LOG_DIR, CSV_LOG_DIR, CSV_MASTER);
00295 #if 0
00296    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);
00297 #endif
00298    if (build_csv_record(buf, sizeof(buf), cdr)) {
00299       ast_log(LOG_WARNING, "Unable to create CSV record in %d bytes.  CDR not recorded!\n", (int)sizeof(buf));
00300    } else {
00301       /* because of the absolutely unconditional need for the
00302          highest reliability possible in writing billing records,
00303          we open write and close the log file each time */
00304       ast_mutex_lock(&mf_lock);
00305       mf = fopen(csvmaster, "a");
00306       if (mf) {
00307          fputs(buf, mf);
00308          fflush(mf); /* be particularly anal here */
00309          fclose(mf);
00310          mf = NULL;
00311          ast_mutex_unlock(&mf_lock);
00312       } else {
00313          ast_mutex_unlock(&mf_lock);
00314          ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", csvmaster, strerror(errno));
00315       }
00316 
00317       if (!ast_strlen_zero(cdr->accountcode)) {
00318          if (writefile(buf, cdr->accountcode))
00319             ast_log(LOG_WARNING, "Unable to write CSV record to account file '%s' : %s\n", cdr->accountcode, strerror(errno));
00320       }
00321    }
00322    return 0;
00323 }

static int load_config ( void   )  [static]

Definition at line 99 of file cdr_csv.c.

References ast_config_destroy(), ast_config_load(), ast_log(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), LOG_DEBUG, LOG_WARNING, and var.

00100 {
00101    struct ast_config *cfg;
00102    struct ast_variable *var;
00103    const char *tmp;
00104 
00105    usegmtime = 0;
00106    loguniqueid = 0;
00107    loguserfield = 0;
00108    
00109    cfg = ast_config_load(config);
00110    
00111    if (!cfg) {
00112       ast_log(LOG_WARNING, "unable to load config: %s\n", config);
00113       return 0;
00114    } 
00115    
00116    var = ast_variable_browse(cfg, "csv");
00117    if (!var) {
00118       ast_config_destroy(cfg);
00119       return 0;
00120    }
00121    
00122    tmp = ast_variable_retrieve(cfg, "csv", "usegmtime");
00123    if (tmp) {
00124       usegmtime = ast_true(tmp);
00125       if (usegmtime) {
00126          ast_log(LOG_DEBUG, "logging time in GMT\n");
00127       }
00128    }
00129 
00130    tmp = ast_variable_retrieve(cfg, "csv", "loguniqueid");
00131    if (tmp) {
00132       loguniqueid = ast_true(tmp);
00133       if (loguniqueid) {
00134          ast_log(LOG_DEBUG, "logging CDR field UNIQUEID\n");
00135       }
00136    }
00137 
00138    tmp = ast_variable_retrieve(cfg, "csv", "loguserfield");
00139    if (tmp) {
00140       loguserfield = ast_true(tmp);
00141       if (loguserfield) {
00142          ast_log(LOG_DEBUG, "logging CDR user-defined field\n");
00143       }
00144    }
00145 
00146    ast_config_destroy(cfg);
00147    return 1;
00148 }

static int load_module ( void   )  [static]

Definition at line 332 of file cdr_csv.c.

References ast_cdr_register(), ast_log(), AST_MODULE_LOAD_DECLINE, csv_log(), load_config(), and LOG_ERROR.

00333 {
00334    int res;
00335    
00336    if(!load_config())
00337       return AST_MODULE_LOAD_DECLINE;
00338 
00339    res = ast_cdr_register(name, ast_module_info->description, csv_log);
00340    if (res) {
00341       ast_log(LOG_ERROR, "Unable to register CSV CDR handling\n");
00342    } else {
00343       loaded = 1;
00344    }
00345    return res;
00346 }

static int reload ( void   )  [static]

Definition at line 348 of file cdr_csv.c.

References ast_cdr_unregister(), ast_log(), load_config(), and LOG_WARNING.

00349 {
00350    if (load_config()) {
00351       loaded = 1;
00352    } else {
00353       loaded = 0;
00354       ast_log(LOG_WARNING, "No [csv] section in cdr.conf.  Unregistering backend.\n");
00355       ast_cdr_unregister(name);
00356    }
00357 
00358    return 0;
00359 }

static int unload_module ( void   )  [static]

Definition at line 325 of file cdr_csv.c.

References ast_cdr_unregister().

00326 {
00327    ast_cdr_unregister(name);
00328    loaded = 0;
00329    return 0;
00330 }

static int writefile ( char *  s,
char *  acc 
) [static]

Definition at line 262 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().

00263 {
00264    char tmp[PATH_MAX];
00265    FILE *f;
00266    if (strchr(acc, '/') || (acc[0] == '.')) {
00267       ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n", acc);
00268       return -1;
00269    }
00270    snprintf(tmp, sizeof(tmp), "%s/%s/%s.csv", (char *)ast_config_AST_LOG_DIR,CSV_LOG_DIR, acc);
00271 
00272    ast_mutex_lock(&acf_lock);
00273    f = fopen(tmp, "a");
00274    if (!f) {
00275       ast_mutex_unlock(&acf_lock);
00276       ast_log(LOG_ERROR, "Unable to open file %s : %s\n", tmp, strerror(errno));
00277       return -1;
00278    }
00279    fputs(s, f);
00280    fflush(f);
00281    fclose(f);
00282    ast_mutex_unlock(&acf_lock);
00283 
00284    return 0;
00285 }


Variable Documentation

char* config = "cdr.conf" [static]

Definition at line 61 of file cdr_csv.c.

int loaded = 0 [static]

Definition at line 60 of file cdr_csv.c.

int loguniqueid = 0 [static]

Definition at line 58 of file cdr_csv.c.

int loguserfield = 0 [static]

Definition at line 59 of file cdr_csv.c.

char* name = "csv" [static]

Definition at line 94 of file cdr_csv.c.

int usegmtime = 0 [static]

Definition at line 57 of file cdr_csv.c.


Generated on Sun Jun 12 16:37:52 2011 for Asterisk - the Open Source PBX by  doxygen 1.5.6