logger.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. /*
  2. * Asterisk Logger
  3. *
  4. * Mark Spencer <markster@marko.net>
  5. *
  6. * Copyright(C)1999, Linux Support Services, Inc.
  7. *
  8. * Distributed under the terms of the GNU General Public License (GPL) Version 2
  9. *
  10. * Logging routines
  11. *
  12. */
  13. #include <signal.h>
  14. #include <stdarg.h>
  15. #include <stdio.h>
  16. #include <unistd.h>
  17. #include <time.h>
  18. #include <asterisk/lock.h>
  19. #include <asterisk/options.h>
  20. #include <asterisk/channel.h>
  21. #include <asterisk/config.h>
  22. #include <asterisk/term.h>
  23. #include <asterisk/cli.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <errno.h>
  27. #include <pthread.h>
  28. #include <sys/stat.h>
  29. #include "asterisk.h"
  30. #include "astconf.h"
  31. #define SYSLOG_NAMES /* so we can map syslog facilities names to their numeric values,
  32. from <syslog.h> which is included by logger.h */
  33. #include <syslog.h>
  34. static int syslog_level_map[] = {
  35. LOG_DEBUG,
  36. LOG_INFO, /* arbitrary equivalent of LOG_EVENT */
  37. LOG_NOTICE,
  38. LOG_WARNING,
  39. LOG_ERR,
  40. LOG_DEBUG
  41. };
  42. #define SYSLOG_NLEVELS 6
  43. #include <asterisk/logger.h>
  44. #define MAX_MSG_QUEUE 200
  45. static ast_mutex_t msglist_lock = AST_MUTEX_INITIALIZER;
  46. static ast_mutex_t loglock = AST_MUTEX_INITIALIZER;
  47. static int pending_logger_reload = 0;
  48. static struct msglist {
  49. char *msg;
  50. struct msglist *next;
  51. } *list = NULL, *last = NULL;
  52. struct logchannel {
  53. int logmask;
  54. int facility; /* syslog */
  55. int syslog; /* syslog flag */
  56. int console; /* console logging */
  57. FILE *fileptr; /* logfile logging */
  58. char filename[256];
  59. struct logchannel *next;
  60. };
  61. static struct logchannel *logchannels = NULL;
  62. static int msgcnt = 0;
  63. static FILE *eventlog = NULL;
  64. static char *levels[] = {
  65. "DEBUG",
  66. "EVENT",
  67. "NOTICE",
  68. "WARNING",
  69. "ERROR",
  70. "VERBOSE"
  71. };
  72. static int colors[] = {
  73. COLOR_BRGREEN,
  74. COLOR_BRBLUE,
  75. COLOR_YELLOW,
  76. COLOR_BRRED,
  77. COLOR_RED,
  78. COLOR_GREEN
  79. };
  80. static int make_components(char *s, int lineno)
  81. {
  82. char *w;
  83. int res = 0;
  84. char *stringp=NULL;
  85. stringp=s;
  86. w = strsep(&stringp, ",");
  87. while(w) {
  88. while(*w && (*w < 33))
  89. w++;
  90. if (!strcasecmp(w, "error"))
  91. res |= (1 << __LOG_ERROR);
  92. else if (!strcasecmp(w, "warning"))
  93. res |= (1 << __LOG_WARNING);
  94. else if (!strcasecmp(w, "notice"))
  95. res |= (1 << __LOG_NOTICE);
  96. else if (!strcasecmp(w, "event"))
  97. res |= (1 << __LOG_EVENT);
  98. else if (!strcasecmp(w, "debug"))
  99. res |= (1 << __LOG_DEBUG);
  100. else if (!strcasecmp(w, "verbose"))
  101. res |= (1 << __LOG_VERBOSE);
  102. else {
  103. fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno);
  104. }
  105. w = strsep(&stringp, ",");
  106. }
  107. return res;
  108. }
  109. static struct logchannel *make_logchannel(char *channel, char *components, int lineno)
  110. {
  111. struct logchannel *chan;
  112. char *facility;
  113. CODE *cptr;
  114. if (!strlen(channel))
  115. return NULL;
  116. chan = malloc(sizeof(struct logchannel));
  117. if (chan) {
  118. memset(chan, 0, sizeof(struct logchannel));
  119. if (!strcasecmp(channel, "console")) {
  120. chan->console = 1;
  121. } else if (!strncasecmp(channel, "syslog", 6)) {
  122. /*
  123. * syntax is:
  124. * syslog.facility => level,level,level
  125. */
  126. facility = strchr(channel, '.');
  127. if(!facility++ || !facility) {
  128. facility = "local0";
  129. }
  130. /*
  131. * Walk through the list of facilitynames (defined in sys/syslog.h)
  132. * to see if we can find the one we have been given
  133. */
  134. chan->facility = -1;
  135. cptr = facilitynames;
  136. while (cptr->c_name) {
  137. if (!strncasecmp(facility, cptr->c_name, sizeof(cptr->c_name))) {
  138. chan->facility = cptr->c_val;
  139. break;
  140. }
  141. cptr++;
  142. }
  143. if (0 > chan->facility) {
  144. fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
  145. free(chan);
  146. return NULL;
  147. }
  148. chan->syslog = 1;
  149. openlog("asterisk", LOG_PID, chan->facility);
  150. } else {
  151. if (channel[0] == '/')
  152. strncpy(chan->filename, channel, sizeof(chan->filename) - 1);
  153. else
  154. snprintf(chan->filename, sizeof(chan->filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, channel);
  155. chan->fileptr = fopen(chan->filename, "a");
  156. if (!chan->fileptr) {
  157. /* Can't log here, since we're called with a lock */
  158. fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno));
  159. }
  160. }
  161. chan->logmask = make_components(components, lineno);
  162. }
  163. return chan;
  164. }
  165. static void init_logger_chain(void)
  166. {
  167. struct logchannel *chan, *cur;
  168. struct ast_config *cfg;
  169. struct ast_variable *var;
  170. /* delete our list of log channels */
  171. ast_mutex_lock(&loglock);
  172. chan = logchannels;
  173. while (chan) {
  174. cur = chan->next;
  175. free(chan);
  176. chan = cur;
  177. }
  178. logchannels = NULL;
  179. ast_mutex_unlock(&loglock);
  180. /* close syslog */
  181. closelog();
  182. cfg = ast_load("logger.conf");
  183. /* If no config file, we're fine */
  184. if (!cfg)
  185. return;
  186. ast_mutex_lock(&loglock);
  187. var = ast_variable_browse(cfg, "logfiles");
  188. while(var) {
  189. chan = make_logchannel(var->name, var->value, var->lineno);
  190. if (chan) {
  191. chan->next = logchannels;
  192. logchannels = chan;
  193. }
  194. var = var->next;
  195. }
  196. ast_destroy(cfg);
  197. ast_mutex_unlock(&loglock);
  198. }
  199. int reload_logger(int rotate)
  200. {
  201. char old[AST_CONFIG_MAX_PATH];
  202. char new[AST_CONFIG_MAX_PATH];
  203. struct logchannel *f;
  204. FILE *myf;
  205. int x;
  206. ast_mutex_lock(&loglock);
  207. if (eventlog)
  208. fclose(eventlog);
  209. else
  210. rotate = 0;
  211. eventlog = NULL;
  212. mkdir((char *)ast_config_AST_LOG_DIR, 0755);
  213. snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
  214. if(rotate) {
  215. for(x=0;;x++) {
  216. snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, EVENTLOG,x);
  217. myf = fopen((char *)new, "r");
  218. if(myf)
  219. fclose(myf);
  220. else
  221. break;
  222. }
  223. /* do it */
  224. if (rename(old,new))
  225. fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
  226. }
  227. eventlog = fopen(old, "a");
  228. f = logchannels;
  229. while(f) {
  230. if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
  231. fclose(f->fileptr);
  232. f->fileptr = NULL;
  233. if(rotate) {
  234. strncpy(old, f->filename, sizeof(old));
  235. for(x=0;;x++) {
  236. snprintf(new, sizeof(new), "%s.%d", f->filename, x);
  237. myf = fopen((char *)new, "r");
  238. if (myf) {
  239. fclose(myf);
  240. } else {
  241. break;
  242. }
  243. }
  244. /* do it */
  245. if (rename(old,new))
  246. fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
  247. }
  248. }
  249. f = f->next;
  250. }
  251. ast_mutex_unlock(&loglock);
  252. if (eventlog) {
  253. init_logger_chain();
  254. ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
  255. if (option_verbose)
  256. ast_verbose("Asterisk Event Logger restarted\n");
  257. return 0;
  258. } else
  259. ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
  260. init_logger_chain();
  261. pending_logger_reload = 0;
  262. return -1;
  263. }
  264. static int handle_logger_reload(int fd, int argc, char *argv[])
  265. {
  266. if(reload_logger(0))
  267. {
  268. ast_cli(fd, "Failed to reloadthe logger\n");
  269. return RESULT_FAILURE;
  270. }
  271. else
  272. return RESULT_SUCCESS;
  273. }
  274. static int handle_logger_rotate(int fd, int argc, char *argv[])
  275. {
  276. if(reload_logger(1))
  277. {
  278. ast_cli(fd, "Failed to reloadthe logger\n");
  279. return RESULT_FAILURE;
  280. }
  281. else
  282. return RESULT_SUCCESS;
  283. }
  284. static struct verb {
  285. void (*verboser)(const char *string, int opos, int replacelast, int complete);
  286. struct verb *next;
  287. } *verboser = NULL;
  288. static char logger_reload_help[] =
  289. "Usage: logger reload\n"
  290. " Reloads the logger subsystem state. Use after restarting syslogd(8)\n";
  291. static char logger_rotate_help[] =
  292. "Usage: logger rotate\n"
  293. " Rotates and Reopens the log files.\n";
  294. static struct ast_cli_entry reload_logger_cli =
  295. { { "logger", "reload", NULL },
  296. handle_logger_reload, "Reopens the log files",
  297. logger_reload_help };
  298. static struct ast_cli_entry rotate_logger_cli =
  299. { { "logger", "rotate", NULL },
  300. handle_logger_rotate, "Rotates and reopens the log files",
  301. logger_rotate_help };
  302. static int handle_SIGXFSZ(int sig) {
  303. /* Indicate need to reload */
  304. pending_logger_reload = 1;
  305. return 0;
  306. }
  307. int init_logger(void)
  308. {
  309. char tmp[256];
  310. /* auto rotate if sig SIGXFSZ comes a-knockin */
  311. (void) signal(SIGXFSZ,(void *) handle_SIGXFSZ);
  312. /* register the relaod logger cli command */
  313. ast_cli_register(&reload_logger_cli);
  314. ast_cli_register(&rotate_logger_cli);
  315. /* create the eventlog */
  316. mkdir((char *)ast_config_AST_LOG_DIR, 0755);
  317. snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
  318. eventlog = fopen((char *)tmp, "a");
  319. if (eventlog) {
  320. init_logger_chain();
  321. ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
  322. if (option_verbose)
  323. ast_verbose("Asterisk Event Logger Started %s\n",(char *)tmp);
  324. return 0;
  325. } else
  326. ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
  327. init_logger_chain();
  328. /* create log channels */
  329. init_logger_chain();
  330. return -1;
  331. }
  332. static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args) {
  333. char buf[BUFSIZ];
  334. if(level >= SYSLOG_NLEVELS) {
  335. /* we are locked here, so cannot ast_log() */
  336. fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level);
  337. return;
  338. }
  339. if(level == __LOG_VERBOSE) {
  340. snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)pthread_self());
  341. level = __LOG_DEBUG;
  342. } else {
  343. snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
  344. levels[level], (long)pthread_self(), file, line, function);
  345. }
  346. vsnprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), fmt, args);
  347. syslog(syslog_level_map[level], "%s", buf);
  348. }
  349. /*
  350. * send log messages to syslog and/or the console
  351. */
  352. void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
  353. {
  354. struct logchannel *chan;
  355. char buf[BUFSIZ];
  356. time_t t;
  357. struct tm tm;
  358. char date[256];
  359. va_list ap;
  360. if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) {
  361. return;
  362. }
  363. /* begin critical section */
  364. ast_mutex_lock(&loglock);
  365. time(&t);
  366. localtime_r(&t, &tm);
  367. strftime(date, sizeof(date), "%b %e %T", &tm);
  368. if (level == __LOG_EVENT) {
  369. va_start(ap, fmt);
  370. fprintf(eventlog, "%s asterisk[%d]: ", date, getpid());
  371. vfprintf(eventlog, fmt, ap);
  372. fflush(eventlog);
  373. va_end(ap);
  374. ast_mutex_unlock(&loglock);
  375. return;
  376. }
  377. if (logchannels) {
  378. chan = logchannels;
  379. while(chan) {
  380. if (chan->syslog && (chan->logmask & (1 << level))) {
  381. va_start(ap, fmt);
  382. ast_log_vsyslog(level, file, line, function, fmt, ap);
  383. va_end(ap);
  384. } else if ((chan->logmask & (1 << level)) && (chan->console)) {
  385. char linestr[128];
  386. char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
  387. if(level != __LOG_VERBOSE) {
  388. sprintf(linestr, "%d", line);
  389. snprintf(buf, sizeof(buf), "%s %s[%ld]: %s:%s %s: ",
  390. date,
  391. term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
  392. (long)pthread_self(),
  393. term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
  394. term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
  395. term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
  396. ast_console_puts(buf);
  397. va_start(ap, fmt);
  398. vsnprintf(buf, sizeof(buf), fmt, ap);
  399. va_end(ap);
  400. ast_console_puts(buf);
  401. }
  402. } else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
  403. snprintf(buf, sizeof(buf), "%s %s[%ld]: ", date,
  404. levels[level], (long)pthread_self());
  405. fprintf(chan->fileptr, buf);
  406. va_start(ap, fmt);
  407. vsnprintf(buf, sizeof(buf), fmt, ap);
  408. va_end(ap);
  409. fputs(buf, chan->fileptr);
  410. fflush(chan->fileptr);
  411. }
  412. chan = chan->next;
  413. }
  414. } else {
  415. /*
  416. * we don't have the logger chain configured yet,
  417. * so just log to stdout
  418. */
  419. if (level != __LOG_VERBOSE) {
  420. va_start(ap, fmt);
  421. vsnprintf(buf, sizeof(buf), fmt, ap);
  422. va_end(ap);
  423. fputs(buf, stdout);
  424. }
  425. }
  426. ast_mutex_unlock(&loglock);
  427. /* end critical section */
  428. if (pending_logger_reload) {
  429. reload_logger(1);
  430. ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ\n");
  431. if (option_verbose)
  432. ast_verbose("Rotated Logs Per SIGXFSZ\n");
  433. }
  434. }
  435. extern void ast_verbose(const char *fmt, ...)
  436. {
  437. static char stuff[4096];
  438. static int pos = 0, opos;
  439. static int replacelast = 0, complete;
  440. struct msglist *m;
  441. struct verb *v;
  442. va_list ap;
  443. va_start(ap, fmt);
  444. ast_mutex_lock(&msglist_lock);
  445. vsnprintf(stuff + pos, sizeof(stuff) - pos, fmt, ap);
  446. opos = pos;
  447. pos = strlen(stuff);
  448. if (fmt[strlen(fmt)-1] == '\n')
  449. complete = 1;
  450. else
  451. complete=0;
  452. if (complete) {
  453. if (msgcnt < MAX_MSG_QUEUE) {
  454. /* Allocate new structure */
  455. m = malloc(sizeof(struct msglist));
  456. msgcnt++;
  457. } else {
  458. /* Recycle the oldest entry */
  459. m = list;
  460. list = list->next;
  461. free(m->msg);
  462. }
  463. if (m) {
  464. m->msg = strdup(stuff);
  465. if (m->msg) {
  466. if (last)
  467. last->next = m;
  468. else
  469. list = m;
  470. m->next = NULL;
  471. last = m;
  472. } else {
  473. msgcnt--;
  474. ast_log(LOG_ERROR, "Out of memory\n");
  475. free(m);
  476. }
  477. }
  478. }
  479. if (verboser) {
  480. v = verboser;
  481. while(v) {
  482. v->verboser(stuff, opos, replacelast, complete);
  483. v = v->next;
  484. }
  485. } /* else
  486. fprintf(stdout, stuff + opos); */
  487. ast_log(LOG_VERBOSE, stuff);
  488. if (fmt[strlen(fmt)-1] != '\n')
  489. replacelast = 1;
  490. else
  491. replacelast = pos = 0;
  492. va_end(ap);
  493. ast_mutex_unlock(&msglist_lock);
  494. }
  495. int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete))
  496. {
  497. struct msglist *m;
  498. m = list;
  499. ast_mutex_lock(&msglist_lock);
  500. while(m) {
  501. /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
  502. v(m->msg, 0, 0, 1);
  503. m = m->next;
  504. }
  505. ast_mutex_unlock(&msglist_lock);
  506. return 0;
  507. }
  508. int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
  509. {
  510. struct msglist *m;
  511. struct verb *tmp;
  512. /* XXX Should be more flexible here, taking > 1 verboser XXX */
  513. if ((tmp = malloc(sizeof (struct verb)))) {
  514. tmp->verboser = v;
  515. ast_mutex_lock(&msglist_lock);
  516. tmp->next = verboser;
  517. verboser = tmp;
  518. m = list;
  519. while(m) {
  520. /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
  521. v(m->msg, 0, 0, 1);
  522. m = m->next;
  523. }
  524. ast_mutex_unlock(&msglist_lock);
  525. return 0;
  526. }
  527. return -1;
  528. }
  529. int ast_unregister_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
  530. {
  531. int res = -1;
  532. struct verb *tmp, *tmpl=NULL;
  533. ast_mutex_lock(&msglist_lock);
  534. tmp = verboser;
  535. while(tmp) {
  536. if (tmp->verboser == v) {
  537. if (tmpl)
  538. tmpl->next = tmp->next;
  539. else
  540. verboser = tmp->next;
  541. free(tmp);
  542. break;
  543. }
  544. tmpl = tmp;
  545. tmp = tmp->next;
  546. }
  547. if (tmp)
  548. res = 0;
  549. ast_mutex_unlock(&msglist_lock);
  550. return res;
  551. }