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 |
Comma Separated Value CDR records.
Definition in file cdr_csv.c.
#define CSV_LOG_DIR "/cdr-csv" |
Definition at line 47 of file cdr_csv.c.
Referenced by csv_log(), and writefile().
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 }
int accountlogs [static] |
const char config[] = "cdr.conf" [static] |
Definition at line 57 of file cdr_csv.c.
Referenced by ast_config_new(), ast_readconfig(), custom_log(), do_reload(), load_config(), load_module(), load_odbc_config(), load_pktccops_config(), misdn_cfg_init(), parse_config(), read_config_maps(), and reload_config().
int loguniqueid = 0 [static] |
int loguserfield = 0 [static] |
int usegmtime = 0 [static] |
Definition at line 52 of file cdr_csv.c.
Referenced by load_config().