Thu Apr 28 2011 16:56:56

Asterisk developer's documentation


cdr_csv.c File Reference

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

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

Referenced by csv_log(), and writefile().

#define CSV_MASTER   "/Master.csv"

Definition at line 46 of file cdr_csv.c.

Referenced by csv_log().

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

Definition at line 48 of file cdr_csv.c.

Referenced by append_date().


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 356 of file cdr_csv.c.

static void __unreg_module ( void  ) [static]

Definition at line 356 of file cdr_csv.c.

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

{
   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,
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;
}

Variable Documentation

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]

Definition at line 356 of file cdr_csv.c.

ast_mutex_t acf_lock = AST_MUTEX_INIT_VALUE [static]

Definition at line 90 of file cdr_csv.c.

Referenced by writefile().

Definition at line 356 of file cdr_csv.c.

int loaded = 0 [static]

Definition at line 53 of file cdr_csv.c.

int loguniqueid = 0 [static]

Definition at line 51 of file cdr_csv.c.

int loguserfield = 0 [static]

Definition at line 52 of file cdr_csv.c.

ast_mutex_t mf_lock = AST_MUTEX_INIT_VALUE [static]

Definition at line 89 of file cdr_csv.c.

Referenced by csv_log().

char* name = "csv" [static]

Definition at line 87 of file cdr_csv.c.

int usegmtime = 0 [static]

Definition at line 50 of file cdr_csv.c.

Referenced by load_config().