00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
#include <signal.h>
00015
#include <stdarg.h>
00016
#include <stdio.h>
00017
#include <unistd.h>
00018
#include <time.h>
00019
#include <asterisk/lock.h>
00020
#include <asterisk/options.h>
00021
#include <asterisk/channel.h>
00022
#include <asterisk/config.h>
00023
#include <asterisk/term.h>
00024
#include <asterisk/cli.h>
00025
#include <asterisk/utils.h>
00026
#include <string.h>
00027
#include <stdlib.h>
00028
#include <errno.h>
00029
#include <pthread.h>
00030
#include <sys/stat.h>
00031
#include "asterisk.h"
00032
#include "astconf.h"
00033
00034 #define SYSLOG_NAMES
00035
00036
#include <syslog.h>
00037
static int syslog_level_map[] = {
00038
LOG_DEBUG,
00039 LOG_INFO,
00040
LOG_NOTICE,
00041
LOG_WARNING,
00042 LOG_ERR,
00043
LOG_DEBUG
00044 };
00045 #define SYSLOG_NLEVELS 6
00046
00047
#include <asterisk/logger.h>
00048
00049 #define MAX_MSG_QUEUE 200
00050
00051
static char dateformat[256] =
"%b %e %T";
00052
AST_MUTEX_DEFINE_STATIC(msglist_lock);
00053
AST_MUTEX_DEFINE_STATIC(loglock);
00054
static int pending_logger_reload = 0;
00055
00056
static struct msglist {
00057
char *msg;
00058
struct msglist *next;
00059 } *list = NULL, *last = NULL;
00060
00061 struct logchannel {
00062 int logmask;
00063 int facility;
00064 int syslog;
00065 int console;
00066 FILE *
fileptr;
00067 char filename[256];
00068 struct logchannel *
next;
00069 };
00070
00071
static struct logchannel *logchannels = NULL;
00072
00073
static int msgcnt = 0;
00074
00075
static FILE *eventlog = NULL;
00076
00077
static char *levels[] = {
00078
"DEBUG",
00079
"EVENT",
00080
"NOTICE",
00081
"WARNING",
00082
"ERROR",
00083
"VERBOSE"
00084 };
00085
00086
static int colors[] = {
00087
COLOR_BRGREEN,
00088
COLOR_BRBLUE,
00089
COLOR_YELLOW,
00090
COLOR_BRRED,
00091
COLOR_RED,
00092
COLOR_GREEN
00093 };
00094
00095
static int make_components(
char *s,
int lineno)
00096 {
00097
char *w;
00098
int res = 0;
00099
char *stringp=NULL;
00100 stringp=
s;
00101 w = strsep(&stringp,
",");
00102
while(w) {
00103
while(*w && (*w < 33))
00104 w++;
00105
if (!strcasecmp(w,
"error"))
00106 res |= (1 <<
__LOG_ERROR);
00107
else if (!strcasecmp(w,
"warning"))
00108 res |= (1 <<
__LOG_WARNING);
00109
else if (!strcasecmp(w,
"notice"))
00110 res |= (1 <<
__LOG_NOTICE);
00111
else if (!strcasecmp(w,
"event"))
00112 res |= (1 <<
__LOG_EVENT);
00113
else if (!strcasecmp(w,
"debug"))
00114 res |= (1 <<
__LOG_DEBUG);
00115
else if (!strcasecmp(w,
"verbose"))
00116 res |= (1 <<
__LOG_VERBOSE);
00117
else {
00118 fprintf(stderr,
"Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno);
00119 }
00120 w = strsep(&stringp,
",");
00121 }
00122
return res;
00123 }
00124
00125
static struct logchannel *make_logchannel(
char *channel,
char *components,
int lineno)
00126 {
00127
struct logchannel *chan;
00128
char *facility;
00129 CODE *cptr;
00130
00131
if (ast_strlen_zero(channel))
00132
return NULL;
00133 chan =
malloc(
sizeof(
struct logchannel));
00134
00135
if (chan) {
00136 memset(chan, 0,
sizeof(
struct logchannel));
00137
if (!strcasecmp(channel,
"console")) {
00138 chan->console = 1;
00139 }
else if (!strncasecmp(channel,
"syslog", 6)) {
00140
00141
00142
00143
00144 facility = strchr(channel,
'.');
00145
if(!facility++ || !facility) {
00146 facility =
"local0";
00147 }
00148
00149
00150
00151
00152 chan->facility = -1;
00153 cptr = facilitynames;
00154
while (cptr->c_name) {
00155
if (!strncasecmp(facility, cptr->c_name,
sizeof(cptr->c_name))) {
00156 chan->facility = cptr->c_val;
00157
break;
00158 }
00159 cptr++;
00160 }
00161
if (0 > chan->facility) {
00162 fprintf(stderr,
"Logger Warning: bad syslog facility in logger.conf\n");
00163
free(chan);
00164
return NULL;
00165 }
00166
00167 chan->syslog = 1;
00168 openlog(
"asterisk", LOG_PID, chan->facility);
00169 }
else {
00170
if (channel[0] ==
'/')
00171 strncpy(chan->filename, channel,
sizeof(chan->filename) - 1);
00172
else
00173 snprintf(chan->filename,
sizeof(chan->filename),
"%s/%s", (
char *)ast_config_AST_LOG_DIR, channel);
00174 chan->fileptr = fopen(chan->filename,
"a");
00175
if (!chan->fileptr) {
00176
00177 fprintf(stderr,
"Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno));
00178 }
00179 }
00180 chan->logmask = make_components(components, lineno);
00181 }
00182
return chan;
00183 }
00184
00185
static void init_logger_chain(
void)
00186 {
00187
struct logchannel *chan, *cur;
00188
struct ast_config *cfg;
00189
struct ast_variable *var;
00190
char *
s;
00191
00192
00193
ast_mutex_lock(&loglock);
00194 chan = logchannels;
00195
while (chan) {
00196 cur = chan->
next;
00197
free(chan);
00198 chan = cur;
00199 }
00200 logchannels = NULL;
00201
ast_mutex_unlock(&loglock);
00202
00203
00204 closelog();
00205
00206 cfg =
ast_load(
"logger.conf");
00207
00208
00209
if (!cfg)
00210
return;
00211
00212
ast_mutex_lock(&loglock);
00213
if ((
s =
ast_variable_retrieve(cfg,
"general",
"dateformat"))) {
00214 (
void)strncpy(dateformat,s,
sizeof(dateformat));
00215 }
00216 var =
ast_variable_browse(cfg,
"logfiles");
00217
while(var) {
00218 chan = make_logchannel(var->name, var->value, var->lineno);
00219
if (chan) {
00220 chan->next = logchannels;
00221 logchannels = chan;
00222 }
00223 var = var->
next;
00224 }
00225
00226
ast_destroy(cfg);
00227
ast_mutex_unlock(&loglock);
00228 }
00229
00230
static FILE *qlog = NULL;
00231
AST_MUTEX_DEFINE_STATIC(qloglock);
00232
00233 void ast_queue_log(
const char *queuename,
const char *callid,
const char *agent,
const char *event,
const char *fmt, ...)
00234 {
00235 va_list ap;
00236
ast_mutex_lock(&qloglock);
00237
if (qlog) {
00238 va_start(ap, fmt);
00239 fprintf(qlog,
"%ld|%s|%s|%s|%s|", (
long)time(NULL), callid, queuename, agent, event);
00240 vfprintf(qlog, fmt, ap);
00241 fprintf(qlog,
"\n");
00242 va_end(ap);
00243 fflush(qlog);
00244 }
00245
ast_mutex_unlock(&qloglock);
00246 }
00247
00248
static void queue_log_init(
void)
00249 {
00250
char filename[256];
00251
int reloaded = 0;
00252
ast_mutex_lock(&qloglock);
00253
if (qlog) {
00254 reloaded = 1;
00255 fclose(qlog);
00256 qlog = NULL;
00257 }
00258 snprintf(filename,
sizeof(filename),
"%s/%s", (
char *)ast_config_AST_LOG_DIR,
"queue_log");
00259 qlog = fopen(filename,
"a");
00260
ast_mutex_unlock(&qloglock);
00261
if (reloaded)
00262
ast_queue_log(
"NONE",
"NONE",
"NONE",
"CONFIGRELOAD",
"%s",
"");
00263
else
00264
ast_queue_log(
"NONE",
"NONE",
"NONE",
"QUEUESTART",
"%s",
"");
00265 }
00266
00267 int reload_logger(
int rotate)
00268 {
00269
char old[
AST_CONFIG_MAX_PATH];
00270
char new[
AST_CONFIG_MAX_PATH];
00271
struct logchannel *f;
00272 FILE *myf;
00273
00274
int x;
00275
ast_mutex_lock(&loglock);
00276
if (eventlog)
00277 fclose(eventlog);
00278
else
00279 rotate = 0;
00280 eventlog = NULL;
00281
00282
00283
00284 mkdir((
char *)
ast_config_AST_LOG_DIR, 0755);
00285 snprintf(old,
sizeof(old),
"%s/%s", (
char *)
ast_config_AST_LOG_DIR,
EVENTLOG);
00286
00287
if(rotate) {
00288
for(x=0;;x++) {
00289 snprintf(
new,
sizeof(
new),
"%s/%s.%d", (
char *)
ast_config_AST_LOG_DIR,
EVENTLOG,x);
00290 myf = fopen((
char *)
new,
"r");
00291
if(myf)
00292 fclose(myf);
00293
else
00294
break;
00295 }
00296
00297
00298
if (rename(old,
new))
00299 fprintf(stderr,
"Unable to rename file '%s' to '%s'\n", old,
new);
00300 }
00301
00302 eventlog = fopen(old,
"a");
00303
00304 f = logchannels;
00305
while(f) {
00306
if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
00307 fclose(f->fileptr);
00308 f->fileptr = NULL;
00309
if(rotate) {
00310 strncpy(old, f->filename,
sizeof(old));
00311
00312
for(x=0;;x++) {
00313 snprintf(
new,
sizeof(
new),
"%s.%d", f->filename, x);
00314 myf = fopen((
char *)
new,
"r");
00315
if (myf) {
00316 fclose(myf);
00317 }
else {
00318
break;
00319 }
00320 }
00321
00322
00323
if (rename(old,
new))
00324 fprintf(stderr,
"Unable to rename file '%s' to '%s'\n", old,
new);
00325 }
00326 }
00327 f = f->next;
00328 }
00329
00330
ast_mutex_unlock(&loglock);
00331
00332 queue_log_init();
00333
00334
if (eventlog) {
00335 init_logger_chain();
00336
ast_log(
LOG_EVENT,
"Restarted Asterisk Event Logger\n");
00337
if (
option_verbose)
00338
ast_verbose(
"Asterisk Event Logger restarted\n");
00339
return 0;
00340 }
else
00341
ast_log(
LOG_ERROR,
"Unable to create event log: %s\n", strerror(errno));
00342 init_logger_chain();
00343 pending_logger_reload = 0;
00344
return -1;
00345 }
00346
00347
static int handle_logger_reload(
int fd,
int argc,
char *argv[])
00348 {
00349
if(
reload_logger(0))
00350 {
00351
ast_cli(fd,
"Failed to reloadthe logger\n");
00352
return RESULT_FAILURE;
00353 }
00354
else
00355
return RESULT_SUCCESS;
00356 }
00357
00358
static int handle_logger_rotate(
int fd,
int argc,
char *argv[])
00359 {
00360
if(
reload_logger(1))
00361 {
00362
ast_cli(fd,
"Failed to reloadthe logger\n");
00363
return RESULT_FAILURE;
00364 }
00365
else
00366
return RESULT_SUCCESS;
00367 }
00368
00369
static struct verb {
00370 void (*verboser)(
const char *
string,
int opos,
int replacelast,
int complete);
00371
struct verb *next;
00372 } *verboser = NULL;
00373
00374
00375
static char logger_reload_help[] =
00376
"Usage: logger reload\n"
00377
" Reloads the logger subsystem state. Use after restarting syslogd(8)\n";
00378
00379
static char logger_rotate_help[] =
00380
"Usage: logger rotate\n"
00381
" Rotates and Reopens the log files.\n";
00382
00383
static struct ast_cli_entry reload_logger_cli =
00384 { {
"logger",
"reload", NULL },
00385 handle_logger_reload,
"Reopens the log files",
00386 logger_reload_help };
00387
00388
static struct ast_cli_entry rotate_logger_cli =
00389 { {
"logger",
"rotate", NULL },
00390 handle_logger_rotate,
"Rotates and reopens the log files",
00391 logger_rotate_help };
00392
00393
static int handle_SIGXFSZ(
int sig) {
00394
00395 pending_logger_reload = 1;
00396
return 0;
00397 }
00398
00399 int init_logger(
void)
00400 {
00401
char tmp[256];
00402
00403
00404 (
void) signal(SIGXFSZ,(
void *) handle_SIGXFSZ);
00405
00406
00407
ast_cli_register(&reload_logger_cli);
00408
ast_cli_register(&rotate_logger_cli);
00409
00410
00411 queue_log_init();
00412
00413
00414 mkdir((
char *)
ast_config_AST_LOG_DIR, 0755);
00415 snprintf(tmp,
sizeof(tmp),
"%s/%s", (
char *)
ast_config_AST_LOG_DIR,
EVENTLOG);
00416 eventlog = fopen((
char *)tmp,
"a");
00417
if (eventlog) {
00418 init_logger_chain();
00419
ast_log(
LOG_EVENT,
"Started Asterisk Event Logger\n");
00420
if (
option_verbose)
00421
ast_verbose(
"Asterisk Event Logger Started %s\n",(
char *)tmp);
00422
return 0;
00423 }
else
00424
ast_log(
LOG_ERROR,
"Unable to create event log: %s\n", strerror(errno));
00425
00426 init_logger_chain();
00427
00428
00429 init_logger_chain();
00430
return -1;
00431 }
00432
00433
static void ast_log_vsyslog(
int level,
const char *file,
int line,
const char *function,
const char *fmt, va_list args) {
00434
char buf[BUFSIZ];
00435
00436
if(level >=
SYSLOG_NLEVELS) {
00437
00438 fprintf(stderr,
"ast_log_vsyslog called with bogus level: %d\n", level);
00439
return;
00440 }
00441
if(level ==
__LOG_VERBOSE) {
00442 snprintf(buf,
sizeof(buf),
"VERBOSE[%ld]: ", (
long)pthread_self());
00443 level =
__LOG_DEBUG;
00444 }
else {
00445 snprintf(buf,
sizeof(buf),
"%s[%ld]: %s:%d in %s: ",
00446 levels[level], (
long)pthread_self(), file, line, function);
00447 }
00448 vsnprintf(buf+strlen(buf),
sizeof(buf)-strlen(buf), fmt, args);
00449 syslog(syslog_level_map[level],
"%s", buf);
00450 }
00451
00452
00453
00454
00455 void ast_log(
int level,
const char *file,
int line,
const char *function,
const char *fmt, ...)
00456 {
00457
struct logchannel *chan;
00458
char buf[BUFSIZ];
00459 time_t t;
00460
struct tm tm;
00461
char date[256];
00462
00463 va_list ap;
00464
00465
if (!
option_verbose && !
option_debug && (level ==
__LOG_DEBUG)) {
00466
return;
00467 }
00468
00469
00470
ast_mutex_lock(&loglock);
00471
00472 time(&t);
00473 localtime_r(&t, &tm);
00474 strftime(date,
sizeof(date), dateformat, &tm);
00475
00476
00477
if (level ==
__LOG_EVENT) {
00478 va_start(ap, fmt);
00479
00480 fprintf(eventlog,
"%s asterisk[%d]: ", date, getpid());
00481 vfprintf(eventlog, fmt, ap);
00482 fflush(eventlog);
00483
00484 va_end(ap);
00485
ast_mutex_unlock(&loglock);
00486
return;
00487 }
00488
00489
if (logchannels) {
00490 chan = logchannels;
00491
while(chan) {
00492
if (chan->syslog && (chan->logmask & (1 << level))) {
00493 va_start(ap, fmt);
00494 ast_log_vsyslog(level, file, line, function, fmt, ap);
00495 va_end(ap);
00496 }
else if ((chan->logmask & (1 << level)) && (chan->console)) {
00497
char linestr[128];
00498
char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
00499
00500
if(level !=
__LOG_VERBOSE) {
00501 sprintf(linestr,
"%d", line);
00502 snprintf(buf,
sizeof(buf),
"%s %s[%ld]: %s:%s %s: ",
00503 date,
00504
term_color(tmp1, levels[level], colors[level], 0,
sizeof(tmp1)),
00505 (
long)pthread_self(),
00506
term_color(tmp2, file,
COLOR_BRWHITE, 0,
sizeof(tmp2)),
00507
term_color(tmp3, linestr,
COLOR_BRWHITE, 0,
sizeof(tmp3)),
00508
term_color(tmp4, function,
COLOR_BRWHITE, 0,
sizeof(tmp4)));
00509
00510
ast_console_puts(buf);
00511 va_start(ap, fmt);
00512 vsnprintf(buf,
sizeof(buf), fmt, ap);
00513 va_end(ap);
00514
ast_console_puts(buf);
00515 }
00516 }
else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
00517 snprintf(buf,
sizeof(buf),
"%s %s[%ld]: ", date,
00518 levels[level], (
long)pthread_self());
00519 fprintf(chan->fileptr, buf);
00520 va_start(ap, fmt);
00521 vsnprintf(buf,
sizeof(buf), fmt, ap);
00522 va_end(ap);
00523 fputs(buf, chan->fileptr);
00524 fflush(chan->fileptr);
00525 }
00526 chan = chan->next;
00527 }
00528 }
else {
00529
00530
00531
00532
00533
if (level !=
__LOG_VERBOSE) {
00534 va_start(ap, fmt);
00535 vsnprintf(buf,
sizeof(buf), fmt, ap);
00536 va_end(ap);
00537 fputs(buf, stdout);
00538 }
00539 }
00540
00541
ast_mutex_unlock(&loglock);
00542
00543
if (pending_logger_reload) {
00544
reload_logger(1);
00545
ast_log(
LOG_EVENT,
"Rotated Logs Per SIGXFSZ\n");
00546
if (
option_verbose)
00547
ast_verbose(
"Rotated Logs Per SIGXFSZ\n");
00548 }
00549 }
00550
00551 extern void ast_verbose(
const char *fmt, ...)
00552 {
00553
static char stuff[4096];
00554
static int pos = 0, opos;
00555
static int replacelast = 0, complete;
00556
struct msglist *m;
00557
struct verb *v;
00558 va_list ap;
00559 va_start(ap, fmt);
00560
ast_mutex_lock(&msglist_lock);
00561 vsnprintf(stuff + pos,
sizeof(stuff) - pos, fmt, ap);
00562 opos = pos;
00563 pos = strlen(stuff);
00564
if (fmt[strlen(fmt)-1] ==
'\n')
00565 complete = 1;
00566
else
00567 complete=0;
00568
if (complete) {
00569
if (msgcnt <
MAX_MSG_QUEUE) {
00570
00571 m =
malloc(
sizeof(
struct msglist));
00572 msgcnt++;
00573 }
else {
00574
00575 m = list;
00576 list = list->next;
00577
free(m->msg);
00578 }
00579
if (m) {
00580 m->msg =
strdup(stuff);
00581
if (m->msg) {
00582
if (last)
00583 last->next = m;
00584
else
00585 list = m;
00586 m->next = NULL;
00587 last = m;
00588 }
else {
00589 msgcnt--;
00590
ast_log(
LOG_ERROR,
"Out of memory\n");
00591
free(m);
00592 }
00593 }
00594 }
00595
if (verboser) {
00596 v = verboser;
00597
while(v) {
00598 v->verboser(stuff, opos, replacelast, complete);
00599 v = v->next;
00600 }
00601 }
00602
00603
00604
ast_log(
LOG_VERBOSE, stuff);
00605
00606
if (fmt[strlen(fmt)-1] !=
'\n')
00607 replacelast = 1;
00608
else
00609 replacelast = pos = 0;
00610 va_end(ap);
00611
00612
ast_mutex_unlock(&msglist_lock);
00613 }
00614
00615 int ast_verbose_dmesg(
void (*v)(
const char *string,
int opos,
int replacelast,
int complete))
00616 {
00617
struct msglist *m;
00618 m = list;
00619
ast_mutex_lock(&msglist_lock);
00620
while(m) {
00621
00622 v(m->msg, 0, 0, 1);
00623 m = m->next;
00624 }
00625
ast_mutex_unlock(&msglist_lock);
00626
return 0;
00627 }
00628
00629 int ast_register_verbose(
void (*v)(
const char *string,
int opos,
int replacelast,
int complete))
00630 {
00631
struct msglist *m;
00632
struct verb *tmp;
00633
00634
if ((tmp =
malloc(
sizeof (
struct verb)))) {
00635 tmp->verboser = v;
00636
ast_mutex_lock(&msglist_lock);
00637 tmp->next = verboser;
00638 verboser = tmp;
00639 m = list;
00640
while(m) {
00641
00642 v(m->msg, 0, 0, 1);
00643 m = m->next;
00644 }
00645
ast_mutex_unlock(&msglist_lock);
00646
return 0;
00647 }
00648
return -1;
00649 }
00650
00651 int ast_unregister_verbose(
void (*v)(
const char *string,
int opos,
int replacelast,
int complete))
00652 {
00653
int res = -1;
00654
struct verb *tmp, *tmpl=NULL;
00655
ast_mutex_lock(&msglist_lock);
00656 tmp = verboser;
00657
while(tmp) {
00658
if (tmp->verboser == v) {
00659
if (tmpl)
00660 tmpl->next = tmp->next;
00661
else
00662 verboser = tmp->next;
00663
free(tmp);
00664
break;
00665 }
00666 tmpl = tmp;
00667 tmp = tmp->next;
00668 }
00669
if (tmp)
00670 res = 0;
00671
ast_mutex_unlock(&msglist_lock);
00672
return res;
00673 }