#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"
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 |
Definition in file cdr_csv.c.
#define CSV_LOG_DIR "/cdr-csv" |
#define DATE_FORMAT "%Y-%m-%d %T" |
Definition at line 55 of file cdr_csv.c.
Referenced by append_date(), build_radius_record(), get_date(), manager_log(), odbc_log(), pgsql_log(), and sqlite_log().
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 }
int loguniqueid = 0 [static] |
int loguserfield = 0 [static] |