#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 | 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 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, mf, 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 }
int loguniqueid = 0 [static] |
int loguserfield = 0 [static] |