logger.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. * \brief Asterisk Logger
  20. *
  21. * Logging routines
  22. *
  23. */
  24. #include <signal.h>
  25. #include <stdarg.h>
  26. #include <stdio.h>
  27. #include <unistd.h>
  28. #include <time.h>
  29. #include <string.h>
  30. #include <stdlib.h>
  31. #include <errno.h>
  32. #include <sys/stat.h>
  33. #define SYSLOG_NAMES /* so we can map syslog facilities names to their numeric values,
  34. from <syslog.h> which is included by logger.h */
  35. #include <syslog.h>
  36. #include "asterisk.h"
  37. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  38. static int syslog_level_map[] = {
  39. LOG_DEBUG,
  40. LOG_INFO, /* arbitrary equivalent of LOG_EVENT */
  41. LOG_NOTICE,
  42. LOG_WARNING,
  43. LOG_ERR,
  44. LOG_DEBUG,
  45. LOG_DEBUG
  46. };
  47. #define SYSLOG_NLEVELS sizeof(syslog_level_map) / sizeof(int)
  48. #include "asterisk/logger.h"
  49. #include "asterisk/lock.h"
  50. #include "asterisk/options.h"
  51. #include "asterisk/channel.h"
  52. #include "asterisk/config.h"
  53. #include "asterisk/term.h"
  54. #include "asterisk/cli.h"
  55. #include "asterisk/utils.h"
  56. #include "asterisk/manager.h"
  57. #define MAX_MSG_QUEUE 200
  58. #if defined(__linux__) && !defined(__NR_gettid)
  59. #include <asm/unistd.h>
  60. #endif
  61. #if defined(__linux__) && defined(__NR_gettid)
  62. #define GETTID() syscall(__NR_gettid)
  63. #else
  64. #define GETTID() getpid()
  65. #endif
  66. static char dateformat[256] = "%b %e %T"; /* Original Asterisk Format */
  67. AST_MUTEX_DEFINE_STATIC(msglist_lock);
  68. AST_MUTEX_DEFINE_STATIC(loglock);
  69. static int filesize_reload_needed = 0;
  70. static int global_logmask = -1;
  71. static struct {
  72. unsigned int queue_log:1;
  73. unsigned int event_log:1;
  74. } logfiles = { 1, 1 };
  75. static struct msglist {
  76. char *msg;
  77. struct msglist *next;
  78. } *list = NULL, *last = NULL;
  79. static char hostname[MAXHOSTNAMELEN];
  80. enum logtypes {
  81. LOGTYPE_SYSLOG,
  82. LOGTYPE_FILE,
  83. LOGTYPE_CONSOLE,
  84. };
  85. struct logchannel {
  86. int logmask; /* What to log to this channel */
  87. int disabled; /* If this channel is disabled or not */
  88. int facility; /* syslog facility */
  89. enum logtypes type; /* Type of log channel */
  90. FILE *fileptr; /* logfile logging file pointer */
  91. char filename[256]; /* Filename */
  92. struct logchannel *next; /* Next channel in chain */
  93. };
  94. static struct logchannel *logchannels = NULL;
  95. static int msgcnt = 0;
  96. static FILE *eventlog = NULL;
  97. static FILE *qlog = NULL;
  98. static char *levels[] = {
  99. "DEBUG",
  100. "EVENT",
  101. "NOTICE",
  102. "WARNING",
  103. "ERROR",
  104. "VERBOSE",
  105. "DTMF"
  106. };
  107. static int colors[] = {
  108. COLOR_BRGREEN,
  109. COLOR_BRBLUE,
  110. COLOR_YELLOW,
  111. COLOR_BRRED,
  112. COLOR_RED,
  113. COLOR_GREEN,
  114. COLOR_BRGREEN
  115. };
  116. static int make_components(char *s, int lineno)
  117. {
  118. char *w;
  119. int res = 0;
  120. char *stringp=NULL;
  121. stringp=s;
  122. w = strsep(&stringp, ",");
  123. while(w) {
  124. while(*w && (*w < 33))
  125. w++;
  126. if (!strcasecmp(w, "error"))
  127. res |= (1 << __LOG_ERROR);
  128. else if (!strcasecmp(w, "warning"))
  129. res |= (1 << __LOG_WARNING);
  130. else if (!strcasecmp(w, "notice"))
  131. res |= (1 << __LOG_NOTICE);
  132. else if (!strcasecmp(w, "event"))
  133. res |= (1 << __LOG_EVENT);
  134. else if (!strcasecmp(w, "debug"))
  135. res |= (1 << __LOG_DEBUG);
  136. else if (!strcasecmp(w, "verbose"))
  137. res |= (1 << __LOG_VERBOSE);
  138. else if (!strcasecmp(w, "dtmf"))
  139. res |= (1 << __LOG_DTMF);
  140. else {
  141. fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno);
  142. }
  143. w = strsep(&stringp, ",");
  144. }
  145. return res;
  146. }
  147. static struct logchannel *make_logchannel(char *channel, char *components, int lineno)
  148. {
  149. struct logchannel *chan;
  150. char *facility;
  151. #ifndef SOLARIS
  152. CODE *cptr;
  153. #endif
  154. if (ast_strlen_zero(channel))
  155. return NULL;
  156. chan = malloc(sizeof(struct logchannel));
  157. if (!chan) /* Can't allocate memory */
  158. return NULL;
  159. memset(chan, 0, sizeof(struct logchannel));
  160. if (!strcasecmp(channel, "console")) {
  161. chan->type = LOGTYPE_CONSOLE;
  162. } else if (!strncasecmp(channel, "syslog", 6)) {
  163. /*
  164. * syntax is:
  165. * syslog.facility => level,level,level
  166. */
  167. facility = strchr(channel, '.');
  168. if(!facility++ || !facility) {
  169. facility = "local0";
  170. }
  171. #ifndef SOLARIS
  172. /*
  173. * Walk through the list of facilitynames (defined in sys/syslog.h)
  174. * to see if we can find the one we have been given
  175. */
  176. chan->facility = -1;
  177. cptr = facilitynames;
  178. while (cptr->c_name) {
  179. if (!strcasecmp(facility, cptr->c_name)) {
  180. chan->facility = cptr->c_val;
  181. break;
  182. }
  183. cptr++;
  184. }
  185. #else
  186. chan->facility = -1;
  187. if (!strcasecmp(facility, "kern"))
  188. chan->facility = LOG_KERN;
  189. else if (!strcasecmp(facility, "USER"))
  190. chan->facility = LOG_USER;
  191. else if (!strcasecmp(facility, "MAIL"))
  192. chan->facility = LOG_MAIL;
  193. else if (!strcasecmp(facility, "DAEMON"))
  194. chan->facility = LOG_DAEMON;
  195. else if (!strcasecmp(facility, "AUTH"))
  196. chan->facility = LOG_AUTH;
  197. else if (!strcasecmp(facility, "SYSLOG"))
  198. chan->facility = LOG_SYSLOG;
  199. else if (!strcasecmp(facility, "LPR"))
  200. chan->facility = LOG_LPR;
  201. else if (!strcasecmp(facility, "NEWS"))
  202. chan->facility = LOG_NEWS;
  203. else if (!strcasecmp(facility, "UUCP"))
  204. chan->facility = LOG_UUCP;
  205. else if (!strcasecmp(facility, "CRON"))
  206. chan->facility = LOG_CRON;
  207. else if (!strcasecmp(facility, "LOCAL0"))
  208. chan->facility = LOG_LOCAL0;
  209. else if (!strcasecmp(facility, "LOCAL1"))
  210. chan->facility = LOG_LOCAL1;
  211. else if (!strcasecmp(facility, "LOCAL2"))
  212. chan->facility = LOG_LOCAL2;
  213. else if (!strcasecmp(facility, "LOCAL3"))
  214. chan->facility = LOG_LOCAL3;
  215. else if (!strcasecmp(facility, "LOCAL4"))
  216. chan->facility = LOG_LOCAL4;
  217. else if (!strcasecmp(facility, "LOCAL5"))
  218. chan->facility = LOG_LOCAL5;
  219. else if (!strcasecmp(facility, "LOCAL6"))
  220. chan->facility = LOG_LOCAL6;
  221. else if (!strcasecmp(facility, "LOCAL7"))
  222. chan->facility = LOG_LOCAL7;
  223. #endif /* Solaris */
  224. if (0 > chan->facility) {
  225. fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
  226. free(chan);
  227. return NULL;
  228. }
  229. chan->type = LOGTYPE_SYSLOG;
  230. snprintf(chan->filename, sizeof(chan->filename), "%s", channel);
  231. openlog("asterisk", LOG_PID, chan->facility);
  232. } else {
  233. if (channel[0] == '/') {
  234. if(!ast_strlen_zero(hostname)) {
  235. snprintf(chan->filename, sizeof(chan->filename) - 1,"%s.%s", channel, hostname);
  236. } else {
  237. ast_copy_string(chan->filename, channel, sizeof(chan->filename));
  238. }
  239. }
  240. if(!ast_strlen_zero(hostname)) {
  241. snprintf(chan->filename, sizeof(chan->filename), "%s/%s.%s",(char *)ast_config_AST_LOG_DIR, channel, hostname);
  242. } else {
  243. snprintf(chan->filename, sizeof(chan->filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, channel);
  244. }
  245. chan->fileptr = fopen(chan->filename, "a");
  246. if (!chan->fileptr) {
  247. /* Can't log here, since we're called with a lock */
  248. fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno));
  249. }
  250. chan->type = LOGTYPE_FILE;
  251. }
  252. chan->logmask = make_components(components, lineno);
  253. return chan;
  254. }
  255. static void init_logger_chain(void)
  256. {
  257. struct logchannel *chan, *cur;
  258. struct ast_config *cfg;
  259. struct ast_variable *var;
  260. char *s;
  261. /* delete our list of log channels */
  262. ast_mutex_lock(&loglock);
  263. chan = logchannels;
  264. while (chan) {
  265. cur = chan->next;
  266. free(chan);
  267. chan = cur;
  268. }
  269. logchannels = NULL;
  270. ast_mutex_unlock(&loglock);
  271. global_logmask = 0;
  272. errno = 0;
  273. /* close syslog */
  274. closelog();
  275. cfg = ast_config_load("logger.conf");
  276. /* If no config file, we're fine, set default options. */
  277. if (!cfg) {
  278. if (errno)
  279. fprintf(stderr, "Unable to open logger.conf: %s; default settings will be used.\n", strerror(errno));
  280. else
  281. fprintf(stderr, "Errors detected in logger.conf: see above; default settings will be used.\n");
  282. chan = malloc(sizeof(struct logchannel));
  283. memset(chan, 0, sizeof(struct logchannel));
  284. chan->type = LOGTYPE_CONSOLE;
  285. chan->logmask = 28; /*warning,notice,error */
  286. chan->next = logchannels;
  287. logchannels = chan;
  288. global_logmask |= chan->logmask;
  289. return;
  290. }
  291. ast_mutex_lock(&loglock);
  292. if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
  293. if(ast_true(s)) {
  294. if(gethostname(hostname, sizeof(hostname)-1)) {
  295. ast_copy_string(hostname, "unknown", sizeof(hostname));
  296. ast_log(LOG_WARNING, "What box has no hostname???\n");
  297. }
  298. } else
  299. hostname[0] = '\0';
  300. } else
  301. hostname[0] = '\0';
  302. if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
  303. ast_copy_string(dateformat, s, sizeof(dateformat));
  304. } else
  305. ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
  306. if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
  307. logfiles.queue_log = ast_true(s);
  308. }
  309. if ((s = ast_variable_retrieve(cfg, "general", "event_log"))) {
  310. logfiles.event_log = ast_true(s);
  311. }
  312. var = ast_variable_browse(cfg, "logfiles");
  313. while(var) {
  314. chan = make_logchannel(var->name, var->value, var->lineno);
  315. if (chan) {
  316. chan->next = logchannels;
  317. logchannels = chan;
  318. global_logmask |= chan->logmask;
  319. }
  320. var = var->next;
  321. }
  322. ast_config_destroy(cfg);
  323. ast_mutex_unlock(&loglock);
  324. }
  325. void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
  326. {
  327. va_list ap;
  328. ast_mutex_lock(&loglock);
  329. if (qlog) {
  330. va_start(ap, fmt);
  331. fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
  332. vfprintf(qlog, fmt, ap);
  333. fprintf(qlog, "\n");
  334. va_end(ap);
  335. fflush(qlog);
  336. }
  337. ast_mutex_unlock(&loglock);
  338. }
  339. int reload_logger(int rotate)
  340. {
  341. char old[AST_CONFIG_MAX_PATH] = "";
  342. char new[AST_CONFIG_MAX_PATH];
  343. int event_rotate = rotate, queue_rotate = rotate;
  344. struct logchannel *f;
  345. FILE *myf;
  346. int x, res = 0;
  347. ast_mutex_lock(&msglist_lock); /* to avoid deadlock */
  348. ast_mutex_lock(&loglock);
  349. if (eventlog)
  350. fclose(eventlog);
  351. else
  352. event_rotate = 0;
  353. eventlog = NULL;
  354. if (qlog)
  355. fclose(qlog);
  356. else
  357. queue_rotate = 0;
  358. qlog = NULL;
  359. mkdir((char *)ast_config_AST_LOG_DIR, 0755);
  360. f = logchannels;
  361. while(f) {
  362. if (f->disabled) {
  363. f->disabled = 0; /* Re-enable logging at reload */
  364. manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
  365. }
  366. if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
  367. fclose(f->fileptr); /* Close file */
  368. f->fileptr = NULL;
  369. if(rotate) {
  370. ast_copy_string(old, f->filename, sizeof(old));
  371. for(x=0;;x++) {
  372. snprintf(new, sizeof(new), "%s.%d", f->filename, x);
  373. myf = fopen((char *)new, "r");
  374. if (myf) {
  375. fclose(myf);
  376. } else {
  377. break;
  378. }
  379. }
  380. /* do it */
  381. if (rename(old,new))
  382. fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
  383. }
  384. }
  385. f = f->next;
  386. }
  387. filesize_reload_needed = 0;
  388. init_logger_chain();
  389. if (logfiles.event_log) {
  390. snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
  391. if (event_rotate) {
  392. for (x=0;;x++) {
  393. snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, EVENTLOG,x);
  394. myf = fopen((char *)new, "r");
  395. if (myf) /* File exists */
  396. fclose(myf);
  397. else
  398. break;
  399. }
  400. /* do it */
  401. if (rename(old,new))
  402. ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
  403. }
  404. eventlog = fopen(old, "a");
  405. if (eventlog) {
  406. ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
  407. if (option_verbose)
  408. ast_verbose("Asterisk Event Logger restarted\n");
  409. } else {
  410. ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
  411. res = -1;
  412. }
  413. }
  414. if (logfiles.queue_log) {
  415. snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, QUEUELOG);
  416. if (queue_rotate) {
  417. for (x = 0; ; x++) {
  418. snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, QUEUELOG, x);
  419. myf = fopen((char *)new, "r");
  420. if (myf) /* File exists */
  421. fclose(myf);
  422. else
  423. break;
  424. }
  425. /* do it */
  426. if (rename(old, new))
  427. ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
  428. }
  429. qlog = fopen(old, "a");
  430. if (qlog) {
  431. ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
  432. ast_log(LOG_EVENT, "Restarted Asterisk Queue Logger\n");
  433. if (option_verbose)
  434. ast_verbose("Asterisk Queue Logger restarted\n");
  435. } else {
  436. ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
  437. res = -1;
  438. }
  439. }
  440. ast_mutex_unlock(&loglock);
  441. ast_mutex_unlock(&msglist_lock);
  442. return res;
  443. }
  444. static int handle_logger_reload(int fd, int argc, char *argv[])
  445. {
  446. if(reload_logger(0)) {
  447. ast_cli(fd, "Failed to reload the logger\n");
  448. return RESULT_FAILURE;
  449. } else
  450. return RESULT_SUCCESS;
  451. }
  452. static int handle_logger_rotate(int fd, int argc, char *argv[])
  453. {
  454. if(reload_logger(1)) {
  455. ast_cli(fd, "Failed to reload the logger and rotate log files\n");
  456. return RESULT_FAILURE;
  457. } else
  458. return RESULT_SUCCESS;
  459. }
  460. /*--- handle_logger_show_channels: CLI command to show logging system
  461. configuration */
  462. static int handle_logger_show_channels(int fd, int argc, char *argv[])
  463. {
  464. #define FORMATL "%-35.35s %-8.8s %-9.9s "
  465. struct logchannel *chan;
  466. ast_mutex_lock(&loglock);
  467. chan = logchannels;
  468. ast_cli(fd,FORMATL, "Channel", "Type", "Status");
  469. ast_cli(fd, "Configuration\n");
  470. ast_cli(fd,FORMATL, "-------", "----", "------");
  471. ast_cli(fd, "-------------\n");
  472. while (chan) {
  473. ast_cli(fd, FORMATL, chan->filename, chan->type==LOGTYPE_CONSOLE ? "Console" : (chan->type==LOGTYPE_SYSLOG ? "Syslog" : "File"),
  474. chan->disabled ? "Disabled" : "Enabled");
  475. ast_cli(fd, " - ");
  476. if (chan->logmask & (1 << __LOG_DEBUG))
  477. ast_cli(fd, "Debug ");
  478. if (chan->logmask & (1 << __LOG_DTMF))
  479. ast_cli(fd, "DTMF ");
  480. if (chan->logmask & (1 << __LOG_VERBOSE))
  481. ast_cli(fd, "Verbose ");
  482. if (chan->logmask & (1 << __LOG_WARNING))
  483. ast_cli(fd, "Warning ");
  484. if (chan->logmask & (1 << __LOG_NOTICE))
  485. ast_cli(fd, "Notice ");
  486. if (chan->logmask & (1 << __LOG_ERROR))
  487. ast_cli(fd, "Error ");
  488. if (chan->logmask & (1 << __LOG_EVENT))
  489. ast_cli(fd, "Event ");
  490. ast_cli(fd, "\n");
  491. chan = chan->next;
  492. }
  493. ast_cli(fd, "\n");
  494. ast_mutex_unlock(&loglock);
  495. return RESULT_SUCCESS;
  496. }
  497. static struct verb {
  498. void (*verboser)(const char *string, int opos, int replacelast, int complete);
  499. struct verb *next;
  500. } *verboser = NULL;
  501. static char logger_reload_help[] =
  502. "Usage: logger reload\n"
  503. " Reloads the logger subsystem state. Use after restarting syslogd(8) if you are using syslog logging.\n";
  504. static char logger_rotate_help[] =
  505. "Usage: logger rotate\n"
  506. " Rotates and Reopens the log files.\n";
  507. static char logger_show_channels_help[] =
  508. "Usage: logger show channels\n"
  509. " Show configured logger channels.\n";
  510. static struct ast_cli_entry logger_show_channels_cli =
  511. { { "logger", "show", "channels", NULL },
  512. handle_logger_show_channels, "List configured log channels",
  513. logger_show_channels_help };
  514. static struct ast_cli_entry reload_logger_cli =
  515. { { "logger", "reload", NULL },
  516. handle_logger_reload, "Reopens the log files",
  517. logger_reload_help };
  518. static struct ast_cli_entry rotate_logger_cli =
  519. { { "logger", "rotate", NULL },
  520. handle_logger_rotate, "Rotates and reopens the log files",
  521. logger_rotate_help };
  522. static int handle_SIGXFSZ(int sig)
  523. {
  524. /* Indicate need to reload */
  525. filesize_reload_needed = 1;
  526. return 0;
  527. }
  528. int init_logger(void)
  529. {
  530. char tmp[256];
  531. int res = 0;
  532. /* auto rotate if sig SIGXFSZ comes a-knockin */
  533. (void) signal(SIGXFSZ,(void *) handle_SIGXFSZ);
  534. /* register the relaod logger cli command */
  535. ast_cli_register(&reload_logger_cli);
  536. ast_cli_register(&rotate_logger_cli);
  537. ast_cli_register(&logger_show_channels_cli);
  538. mkdir((char *)ast_config_AST_LOG_DIR, 0755);
  539. /* create log channels */
  540. init_logger_chain();
  541. /* create the eventlog */
  542. if (logfiles.event_log) {
  543. mkdir((char *)ast_config_AST_LOG_DIR, 0755);
  544. snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
  545. eventlog = fopen((char *)tmp, "a");
  546. if (eventlog) {
  547. ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
  548. if (option_verbose)
  549. ast_verbose("Asterisk Event Logger Started %s\n",(char *)tmp);
  550. } else {
  551. ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
  552. res = -1;
  553. }
  554. }
  555. if (logfiles.queue_log) {
  556. snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, QUEUELOG);
  557. qlog = fopen(tmp, "a");
  558. ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
  559. }
  560. return res;
  561. }
  562. void close_logger(void)
  563. {
  564. struct msglist *m, *tmp;
  565. ast_mutex_lock(&msglist_lock);
  566. m = list;
  567. while(m) {
  568. if (m->msg) {
  569. free(m->msg);
  570. }
  571. tmp = m->next;
  572. free(m);
  573. m = tmp;
  574. }
  575. list = last = NULL;
  576. msgcnt = 0;
  577. ast_mutex_unlock(&msglist_lock);
  578. return;
  579. }
  580. static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args)
  581. {
  582. char buf[BUFSIZ];
  583. char *s;
  584. if (level >= SYSLOG_NLEVELS) {
  585. /* we are locked here, so cannot ast_log() */
  586. fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level);
  587. return;
  588. }
  589. if (level == __LOG_VERBOSE) {
  590. snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)GETTID());
  591. level = __LOG_DEBUG;
  592. } else if (level == __LOG_DTMF) {
  593. snprintf(buf, sizeof(buf), "DTMF[%ld]: ", (long)GETTID());
  594. level = __LOG_DEBUG;
  595. } else {
  596. snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
  597. levels[level], (long)GETTID(), file, line, function);
  598. }
  599. s = buf + strlen(buf);
  600. vsnprintf(s, sizeof(buf) - strlen(buf), fmt, args);
  601. term_strip(s, s, strlen(s) + 1);
  602. syslog(syslog_level_map[level], "%s", buf);
  603. }
  604. /*
  605. * send log messages to syslog and/or the console
  606. */
  607. void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
  608. {
  609. struct logchannel *chan;
  610. char buf[BUFSIZ];
  611. time_t t;
  612. struct tm tm;
  613. char date[256];
  614. va_list ap;
  615. if (!logchannels)
  616. {
  617. /*
  618. * we don't have the logger chain configured yet,
  619. * so just log to stdout
  620. */
  621. if (level != __LOG_VERBOSE) {
  622. va_start(ap, fmt);
  623. vsnprintf(buf, sizeof(buf), fmt, ap);
  624. va_end(ap);
  625. fputs(buf, stdout);
  626. }
  627. return;
  628. }
  629. /* don't display LOG_DEBUG messages unless option_verbose _or_ option_debug
  630. are non-zero; LOG_DEBUG messages can still be displayed if option_debug
  631. is zero, if option_verbose is non-zero (this allows for 'level zero'
  632. LOG_DEBUG messages to be displayed, if the logmask on any channel
  633. allows it)
  634. */
  635. if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) {
  636. return;
  637. }
  638. /* Ignore anything that never gets logged anywhere */
  639. if (!(global_logmask & (1 << level)))
  640. return;
  641. /* Ignore anything other than the currently debugged file if there is one */
  642. if ((level == __LOG_DEBUG) && !ast_strlen_zero(debug_filename) && strcasecmp(debug_filename, file))
  643. return;
  644. /* begin critical section */
  645. ast_mutex_lock(&loglock);
  646. time(&t);
  647. localtime_r(&t, &tm);
  648. strftime(date, sizeof(date), dateformat, &tm);
  649. if (logfiles.event_log && level == __LOG_EVENT) {
  650. va_start(ap, fmt);
  651. fprintf(eventlog, "%s asterisk[%d]: ", date, getpid());
  652. vfprintf(eventlog, fmt, ap);
  653. fflush(eventlog);
  654. va_end(ap);
  655. ast_mutex_unlock(&loglock);
  656. return;
  657. }
  658. chan = logchannels;
  659. while(chan && !chan->disabled) {
  660. /* Check syslog channels */
  661. if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << level))) {
  662. va_start(ap, fmt);
  663. ast_log_vsyslog(level, file, line, function, fmt, ap);
  664. va_end(ap);
  665. /* Console channels */
  666. } else if ((chan->logmask & (1 << level)) && (chan->type == LOGTYPE_CONSOLE)) {
  667. char linestr[128];
  668. char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
  669. if (level != __LOG_VERBOSE) {
  670. sprintf(linestr, "%d", line);
  671. snprintf(buf, sizeof(buf), option_timestamp ? "[%s] %s[%ld]: %s:%s %s: " : "%s %s[%ld]: %s:%s %s: ",
  672. date,
  673. term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
  674. (long)GETTID(),
  675. term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
  676. term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
  677. term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
  678. ast_console_puts(buf);
  679. va_start(ap, fmt);
  680. vsnprintf(buf, sizeof(buf), fmt, ap);
  681. va_end(ap);
  682. ast_console_puts(buf);
  683. }
  684. /* File channels */
  685. } else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
  686. int res;
  687. snprintf(buf, sizeof(buf), option_timestamp ? "[%s] %s[%ld]: " : "%s %s[%ld] %s: ", date,
  688. levels[level], (long)GETTID(), file);
  689. res = fprintf(chan->fileptr, buf);
  690. if (res <= 0 && buf[0] != '\0') { /* Error, no characters printed */
  691. fprintf(stderr,"**** Asterisk Logging Error: ***********\n");
  692. if (errno == ENOMEM || errno == ENOSPC) {
  693. fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
  694. } else
  695. fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
  696. manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
  697. chan->disabled = 1;
  698. } else {
  699. /* No error message, continue printing */
  700. va_start(ap, fmt);
  701. vsnprintf(buf, sizeof(buf), fmt, ap);
  702. va_end(ap);
  703. term_strip(buf, buf, sizeof(buf));
  704. fputs(buf, chan->fileptr);
  705. fflush(chan->fileptr);
  706. }
  707. }
  708. chan = chan->next;
  709. }
  710. ast_mutex_unlock(&loglock);
  711. /* end critical section */
  712. if (filesize_reload_needed) {
  713. reload_logger(1);
  714. ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
  715. if (option_verbose)
  716. ast_verbose("Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
  717. }
  718. }
  719. void ast_verbose(const char *fmt, ...)
  720. {
  721. static char stuff[4096];
  722. static int len = 0;
  723. static int replacelast = 0;
  724. int complete;
  725. int olen;
  726. struct msglist *m;
  727. struct verb *v;
  728. va_list ap;
  729. va_start(ap, fmt);
  730. if (option_timestamp) {
  731. time_t t;
  732. struct tm tm;
  733. char date[40];
  734. char *datefmt;
  735. time(&t);
  736. localtime_r(&t, &tm);
  737. strftime(date, sizeof(date), dateformat, &tm);
  738. datefmt = alloca(strlen(date) + 3 + strlen(fmt) + 1);
  739. if (datefmt) {
  740. sprintf(datefmt, "[%s] %s", date, fmt);
  741. fmt = datefmt;
  742. }
  743. }
  744. /* this lock is also protecting against multiple threads
  745. being in this function at the same time, so it must be
  746. held before any of the static variables are accessed
  747. */
  748. ast_mutex_lock(&msglist_lock);
  749. /* there is a potential security problem here: if formatting
  750. the current date using 'dateformat' results in a string
  751. containing '%', then the vsnprintf() call below will
  752. probably try to access random memory
  753. */
  754. vsnprintf(stuff + len, sizeof(stuff) - len, fmt, ap);
  755. va_end(ap);
  756. olen = len;
  757. len = strlen(stuff);
  758. complete = (stuff[len - 1] == '\n') ? 1 : 0;
  759. /* If we filled up the stuff completely, then log it even without the '\n' */
  760. if (len >= sizeof(stuff) - 1) {
  761. complete = 1;
  762. len = 0;
  763. }
  764. if (complete) {
  765. if (msgcnt < MAX_MSG_QUEUE) {
  766. /* Allocate new structure */
  767. if ((m = calloc(1, sizeof(*m))))
  768. msgcnt++;
  769. } else {
  770. /* Recycle the oldest entry */
  771. m = list;
  772. list = list->next;
  773. if (m->msg)
  774. free(m->msg);
  775. }
  776. if (m) {
  777. m->msg = strdup(stuff);
  778. if (m->msg) {
  779. if (last)
  780. last->next = m;
  781. else
  782. list = m;
  783. m->next = NULL;
  784. last = m;
  785. } else {
  786. msgcnt--;
  787. ast_log(LOG_ERROR, "Out of memory\n");
  788. free(m);
  789. }
  790. }
  791. }
  792. for (v = verboser; v; v = v->next)
  793. v->verboser(stuff, olen, replacelast, complete);
  794. ast_log(LOG_VERBOSE, "%s", stuff);
  795. if (len) {
  796. if (!complete)
  797. replacelast = 1;
  798. else
  799. replacelast = len = 0;
  800. }
  801. ast_mutex_unlock(&msglist_lock);
  802. }
  803. int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete))
  804. {
  805. struct msglist *m;
  806. ast_mutex_lock(&msglist_lock);
  807. m = list;
  808. while(m) {
  809. /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
  810. v(m->msg, 0, 0, 1);
  811. m = m->next;
  812. }
  813. ast_mutex_unlock(&msglist_lock);
  814. return 0;
  815. }
  816. int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
  817. {
  818. struct msglist *m;
  819. struct verb *tmp;
  820. /* XXX Should be more flexible here, taking > 1 verboser XXX */
  821. if ((tmp = malloc(sizeof (struct verb)))) {
  822. tmp->verboser = v;
  823. ast_mutex_lock(&msglist_lock);
  824. tmp->next = verboser;
  825. verboser = tmp;
  826. m = list;
  827. while(m) {
  828. /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
  829. v(m->msg, 0, 0, 1);
  830. m = m->next;
  831. }
  832. ast_mutex_unlock(&msglist_lock);
  833. return 0;
  834. }
  835. return -1;
  836. }
  837. int ast_unregister_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
  838. {
  839. int res = -1;
  840. struct verb *tmp, *tmpl=NULL;
  841. ast_mutex_lock(&msglist_lock);
  842. tmp = verboser;
  843. while(tmp) {
  844. if (tmp->verboser == v) {
  845. if (tmpl)
  846. tmpl->next = tmp->next;
  847. else
  848. verboser = tmp->next;
  849. free(tmp);
  850. break;
  851. }
  852. tmpl = tmp;
  853. tmp = tmp->next;
  854. }
  855. if (tmp)
  856. res = 0;
  857. ast_mutex_unlock(&msglist_lock);
  858. return res;
  859. }