Mon Mar 31 07:39:18 2008

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

Definition at line 55 of file cdr_csv.c.


Function Documentation

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

Definition at line 188 of file cdr_csv.c.

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

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

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

Definition at line 174 of file cdr_csv.c.

Referenced by build_csv_record().

00175 {
00176    char tmp[32];
00177    int pos = strlen(buf);
00178    snprintf(tmp, sizeof(tmp), "%d", s);
00179    if (pos + strlen(tmp) > bufsize - 3)
00180       return -1;
00181    strncat(buf, tmp, bufsize - strlen(buf) - 1);
00182    pos = strlen(buf);
00183    buf[pos++] = ',';
00184    buf[pos++] = '\0';
00185    return 0;
00186 }

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

Definition at line 149 of file cdr_csv.c.

References error().

Referenced by append_date(), and build_csv_record().

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

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

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

static int csv_log ( struct ast_cdr cdr  )  [static]

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

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

static int load_config ( void   )  [static]

Definition at line 98 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.

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

static int load_module ( void   )  [static]

Definition at line 330 of file cdr_csv.c.

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

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

static int reload ( void   )  [static]

Definition at line 344 of file cdr_csv.c.

References load_config().

00345 {
00346    load_config();
00347 
00348    return 0;
00349 }

static int unload_module ( void   )  [static]

Definition at line 324 of file cdr_csv.c.

References ast_cdr_unregister().

00325 {
00326    ast_cdr_unregister(name);
00327    return 0;
00328 }

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

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

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


Variable Documentation

char* config = "cdr.conf" [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 93 of file cdr_csv.c.

int usegmtime = 0 [static]

Definition at line 57 of file cdr_csv.c.


Generated on Mon Mar 31 07:39:18 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1