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 <sys/stat.h>
00030
#include "asterisk.h"
00031
#include "astconf.h"
00032
00033 #define SYSLOG_NAMES
00034
00035
#include <syslog.h>
00036
static int syslog_level_map[] = {
00037
LOG_DEBUG,
00038 LOG_INFO,
00039
LOG_NOTICE,
00040
LOG_WARNING,
00041 LOG_ERR,
00042
LOG_DEBUG
00043 };
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 strncpy(dateformat, s,
sizeof(dateformat) - 1);
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) - 1);
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
00396 pending_logger_reload = 1;
00397
return 0;
00398 }
00399
00400 int init_logger(
void)
00401 {
00402
char tmp[256];
00403
00404
00405 (
void) signal(SIGXFSZ,(
void *) handle_SIGXFSZ);
00406
00407
00408
ast_cli_register(&reload_logger_cli);
00409
ast_cli_register(&rotate_logger_cli);
00410
00411
00412 queue_log_init();
00413
00414
00415 mkdir((
char *)
ast_config_AST_LOG_DIR, 0755);
00416 snprintf(tmp,
sizeof(tmp),
"%s/%s", (
char *)
ast_config_AST_LOG_DIR,
EVENTLOG);
00417 eventlog = fopen((
char *)tmp,
"a");
00418
if (eventlog) {
00419 init_logger_chain();
00420
ast_log(
LOG_EVENT,
"Started Asterisk Event Logger\n");
00421
if (
option_verbose)
00422
ast_verbose(
"Asterisk Event Logger Started %s\n",(
char *)tmp);
00423
return 0;
00424 }
else
00425
ast_log(
LOG_ERROR,
"Unable to create event log: %s\n", strerror(errno));
00426
00427
00428 init_logger_chain();
00429
return -1;
00430 }
00431
00432 void close_logger(
void)
00433 {
00434
struct msglist *m, *tmp;
00435
00436 m = list;
00437
ast_mutex_lock(&msglist_lock);
00438
while(m) {
00439
if (m->msg) {
00440
free(m->msg);
00441 }
00442 tmp = m->next;
00443
free(m);
00444 m = tmp;
00445 }
00446 list = last = NULL;
00447
ast_mutex_unlock(&msglist_lock);
00448
return;
00449 }
00450
00451
static void ast_log_vsyslog(
int level,
const char *file,
int line,
const char *function,
const char *fmt, va_list args)
00452 {
00453
char buf[BUFSIZ];
00454
00455
if (level >=
SYSLOG_NLEVELS) {
00456
00457 fprintf(stderr,
"ast_log_vsyslog called with bogus level: %d\n", level);
00458
return;
00459 }
00460
if (level ==
__LOG_VERBOSE) {
00461 snprintf(buf,
sizeof(buf),
"VERBOSE[%ld]: ", (
long)pthread_self());
00462 level =
__LOG_DEBUG;
00463 }
else {
00464 snprintf(buf,
sizeof(buf),
"%s[%ld]: %s:%d in %s: ",
00465 levels[level], (
long)pthread_self(), file, line, function);
00466 }
00467 vsnprintf(buf+strlen(buf),
sizeof(buf)-strlen(buf), fmt, args);
00468 syslog(syslog_level_map[level],
"%s", buf);
00469 }
00470
00471
00472
00473
00474 void ast_log(
int level,
const char *file,
int line,
const char *function,
const char *fmt, ...)
00475 {
00476
struct logchannel *chan;
00477
char buf[BUFSIZ];
00478 time_t t;
00479
struct tm tm;
00480
char date[256];
00481
00482 va_list ap;
00483
00484
if (!
option_verbose && !
option_debug && (level ==
__LOG_DEBUG)) {
00485
return;
00486 }
00487
00488
00489
ast_mutex_lock(&loglock);
00490
00491 time(&t);
00492 localtime_r(&t, &tm);
00493 strftime(date,
sizeof(date), dateformat, &tm);
00494
00495
if (level ==
__LOG_EVENT) {
00496 va_start(ap, fmt);
00497
00498 fprintf(eventlog,
"%s asterisk[%d]: ", date, getpid());
00499 vfprintf(eventlog, fmt, ap);
00500 fflush(eventlog);
00501
00502 va_end(ap);
00503
ast_mutex_unlock(&loglock);
00504
return;
00505 }
00506
00507
if (logchannels) {
00508 chan = logchannels;
00509
while(chan) {
00510
if (chan->syslog && (chan->logmask & (1 << level))) {
00511 va_start(ap, fmt);
00512 ast_log_vsyslog(level, file, line, function, fmt, ap);
00513 va_end(ap);
00514 }
else if ((chan->logmask & (1 << level)) && (chan->console)) {
00515
char linestr[128];
00516
char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
00517
00518
if (level !=
__LOG_VERBOSE) {
00519 sprintf(linestr,
"%d", line);
00520 snprintf(buf,
sizeof(buf),
"%s %s[%ld]: %s:%s %s: ",
00521 date,
00522
term_color(tmp1, levels[level], colors[level], 0,
sizeof(tmp1)),
00523 (
long)pthread_self(),
00524
term_color(tmp2, file,
COLOR_BRWHITE, 0,
sizeof(tmp2)),
00525
term_color(tmp3, linestr,
COLOR_BRWHITE, 0,
sizeof(tmp3)),
00526
term_color(tmp4, function,
COLOR_BRWHITE, 0,
sizeof(tmp4)));
00527
00528
ast_console_puts(buf);
00529 va_start(ap, fmt);
00530 vsnprintf(buf,
sizeof(buf), fmt, ap);
00531 va_end(ap);
00532
ast_console_puts(buf);
00533 }
00534 }
else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
00535 snprintf(buf,
sizeof(buf),
"%s %s[%ld]: ", date,
00536 levels[level], (
long)pthread_self());
00537 fprintf(chan->fileptr, buf);
00538 va_start(ap, fmt);
00539 vsnprintf(buf,
sizeof(buf), fmt, ap);
00540 va_end(ap);
00541 fputs(buf, chan->fileptr);
00542 fflush(chan->fileptr);
00543 }
00544 chan = chan->next;
00545 }
00546 }
else {
00547
00548
00549
00550
00551
if (level !=
__LOG_VERBOSE) {
00552 va_start(ap, fmt);
00553 vsnprintf(buf,
sizeof(buf), fmt, ap);
00554 va_end(ap);
00555 fputs(buf, stdout);
00556 }
00557 }
00558
00559
ast_mutex_unlock(&loglock);
00560
00561
if (pending_logger_reload) {
00562
reload_logger(1);
00563
ast_log(
LOG_EVENT,
"Rotated Logs Per SIGXFSZ\n");
00564
if (
option_verbose)
00565
ast_verbose(
"Rotated Logs Per SIGXFSZ\n");
00566 }
00567 }
00568
00569 extern void ast_verbose(
const char *fmt, ...)
00570 {
00571
static char stuff[4096];
00572
static int pos = 0, opos;
00573
static int replacelast = 0, complete;
00574
struct msglist *m;
00575
struct verb *v;
00576 va_list ap;
00577 va_start(ap, fmt);
00578
ast_mutex_lock(&msglist_lock);
00579 vsnprintf(stuff + pos,
sizeof(stuff) - pos, fmt, ap);
00580 opos = pos;
00581 pos = strlen(stuff);
00582
if (fmt[strlen(fmt)-1] ==
'\n')
00583 complete = 1;
00584
else
00585 complete=0;
00586
if (complete) {
00587
if (msgcnt <
MAX_MSG_QUEUE) {
00588
00589 m =
malloc(
sizeof(
struct msglist));
00590 msgcnt++;
00591 }
else {
00592
00593 m = list;
00594 list = list->next;
00595
free(m->msg);
00596 }
00597
if (m) {
00598 m->msg =
strdup(stuff);
00599
if (m->msg) {
00600
if (last)
00601 last->next = m;
00602
else
00603 list = m;
00604 m->next = NULL;
00605 last = m;
00606 }
else {
00607 msgcnt--;
00608
ast_log(
LOG_ERROR,
"Out of memory\n");
00609
free(m);
00610 }
00611 }
00612 }
00613
if (verboser) {
00614 v = verboser;
00615
while(v) {
00616 v->verboser(stuff, opos, replacelast, complete);
00617 v = v->next;
00618 }
00619 }
00620
00621
00622
ast_log(
LOG_VERBOSE, stuff);
00623
00624
if (fmt[strlen(fmt)-1] !=
'\n')
00625 replacelast = 1;
00626
else
00627 replacelast = pos = 0;
00628 va_end(ap);
00629
00630
ast_mutex_unlock(&msglist_lock);
00631 }
00632
00633 int ast_verbose_dmesg(
void (*v)(
const char *string,
int opos,
int replacelast,
int complete))
00634 {
00635
struct msglist *m;
00636 m = list;
00637
ast_mutex_lock(&msglist_lock);
00638
while(m) {
00639
00640 v(m->msg, 0, 0, 1);
00641 m = m->next;
00642 }
00643
ast_mutex_unlock(&msglist_lock);
00644
return 0;
00645 }
00646
00647 int ast_register_verbose(
void (*v)(
const char *string,
int opos,
int replacelast,
int complete))
00648 {
00649
struct msglist *m;
00650
struct verb *tmp;
00651
00652
if ((tmp =
malloc(
sizeof (
struct verb)))) {
00653 tmp->verboser = v;
00654
ast_mutex_lock(&msglist_lock);
00655 tmp->next = verboser;
00656 verboser = tmp;
00657 m = list;
00658
while(m) {
00659
00660 v(m->msg, 0, 0, 1);
00661 m = m->next;
00662 }
00663
ast_mutex_unlock(&msglist_lock);
00664
return 0;
00665 }
00666
return -1;
00667 }
00668
00669 int ast_unregister_verbose(
void (*v)(
const char *string,
int opos,
int replacelast,
int complete))
00670 {
00671
int res = -1;
00672
struct verb *tmp, *tmpl=NULL;
00673
ast_mutex_lock(&msglist_lock);
00674 tmp = verboser;
00675
while(tmp) {
00676
if (tmp->verboser == v) {
00677
if (tmpl)
00678 tmpl->next = tmp->next;
00679
else
00680 verboser = tmp->next;
00681
free(tmp);
00682
break;
00683 }
00684 tmpl = tmp;
00685 tmp = tmp->next;
00686 }
00687
if (tmp)
00688 res = 0;
00689
ast_mutex_unlock(&msglist_lock);
00690
return res;
00691 }