logger.c 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2006, 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. *
  20. * \brief Asterisk Logger
  21. *
  22. * Logging routines
  23. *
  24. * \author Mark Spencer <markster@digium.com>
  25. */
  26. /*! \li \ref logger.c uses the configuration file \ref logger.conf
  27. * \addtogroup configuration_file Configuration Files
  28. */
  29. /*!
  30. * \page logger.conf logger.conf
  31. * \verbinclude logger.conf.sample
  32. */
  33. /*** MODULEINFO
  34. <support_level>core</support_level>
  35. ***/
  36. #include "asterisk.h"
  37. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  38. /* When we include logger.h again it will trample on some stuff in syslog.h, but
  39. * nothing we care about in here. */
  40. #include <syslog.h>
  41. #include <signal.h>
  42. #include <time.h>
  43. #include <sys/stat.h>
  44. #include <fcntl.h>
  45. #include "asterisk/_private.h"
  46. #include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */
  47. #include "asterisk/logger.h"
  48. #include "asterisk/lock.h"
  49. #include "asterisk/channel.h"
  50. #include "asterisk/config.h"
  51. #include "asterisk/term.h"
  52. #include "asterisk/cli.h"
  53. #include "asterisk/utils.h"
  54. #include "asterisk/manager.h"
  55. #include "asterisk/astobj2.h"
  56. #include "asterisk/threadstorage.h"
  57. #include "asterisk/strings.h"
  58. #include "asterisk/pbx.h"
  59. #include "asterisk/app.h"
  60. #include "asterisk/syslog.h"
  61. #include "asterisk/buildinfo.h"
  62. #include "asterisk/ast_version.h"
  63. #include "asterisk/backtrace.h"
  64. /*** DOCUMENTATION
  65. ***/
  66. static char dateformat[256] = "%b %e %T"; /* Original Asterisk Format */
  67. static char queue_log_name[256] = QUEUELOG;
  68. static char exec_after_rotate[256] = "";
  69. static int filesize_reload_needed;
  70. static unsigned int global_logmask = 0xFFFF;
  71. static int queuelog_init;
  72. static int logger_initialized;
  73. static volatile int next_unique_callid; /* Used to assign unique call_ids to calls */
  74. static int display_callids;
  75. static void unique_callid_cleanup(void *data);
  76. struct ast_callid {
  77. int call_identifier; /* Numerical value of the call displayed in the logs */
  78. };
  79. AST_THREADSTORAGE_CUSTOM(unique_callid, NULL, unique_callid_cleanup);
  80. static enum rotatestrategy {
  81. NONE = 0, /* Do not rotate log files at all, instead rely on external mechanisms */
  82. SEQUENTIAL = 1 << 0, /* Original method - create a new file, in order */
  83. ROTATE = 1 << 1, /* Rotate all files, such that the oldest file has the highest suffix */
  84. TIMESTAMP = 1 << 2, /* Append the epoch timestamp onto the end of the archived file */
  85. } rotatestrategy = SEQUENTIAL;
  86. static struct {
  87. unsigned int queue_log:1;
  88. unsigned int queue_log_to_file:1;
  89. unsigned int queue_adaptive_realtime:1;
  90. unsigned int queue_log_realtime_use_gmt:1;
  91. } logfiles = { 1 };
  92. static char hostname[MAXHOSTNAMELEN];
  93. enum logtypes {
  94. LOGTYPE_SYSLOG,
  95. LOGTYPE_FILE,
  96. LOGTYPE_CONSOLE,
  97. };
  98. struct logchannel {
  99. /*! What to log to this channel */
  100. unsigned int logmask;
  101. /*! If this channel is disabled or not */
  102. int disabled;
  103. /*! syslog facility */
  104. int facility;
  105. /*! Verbosity level. (-1 if use option_verbose for the level.) */
  106. int verbosity;
  107. /*! Type of log channel */
  108. enum logtypes type;
  109. /*! logfile logging file pointer */
  110. FILE *fileptr;
  111. /*! Filename */
  112. char filename[PATH_MAX];
  113. /*! field for linking to list */
  114. AST_LIST_ENTRY(logchannel) list;
  115. /*! Line number from configuration file */
  116. int lineno;
  117. /*! Components (levels) from last config load */
  118. char components[0];
  119. };
  120. static AST_RWLIST_HEAD_STATIC(logchannels, logchannel);
  121. enum logmsgtypes {
  122. LOGMSG_NORMAL = 0,
  123. LOGMSG_VERBOSE,
  124. };
  125. struct logmsg {
  126. enum logmsgtypes type;
  127. int level;
  128. int line;
  129. int lwp;
  130. struct ast_callid *callid;
  131. AST_DECLARE_STRING_FIELDS(
  132. AST_STRING_FIELD(date);
  133. AST_STRING_FIELD(file);
  134. AST_STRING_FIELD(function);
  135. AST_STRING_FIELD(message);
  136. AST_STRING_FIELD(level_name);
  137. );
  138. AST_LIST_ENTRY(logmsg) list;
  139. };
  140. static void logmsg_free(struct logmsg *msg)
  141. {
  142. if (msg->callid) {
  143. ast_callid_unref(msg->callid);
  144. }
  145. ast_free(msg);
  146. }
  147. static AST_LIST_HEAD_STATIC(logmsgs, logmsg);
  148. static pthread_t logthread = AST_PTHREADT_NULL;
  149. static ast_cond_t logcond;
  150. static int close_logger_thread = 0;
  151. static FILE *qlog;
  152. /*! \brief Logging channels used in the Asterisk logging system
  153. *
  154. * The first 16 levels are reserved for system usage, and the remaining
  155. * levels are reserved for usage by dynamic levels registered via
  156. * ast_logger_register_level.
  157. */
  158. /* Modifications to this array are protected by the rwlock in the
  159. * logchannels list.
  160. */
  161. static char *levels[NUMLOGLEVELS] = {
  162. "DEBUG",
  163. "---EVENT---", /* no longer used */
  164. "NOTICE",
  165. "WARNING",
  166. "ERROR",
  167. "VERBOSE",
  168. "DTMF",
  169. };
  170. /*! \brief Colors used in the console for logging */
  171. static const int colors[NUMLOGLEVELS] = {
  172. COLOR_BRGREEN,
  173. COLOR_BRBLUE, /* no longer used */
  174. COLOR_YELLOW,
  175. COLOR_BRRED,
  176. COLOR_RED,
  177. COLOR_GREEN,
  178. COLOR_BRGREEN,
  179. 0,
  180. 0,
  181. 0,
  182. 0,
  183. 0,
  184. 0,
  185. 0,
  186. 0,
  187. 0,
  188. COLOR_BRBLUE,
  189. COLOR_BRBLUE,
  190. COLOR_BRBLUE,
  191. COLOR_BRBLUE,
  192. COLOR_BRBLUE,
  193. COLOR_BRBLUE,
  194. COLOR_BRBLUE,
  195. COLOR_BRBLUE,
  196. COLOR_BRBLUE,
  197. COLOR_BRBLUE,
  198. COLOR_BRBLUE,
  199. COLOR_BRBLUE,
  200. COLOR_BRBLUE,
  201. COLOR_BRBLUE,
  202. COLOR_BRBLUE,
  203. COLOR_BRBLUE,
  204. };
  205. AST_THREADSTORAGE(verbose_buf);
  206. #define VERBOSE_BUF_INIT_SIZE 256
  207. AST_THREADSTORAGE(log_buf);
  208. #define LOG_BUF_INIT_SIZE 256
  209. static void logger_queue_init(void);
  210. static void make_components(struct logchannel *chan)
  211. {
  212. char *w;
  213. unsigned int logmask = 0;
  214. char *stringp = ast_strdupa(chan->components);
  215. unsigned int x;
  216. unsigned int verb_level;
  217. /* Default to using option_verbose as the verbosity level of the logging channel. */
  218. verb_level = -1;
  219. while ((w = strsep(&stringp, ","))) {
  220. w = ast_strip(w);
  221. if (ast_strlen_zero(w)) {
  222. continue;
  223. }
  224. if (!strcmp(w, "*")) {
  225. logmask = 0xFFFFFFFF;
  226. } else if (!strncasecmp(w, "verbose(", 8)) {
  227. if (levels[__LOG_VERBOSE] && sscanf(w + 8, "%30u)", &verb_level) == 1) {
  228. logmask |= (1 << __LOG_VERBOSE);
  229. }
  230. } else {
  231. for (x = 0; x < ARRAY_LEN(levels); ++x) {
  232. if (levels[x] && !strcasecmp(w, levels[x])) {
  233. logmask |= (1 << x);
  234. break;
  235. }
  236. }
  237. }
  238. }
  239. if (chan->type == LOGTYPE_CONSOLE) {
  240. /*
  241. * Force to use the root console verbose level so if the
  242. * user specified any verbose level then it does not interfere
  243. * with calculating the ast_verb_sys_level value.
  244. */
  245. chan->verbosity = -1;
  246. } else {
  247. chan->verbosity = verb_level;
  248. }
  249. chan->logmask = logmask;
  250. }
  251. static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno)
  252. {
  253. struct logchannel *chan;
  254. char *facility;
  255. struct ast_tm tm;
  256. struct timeval now = ast_tvnow();
  257. char datestring[256];
  258. if (ast_strlen_zero(channel) || !(chan = ast_calloc(1, sizeof(*chan) + strlen(components) + 1)))
  259. return NULL;
  260. strcpy(chan->components, components);
  261. chan->lineno = lineno;
  262. if (!strcasecmp(channel, "console")) {
  263. chan->type = LOGTYPE_CONSOLE;
  264. } else if (!strncasecmp(channel, "syslog", 6)) {
  265. /*
  266. * syntax is:
  267. * syslog.facility => level,level,level
  268. */
  269. facility = strchr(channel, '.');
  270. if (!facility++ || !facility) {
  271. facility = "local0";
  272. }
  273. chan->facility = ast_syslog_facility(facility);
  274. if (chan->facility < 0) {
  275. fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
  276. ast_free(chan);
  277. return NULL;
  278. }
  279. chan->type = LOGTYPE_SYSLOG;
  280. ast_copy_string(chan->filename, channel, sizeof(chan->filename));
  281. openlog("asterisk", LOG_PID, chan->facility);
  282. } else {
  283. const char *log_dir_prefix = "";
  284. const char *log_dir_separator = "";
  285. if (channel[0] != '/') {
  286. log_dir_prefix = ast_config_AST_LOG_DIR;
  287. log_dir_separator = "/";
  288. }
  289. if (!ast_strlen_zero(hostname)) {
  290. snprintf(chan->filename, sizeof(chan->filename), "%s%s%s.%s",
  291. log_dir_prefix, log_dir_separator, channel, hostname);
  292. } else {
  293. snprintf(chan->filename, sizeof(chan->filename), "%s%s%s",
  294. log_dir_prefix, log_dir_separator, channel);
  295. }
  296. if (!(chan->fileptr = fopen(chan->filename, "a"))) {
  297. /* Can't do real logging here since we're called with a lock
  298. * so log to any attached consoles */
  299. ast_console_puts_mutable("ERROR: Unable to open log file '", __LOG_ERROR);
  300. ast_console_puts_mutable(chan->filename, __LOG_ERROR);
  301. ast_console_puts_mutable("': ", __LOG_ERROR);
  302. ast_console_puts_mutable(strerror(errno), __LOG_ERROR);
  303. ast_console_puts_mutable("'\n", __LOG_ERROR);
  304. ast_free(chan);
  305. return NULL;
  306. } else {
  307. /* Create our date/time */
  308. ast_localtime(&now, &tm, NULL);
  309. ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
  310. fprintf(chan->fileptr, "[%s] Asterisk %s built by %s @ %s on a %s running %s on %s\n",
  311. datestring, ast_get_version(), ast_build_user, ast_build_hostname,
  312. ast_build_machine, ast_build_os, ast_build_date);
  313. fflush(chan->fileptr);
  314. }
  315. chan->type = LOGTYPE_FILE;
  316. }
  317. make_components(chan);
  318. return chan;
  319. }
  320. static void init_logger_chain(int locked, const char *altconf)
  321. {
  322. struct logchannel *chan;
  323. struct ast_config *cfg;
  324. struct ast_variable *var;
  325. const char *s;
  326. struct ast_flags config_flags = { 0 };
  327. display_callids = 1;
  328. if (!(cfg = ast_config_load2(S_OR(altconf, "logger.conf"), "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
  329. return;
  330. }
  331. /* delete our list of log channels */
  332. if (!locked) {
  333. AST_RWLIST_WRLOCK(&logchannels);
  334. }
  335. while ((chan = AST_RWLIST_REMOVE_HEAD(&logchannels, list))) {
  336. ast_free(chan);
  337. }
  338. global_logmask = 0;
  339. if (!locked) {
  340. AST_RWLIST_UNLOCK(&logchannels);
  341. }
  342. errno = 0;
  343. /* close syslog */
  344. closelog();
  345. /* If no config file, we're fine, set default options. */
  346. if (!cfg) {
  347. if (errno) {
  348. fprintf(stderr, "Unable to open logger.conf: %s; default settings will be used.\n", strerror(errno));
  349. } else {
  350. fprintf(stderr, "Errors detected in logger.conf: see above; default settings will be used.\n");
  351. }
  352. if (!(chan = ast_calloc(1, sizeof(*chan)))) {
  353. return;
  354. }
  355. chan->type = LOGTYPE_CONSOLE;
  356. chan->logmask = __LOG_WARNING | __LOG_NOTICE | __LOG_ERROR;
  357. if (!locked) {
  358. AST_RWLIST_WRLOCK(&logchannels);
  359. }
  360. AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
  361. global_logmask |= chan->logmask;
  362. if (!locked) {
  363. AST_RWLIST_UNLOCK(&logchannels);
  364. }
  365. return;
  366. }
  367. if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
  368. if (ast_true(s)) {
  369. if (gethostname(hostname, sizeof(hostname) - 1)) {
  370. ast_copy_string(hostname, "unknown", sizeof(hostname));
  371. fprintf(stderr, "What box has no hostname???\n");
  372. }
  373. } else
  374. hostname[0] = '\0';
  375. } else
  376. hostname[0] = '\0';
  377. if ((s = ast_variable_retrieve(cfg, "general", "display_callids"))) {
  378. display_callids = ast_true(s);
  379. }
  380. if ((s = ast_variable_retrieve(cfg, "general", "dateformat")))
  381. ast_copy_string(dateformat, s, sizeof(dateformat));
  382. else
  383. ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
  384. if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
  385. logfiles.queue_log = ast_true(s);
  386. }
  387. if ((s = ast_variable_retrieve(cfg, "general", "queue_log_to_file"))) {
  388. logfiles.queue_log_to_file = ast_true(s);
  389. }
  390. if ((s = ast_variable_retrieve(cfg, "general", "queue_log_name"))) {
  391. ast_copy_string(queue_log_name, s, sizeof(queue_log_name));
  392. }
  393. if ((s = ast_variable_retrieve(cfg, "general", "queue_log_realtime_use_gmt"))) {
  394. logfiles.queue_log_realtime_use_gmt = ast_true(s);
  395. }
  396. if ((s = ast_variable_retrieve(cfg, "general", "exec_after_rotate"))) {
  397. ast_copy_string(exec_after_rotate, s, sizeof(exec_after_rotate));
  398. }
  399. if ((s = ast_variable_retrieve(cfg, "general", "rotatestrategy"))) {
  400. if (strcasecmp(s, "timestamp") == 0) {
  401. rotatestrategy = TIMESTAMP;
  402. } else if (strcasecmp(s, "rotate") == 0) {
  403. rotatestrategy = ROTATE;
  404. } else if (strcasecmp(s, "sequential") == 0) {
  405. rotatestrategy = SEQUENTIAL;
  406. } else if (strcasecmp(s, "none") == 0) {
  407. rotatestrategy = NONE;
  408. } else {
  409. fprintf(stderr, "Unknown rotatestrategy: %s\n", s);
  410. }
  411. } else {
  412. if ((s = ast_variable_retrieve(cfg, "general", "rotatetimestamp"))) {
  413. rotatestrategy = ast_true(s) ? TIMESTAMP : SEQUENTIAL;
  414. fprintf(stderr, "rotatetimestamp option has been deprecated. Please use rotatestrategy instead.\n");
  415. }
  416. }
  417. if (!locked) {
  418. AST_RWLIST_WRLOCK(&logchannels);
  419. }
  420. var = ast_variable_browse(cfg, "logfiles");
  421. for (; var; var = var->next) {
  422. if (!(chan = make_logchannel(var->name, var->value, var->lineno))) {
  423. /* Print error message directly to the consoles since the lock is held
  424. * and we don't want to unlock with the list partially built */
  425. ast_console_puts_mutable("ERROR: Unable to create log channel '", __LOG_ERROR);
  426. ast_console_puts_mutable(var->name, __LOG_ERROR);
  427. ast_console_puts_mutable("'\n", __LOG_ERROR);
  428. continue;
  429. }
  430. AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
  431. global_logmask |= chan->logmask;
  432. }
  433. if (qlog) {
  434. fclose(qlog);
  435. qlog = NULL;
  436. }
  437. if (!locked) {
  438. AST_RWLIST_UNLOCK(&logchannels);
  439. }
  440. ast_config_destroy(cfg);
  441. }
  442. void ast_child_verbose(int level, const char *fmt, ...)
  443. {
  444. char *msg = NULL, *emsg = NULL, *sptr, *eptr;
  445. va_list ap, aq;
  446. int size;
  447. va_start(ap, fmt);
  448. va_copy(aq, ap);
  449. if ((size = vsnprintf(msg, 0, fmt, ap)) < 0) {
  450. va_end(ap);
  451. va_end(aq);
  452. return;
  453. }
  454. va_end(ap);
  455. if (!(msg = ast_malloc(size + 1))) {
  456. va_end(aq);
  457. return;
  458. }
  459. vsnprintf(msg, size + 1, fmt, aq);
  460. va_end(aq);
  461. if (!(emsg = ast_malloc(size * 2 + 1))) {
  462. ast_free(msg);
  463. return;
  464. }
  465. for (sptr = msg, eptr = emsg; ; sptr++) {
  466. if (*sptr == '"') {
  467. *eptr++ = '\\';
  468. }
  469. *eptr++ = *sptr;
  470. if (*sptr == '\0') {
  471. break;
  472. }
  473. }
  474. ast_free(msg);
  475. fprintf(stdout, "verbose \"%s\" %d\n", emsg, level);
  476. fflush(stdout);
  477. ast_free(emsg);
  478. }
  479. void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
  480. {
  481. va_list ap;
  482. struct timeval tv;
  483. struct ast_tm tm;
  484. char qlog_msg[8192];
  485. int qlog_len;
  486. char time_str[30];
  487. if (!logger_initialized) {
  488. /* You are too early. We are not open yet! */
  489. return;
  490. }
  491. if (!queuelog_init) {
  492. AST_RWLIST_WRLOCK(&logchannels);
  493. if (!queuelog_init) {
  494. /*
  495. * We have delayed initializing the queue logging system so
  496. * preloaded realtime modules can get up. We must initialize
  497. * now since someone is trying to log something.
  498. */
  499. logger_queue_init();
  500. queuelog_init = 1;
  501. AST_RWLIST_UNLOCK(&logchannels);
  502. ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
  503. } else {
  504. AST_RWLIST_UNLOCK(&logchannels);
  505. }
  506. }
  507. if (ast_check_realtime("queue_log")) {
  508. tv = ast_tvnow();
  509. ast_localtime(&tv, &tm, logfiles.queue_log_realtime_use_gmt ? "GMT" : NULL);
  510. ast_strftime(time_str, sizeof(time_str), "%F %T.%6q", &tm);
  511. va_start(ap, fmt);
  512. vsnprintf(qlog_msg, sizeof(qlog_msg), fmt, ap);
  513. va_end(ap);
  514. if (logfiles.queue_adaptive_realtime) {
  515. AST_DECLARE_APP_ARGS(args,
  516. AST_APP_ARG(data)[5];
  517. );
  518. AST_NONSTANDARD_APP_ARGS(args, qlog_msg, '|');
  519. /* Ensure fields are large enough to receive data */
  520. ast_realtime_require_field("queue_log",
  521. "data1", RQ_CHAR, strlen(S_OR(args.data[0], "")),
  522. "data2", RQ_CHAR, strlen(S_OR(args.data[1], "")),
  523. "data3", RQ_CHAR, strlen(S_OR(args.data[2], "")),
  524. "data4", RQ_CHAR, strlen(S_OR(args.data[3], "")),
  525. "data5", RQ_CHAR, strlen(S_OR(args.data[4], "")),
  526. SENTINEL);
  527. /* Store the log */
  528. ast_store_realtime("queue_log", "time", time_str,
  529. "callid", callid,
  530. "queuename", queuename,
  531. "agent", agent,
  532. "event", event,
  533. "data1", S_OR(args.data[0], ""),
  534. "data2", S_OR(args.data[1], ""),
  535. "data3", S_OR(args.data[2], ""),
  536. "data4", S_OR(args.data[3], ""),
  537. "data5", S_OR(args.data[4], ""),
  538. SENTINEL);
  539. } else {
  540. ast_store_realtime("queue_log", "time", time_str,
  541. "callid", callid,
  542. "queuename", queuename,
  543. "agent", agent,
  544. "event", event,
  545. "data", qlog_msg,
  546. SENTINEL);
  547. }
  548. if (!logfiles.queue_log_to_file) {
  549. return;
  550. }
  551. }
  552. if (qlog) {
  553. va_start(ap, fmt);
  554. qlog_len = snprintf(qlog_msg, sizeof(qlog_msg), "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
  555. vsnprintf(qlog_msg + qlog_len, sizeof(qlog_msg) - qlog_len, fmt, ap);
  556. va_end(ap);
  557. AST_RWLIST_RDLOCK(&logchannels);
  558. if (qlog) {
  559. fprintf(qlog, "%s\n", qlog_msg);
  560. fflush(qlog);
  561. }
  562. AST_RWLIST_UNLOCK(&logchannels);
  563. }
  564. }
  565. static int rotate_file(const char *filename)
  566. {
  567. char old[PATH_MAX];
  568. char new[PATH_MAX];
  569. int x, y, which, found, res = 0, fd;
  570. char *suffixes[4] = { "", ".gz", ".bz2", ".Z" };
  571. switch (rotatestrategy) {
  572. case NONE:
  573. /* No rotation */
  574. break;
  575. case SEQUENTIAL:
  576. for (x = 0; ; x++) {
  577. snprintf(new, sizeof(new), "%s.%d", filename, x);
  578. fd = open(new, O_RDONLY);
  579. if (fd > -1)
  580. close(fd);
  581. else
  582. break;
  583. }
  584. if (rename(filename, new)) {
  585. fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
  586. res = -1;
  587. } else {
  588. filename = new;
  589. }
  590. break;
  591. case TIMESTAMP:
  592. snprintf(new, sizeof(new), "%s.%ld", filename, (long)time(NULL));
  593. if (rename(filename, new)) {
  594. fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
  595. res = -1;
  596. } else {
  597. filename = new;
  598. }
  599. break;
  600. case ROTATE:
  601. /* Find the next empty slot, including a possible suffix */
  602. for (x = 0; ; x++) {
  603. found = 0;
  604. for (which = 0; which < ARRAY_LEN(suffixes); which++) {
  605. snprintf(new, sizeof(new), "%s.%d%s", filename, x, suffixes[which]);
  606. fd = open(new, O_RDONLY);
  607. if (fd > -1) {
  608. close(fd);
  609. found = 1;
  610. break;
  611. }
  612. }
  613. if (!found) {
  614. break;
  615. }
  616. }
  617. /* Found an empty slot */
  618. for (y = x; y > 0; y--) {
  619. for (which = 0; which < ARRAY_LEN(suffixes); which++) {
  620. snprintf(old, sizeof(old), "%s.%d%s", filename, y - 1, suffixes[which]);
  621. fd = open(old, O_RDONLY);
  622. if (fd > -1) {
  623. /* Found the right suffix */
  624. close(fd);
  625. snprintf(new, sizeof(new), "%s.%d%s", filename, y, suffixes[which]);
  626. if (rename(old, new)) {
  627. fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
  628. res = -1;
  629. }
  630. break;
  631. }
  632. }
  633. }
  634. /* Finally, rename the current file */
  635. snprintf(new, sizeof(new), "%s.0", filename);
  636. if (rename(filename, new)) {
  637. fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
  638. res = -1;
  639. } else {
  640. filename = new;
  641. }
  642. }
  643. if (!ast_strlen_zero(exec_after_rotate)) {
  644. struct ast_channel *c = ast_dummy_channel_alloc();
  645. char buf[512];
  646. pbx_builtin_setvar_helper(c, "filename", filename);
  647. pbx_substitute_variables_helper(c, exec_after_rotate, buf, sizeof(buf));
  648. if (c) {
  649. c = ast_channel_unref(c);
  650. }
  651. if (ast_safe_system(buf) == -1) {
  652. ast_log(LOG_WARNING, "error executing '%s'\n", buf);
  653. }
  654. }
  655. return res;
  656. }
  657. /*!
  658. * \internal
  659. * \brief Start the realtime queue logging if configured.
  660. *
  661. * \retval TRUE if not to open queue log file.
  662. */
  663. static int logger_queue_rt_start(void)
  664. {
  665. if (ast_check_realtime("queue_log")) {
  666. if (!ast_realtime_require_field("queue_log",
  667. "time", RQ_DATETIME, 26,
  668. "data1", RQ_CHAR, 20,
  669. "data2", RQ_CHAR, 20,
  670. "data3", RQ_CHAR, 20,
  671. "data4", RQ_CHAR, 20,
  672. "data5", RQ_CHAR, 20,
  673. SENTINEL)) {
  674. logfiles.queue_adaptive_realtime = 1;
  675. } else {
  676. logfiles.queue_adaptive_realtime = 0;
  677. }
  678. if (!logfiles.queue_log_to_file) {
  679. /* Don't open the log file. */
  680. return 1;
  681. }
  682. }
  683. return 0;
  684. }
  685. /*!
  686. * \internal
  687. * \brief Rotate the queue log file and restart.
  688. *
  689. * \param queue_rotate Log queue rotation mode.
  690. *
  691. * \note Assumes logchannels is write locked on entry.
  692. *
  693. * \retval 0 on success.
  694. * \retval -1 on error.
  695. */
  696. static int logger_queue_restart(int queue_rotate)
  697. {
  698. int res = 0;
  699. char qfname[PATH_MAX];
  700. if (logger_queue_rt_start()) {
  701. return res;
  702. }
  703. snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
  704. if (qlog) {
  705. /* Just in case it was still open. */
  706. fclose(qlog);
  707. qlog = NULL;
  708. }
  709. if (queue_rotate) {
  710. rotate_file(qfname);
  711. }
  712. /* Open the log file. */
  713. qlog = fopen(qfname, "a");
  714. if (!qlog) {
  715. ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
  716. res = -1;
  717. }
  718. return res;
  719. }
  720. static int reload_logger(int rotate, const char *altconf)
  721. {
  722. int queue_rotate = rotate;
  723. struct logchannel *f;
  724. int res = 0;
  725. AST_RWLIST_WRLOCK(&logchannels);
  726. if (qlog) {
  727. if (rotate < 0) {
  728. /* Check filesize - this one typically doesn't need an auto-rotate */
  729. if (ftello(qlog) > 0x40000000) { /* Arbitrarily, 1 GB */
  730. fclose(qlog);
  731. qlog = NULL;
  732. } else {
  733. queue_rotate = 0;
  734. }
  735. } else {
  736. fclose(qlog);
  737. qlog = NULL;
  738. }
  739. } else {
  740. queue_rotate = 0;
  741. }
  742. ast_mkdir(ast_config_AST_LOG_DIR, 0777);
  743. AST_RWLIST_TRAVERSE(&logchannels, f, list) {
  744. if (f->disabled) {
  745. f->disabled = 0; /* Re-enable logging at reload */
  746. /*** DOCUMENTATION
  747. <managerEventInstance>
  748. <synopsis>Raised when a logging channel is re-enabled after a reload operation.</synopsis>
  749. <syntax>
  750. <parameter name="Channel">
  751. <para>The name of the logging channel.</para>
  752. </parameter>
  753. </syntax>
  754. </managerEventInstance>
  755. ***/
  756. manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
  757. }
  758. if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
  759. int rotate_this = 0;
  760. if (rotatestrategy != NONE && ftello(f->fileptr) > 0x40000000) { /* Arbitrarily, 1 GB */
  761. /* Be more proactive about rotating massive log files */
  762. rotate_this = 1;
  763. }
  764. fclose(f->fileptr); /* Close file */
  765. f->fileptr = NULL;
  766. if (rotate || rotate_this) {
  767. rotate_file(f->filename);
  768. }
  769. }
  770. }
  771. filesize_reload_needed = 0;
  772. init_logger_chain(1 /* locked */, altconf);
  773. ast_unload_realtime("queue_log");
  774. if (logfiles.queue_log) {
  775. res = logger_queue_restart(queue_rotate);
  776. AST_RWLIST_UNLOCK(&logchannels);
  777. ast_verb_update();
  778. ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
  779. ast_verb(1, "Asterisk Queue Logger restarted\n");
  780. } else {
  781. AST_RWLIST_UNLOCK(&logchannels);
  782. ast_verb_update();
  783. }
  784. return res;
  785. }
  786. /*! \brief Reload the logger module without rotating log files (also used from loader.c during
  787. a full Asterisk reload) */
  788. int logger_reload(void)
  789. {
  790. if (reload_logger(0, NULL)) {
  791. return RESULT_FAILURE;
  792. }
  793. return RESULT_SUCCESS;
  794. }
  795. static char *handle_logger_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  796. {
  797. switch (cmd) {
  798. case CLI_INIT:
  799. e->command = "logger reload";
  800. e->usage =
  801. "Usage: logger reload [<alt-conf>]\n"
  802. " Reloads the logger subsystem state. Use after restarting syslogd(8) if you are using syslog logging.\n";
  803. return NULL;
  804. case CLI_GENERATE:
  805. return NULL;
  806. }
  807. if (reload_logger(0, a->argc == 3 ? a->argv[2] : NULL)) {
  808. ast_cli(a->fd, "Failed to reload the logger\n");
  809. return CLI_FAILURE;
  810. }
  811. return CLI_SUCCESS;
  812. }
  813. static char *handle_logger_rotate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  814. {
  815. switch (cmd) {
  816. case CLI_INIT:
  817. e->command = "logger rotate";
  818. e->usage =
  819. "Usage: logger rotate\n"
  820. " Rotates and Reopens the log files.\n";
  821. return NULL;
  822. case CLI_GENERATE:
  823. return NULL;
  824. }
  825. if (reload_logger(1, NULL)) {
  826. ast_cli(a->fd, "Failed to reload the logger and rotate log files\n");
  827. return CLI_FAILURE;
  828. }
  829. return CLI_SUCCESS;
  830. }
  831. static char *handle_logger_set_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  832. {
  833. int x;
  834. int state;
  835. int level = -1;
  836. switch (cmd) {
  837. case CLI_INIT:
  838. e->command = "logger set level {DEBUG|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}";
  839. e->usage =
  840. "Usage: logger set level {DEBUG|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}\n"
  841. " Set a specific log level to enabled/disabled for this console.\n";
  842. return NULL;
  843. case CLI_GENERATE:
  844. return NULL;
  845. }
  846. if (a->argc < 5)
  847. return CLI_SHOWUSAGE;
  848. AST_RWLIST_WRLOCK(&logchannels);
  849. for (x = 0; x < ARRAY_LEN(levels); x++) {
  850. if (levels[x] && !strcasecmp(a->argv[3], levels[x])) {
  851. level = x;
  852. break;
  853. }
  854. }
  855. AST_RWLIST_UNLOCK(&logchannels);
  856. state = ast_true(a->argv[4]) ? 1 : 0;
  857. if (level != -1) {
  858. ast_console_toggle_loglevel(a->fd, level, state);
  859. ast_cli(a->fd, "Logger status for '%s' has been set to '%s'.\n", levels[level], state ? "on" : "off");
  860. } else
  861. return CLI_SHOWUSAGE;
  862. return CLI_SUCCESS;
  863. }
  864. /*! \brief CLI command to show logging system configuration */
  865. static char *handle_logger_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  866. {
  867. #define FORMATL "%-35.35s %-8.8s %-9.9s "
  868. struct logchannel *chan;
  869. switch (cmd) {
  870. case CLI_INIT:
  871. e->command = "logger show channels";
  872. e->usage =
  873. "Usage: logger show channels\n"
  874. " List configured logger channels.\n";
  875. return NULL;
  876. case CLI_GENERATE:
  877. return NULL;
  878. }
  879. ast_cli(a->fd, FORMATL, "Channel", "Type", "Status");
  880. ast_cli(a->fd, "Configuration\n");
  881. ast_cli(a->fd, FORMATL, "-------", "----", "------");
  882. ast_cli(a->fd, "-------------\n");
  883. AST_RWLIST_RDLOCK(&logchannels);
  884. AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
  885. unsigned int level;
  886. ast_cli(a->fd, FORMATL, chan->filename, chan->type == LOGTYPE_CONSOLE ? "Console" : (chan->type == LOGTYPE_SYSLOG ? "Syslog" : "File"),
  887. chan->disabled ? "Disabled" : "Enabled");
  888. ast_cli(a->fd, " - ");
  889. for (level = 0; level < ARRAY_LEN(levels); level++) {
  890. if ((chan->logmask & (1 << level)) && levels[level]) {
  891. ast_cli(a->fd, "%s ", levels[level]);
  892. }
  893. }
  894. ast_cli(a->fd, "\n");
  895. }
  896. AST_RWLIST_UNLOCK(&logchannels);
  897. ast_cli(a->fd, "\n");
  898. return CLI_SUCCESS;
  899. }
  900. struct verb {
  901. void (*verboser)(const char *string);
  902. AST_LIST_ENTRY(verb) list;
  903. };
  904. static AST_RWLIST_HEAD_STATIC(verbosers, verb);
  905. static struct ast_cli_entry cli_logger[] = {
  906. AST_CLI_DEFINE(handle_logger_show_channels, "List configured log channels"),
  907. AST_CLI_DEFINE(handle_logger_reload, "Reopens the log files"),
  908. AST_CLI_DEFINE(handle_logger_rotate, "Rotates and reopens the log files"),
  909. AST_CLI_DEFINE(handle_logger_set_level, "Enables/Disables a specific logging level for this console"),
  910. };
  911. static void _handle_SIGXFSZ(int sig)
  912. {
  913. /* Indicate need to reload */
  914. filesize_reload_needed = 1;
  915. }
  916. static struct sigaction handle_SIGXFSZ = {
  917. .sa_handler = _handle_SIGXFSZ,
  918. .sa_flags = SA_RESTART,
  919. };
  920. static void ast_log_vsyslog(struct logmsg *msg)
  921. {
  922. char buf[BUFSIZ];
  923. int syslog_level = ast_syslog_priority_from_loglevel(msg->level);
  924. char call_identifier_str[13];
  925. if (msg->callid) {
  926. snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", (unsigned)msg->callid->call_identifier);
  927. } else {
  928. call_identifier_str[0] = '\0';
  929. }
  930. if (syslog_level < 0) {
  931. /* we are locked here, so cannot ast_log() */
  932. fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", msg->level);
  933. return;
  934. }
  935. snprintf(buf, sizeof(buf), "%s[%d]%s: %s:%d in %s: %s",
  936. levels[msg->level], msg->lwp, call_identifier_str, msg->file, msg->line, msg->function, msg->message);
  937. term_strip(buf, buf, strlen(buf) + 1);
  938. syslog(syslog_level, "%s", buf);
  939. }
  940. static char *logger_strip_verbose_magic(const char *message, int level)
  941. {
  942. const char *begin, *end;
  943. char *stripped_message, *dst;
  944. char magic = -(level + 1);
  945. if (!(stripped_message = ast_malloc(strlen(message) + 1))) {
  946. return NULL;
  947. }
  948. begin = message;
  949. dst = stripped_message;
  950. do {
  951. end = strchr(begin, magic);
  952. if (end) {
  953. size_t len = end - begin;
  954. memcpy(dst, begin, len);
  955. begin = end + 1;
  956. dst += len;
  957. } else {
  958. strcpy(dst, begin); /* safe */
  959. break;
  960. }
  961. } while (1);
  962. return stripped_message;
  963. }
  964. /*! \brief Print a normal log message to the channels */
  965. static void logger_print_normal(struct logmsg *logmsg)
  966. {
  967. struct logchannel *chan = NULL;
  968. char buf[BUFSIZ];
  969. struct verb *v = NULL;
  970. char *tmpmsg;
  971. int level = 0;
  972. if (logmsg->level == __LOG_VERBOSE) {
  973. /* Iterate through the list of verbosers and pass them the log message string */
  974. AST_RWLIST_RDLOCK(&verbosers);
  975. AST_RWLIST_TRAVERSE(&verbosers, v, list)
  976. v->verboser(logmsg->message);
  977. AST_RWLIST_UNLOCK(&verbosers);
  978. level = VERBOSE_MAGIC2LEVEL(logmsg->message);
  979. tmpmsg = logger_strip_verbose_magic(logmsg->message, level);
  980. if (tmpmsg) {
  981. ast_string_field_set(logmsg, message, tmpmsg);
  982. ast_free(tmpmsg);
  983. }
  984. }
  985. AST_RWLIST_RDLOCK(&logchannels);
  986. if (!AST_RWLIST_EMPTY(&logchannels)) {
  987. AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
  988. char call_identifier_str[13];
  989. if (logmsg->callid) {
  990. snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", (unsigned)logmsg->callid->call_identifier);
  991. } else {
  992. call_identifier_str[0] = '\0';
  993. }
  994. /* If the channel is disabled, then move on to the next one */
  995. if (chan->disabled) {
  996. continue;
  997. }
  998. if (logmsg->level == __LOG_VERBOSE
  999. && (((chan->verbosity < 0) ? option_verbose : chan->verbosity)) < level) {
  1000. continue;
  1001. }
  1002. /* Check syslog channels */
  1003. if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << logmsg->level))) {
  1004. ast_log_vsyslog(logmsg);
  1005. /* Console channels */
  1006. } else if (chan->type == LOGTYPE_CONSOLE && (chan->logmask & (1 << logmsg->level))) {
  1007. char linestr[128];
  1008. /* If the level is verbose, then skip it */
  1009. if (logmsg->level == __LOG_VERBOSE)
  1010. continue;
  1011. /* Turn the numerical line number into a string */
  1012. snprintf(linestr, sizeof(linestr), "%d", logmsg->line);
  1013. /* Build string to print out */
  1014. snprintf(buf, sizeof(buf), "[%s] " COLORIZE_FMT "[%d]%s: " COLORIZE_FMT ":" COLORIZE_FMT " " COLORIZE_FMT ": %s",
  1015. logmsg->date,
  1016. COLORIZE(colors[logmsg->level], 0, logmsg->level_name),
  1017. logmsg->lwp,
  1018. call_identifier_str,
  1019. COLORIZE(COLOR_BRWHITE, 0, logmsg->file),
  1020. COLORIZE(COLOR_BRWHITE, 0, linestr),
  1021. COLORIZE(COLOR_BRWHITE, 0, logmsg->function),
  1022. logmsg->message);
  1023. /* Print out */
  1024. ast_console_puts_mutable(buf, logmsg->level);
  1025. /* File channels */
  1026. } else if (chan->type == LOGTYPE_FILE && (chan->logmask & (1 << logmsg->level))) {
  1027. int res = 0;
  1028. /* If no file pointer exists, skip it */
  1029. if (!chan->fileptr) {
  1030. continue;
  1031. }
  1032. /* Print out to the file */
  1033. res = fprintf(chan->fileptr, "[%s] %s[%d]%s %s: %s",
  1034. logmsg->date, logmsg->level_name, logmsg->lwp, call_identifier_str,
  1035. logmsg->file, term_strip(buf, logmsg->message, BUFSIZ));
  1036. if (res <= 0 && !ast_strlen_zero(logmsg->message)) {
  1037. fprintf(stderr, "**** Asterisk Logging Error: ***********\n");
  1038. if (errno == ENOMEM || errno == ENOSPC)
  1039. fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
  1040. else
  1041. fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
  1042. /*** DOCUMENTATION
  1043. <managerEventInstance>
  1044. <synopsis>Raised when a logging channel is disabled.</synopsis>
  1045. <syntax>
  1046. <parameter name="Channel">
  1047. <para>The name of the logging channel.</para>
  1048. </parameter>
  1049. </syntax>
  1050. </managerEventInstance>
  1051. ***/
  1052. manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
  1053. chan->disabled = 1;
  1054. } else if (res > 0) {
  1055. fflush(chan->fileptr);
  1056. }
  1057. }
  1058. }
  1059. } else if (logmsg->level != __LOG_VERBOSE) {
  1060. fputs(logmsg->message, stdout);
  1061. }
  1062. AST_RWLIST_UNLOCK(&logchannels);
  1063. /* If we need to reload because of the file size, then do so */
  1064. if (filesize_reload_needed) {
  1065. reload_logger(-1, NULL);
  1066. ast_verb(1, "Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
  1067. }
  1068. return;
  1069. }
  1070. /*! \brief Actual logging thread */
  1071. static void *logger_thread(void *data)
  1072. {
  1073. struct logmsg *next = NULL, *msg = NULL;
  1074. for (;;) {
  1075. /* We lock the message list, and see if any message exists... if not we wait on the condition to be signalled */
  1076. AST_LIST_LOCK(&logmsgs);
  1077. if (AST_LIST_EMPTY(&logmsgs)) {
  1078. if (close_logger_thread) {
  1079. AST_LIST_UNLOCK(&logmsgs);
  1080. break;
  1081. } else {
  1082. ast_cond_wait(&logcond, &logmsgs.lock);
  1083. }
  1084. }
  1085. next = AST_LIST_FIRST(&logmsgs);
  1086. AST_LIST_HEAD_INIT_NOLOCK(&logmsgs);
  1087. AST_LIST_UNLOCK(&logmsgs);
  1088. /* Otherwise go through and process each message in the order added */
  1089. while ((msg = next)) {
  1090. /* Get the next entry now so that we can free our current structure later */
  1091. next = AST_LIST_NEXT(msg, list);
  1092. /* Depending on the type, send it to the proper function */
  1093. logger_print_normal(msg);
  1094. /* Free the data since we are done */
  1095. logmsg_free(msg);
  1096. }
  1097. }
  1098. return NULL;
  1099. }
  1100. /*!
  1101. * \internal
  1102. * \brief Initialize the logger queue.
  1103. *
  1104. * \note Assumes logchannels is write locked on entry.
  1105. *
  1106. * \return Nothing
  1107. */
  1108. static void logger_queue_init(void)
  1109. {
  1110. ast_unload_realtime("queue_log");
  1111. if (logfiles.queue_log) {
  1112. char qfname[PATH_MAX];
  1113. if (logger_queue_rt_start()) {
  1114. return;
  1115. }
  1116. /* Open the log file. */
  1117. snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR,
  1118. queue_log_name);
  1119. if (qlog) {
  1120. /* Just in case it was already open. */
  1121. fclose(qlog);
  1122. }
  1123. qlog = fopen(qfname, "a");
  1124. if (!qlog) {
  1125. ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
  1126. }
  1127. }
  1128. }
  1129. int init_logger(void)
  1130. {
  1131. /* auto rotate if sig SIGXFSZ comes a-knockin */
  1132. sigaction(SIGXFSZ, &handle_SIGXFSZ, NULL);
  1133. /* Re-initialize the logmsgs mutex. The recursive mutex can be accessed prior
  1134. * to Asterisk being forked into the background, which can cause the thread
  1135. * ID tracked by the underlying pthread mutex to be different than the ID of
  1136. * the thread that unlocks the mutex. Since init_logger is called after the
  1137. * fork, it is safe to initialize the mutex here for future accesses.
  1138. */
  1139. ast_mutex_destroy(&logmsgs.lock);
  1140. ast_mutex_init(&logmsgs.lock);
  1141. ast_cond_init(&logcond, NULL);
  1142. /* start logger thread */
  1143. if (ast_pthread_create(&logthread, NULL, logger_thread, NULL) < 0) {
  1144. ast_cond_destroy(&logcond);
  1145. return -1;
  1146. }
  1147. /* register the logger cli commands */
  1148. ast_cli_register_multiple(cli_logger, ARRAY_LEN(cli_logger));
  1149. ast_mkdir(ast_config_AST_LOG_DIR, 0777);
  1150. /* create log channels */
  1151. init_logger_chain(0 /* locked */, NULL);
  1152. ast_verb_update();
  1153. logger_initialized = 1;
  1154. return 0;
  1155. }
  1156. void close_logger(void)
  1157. {
  1158. struct logchannel *f = NULL;
  1159. struct verb *cur = NULL;
  1160. ast_cli_unregister_multiple(cli_logger, ARRAY_LEN(cli_logger));
  1161. logger_initialized = 0;
  1162. /* Stop logger thread */
  1163. AST_LIST_LOCK(&logmsgs);
  1164. close_logger_thread = 1;
  1165. ast_cond_signal(&logcond);
  1166. AST_LIST_UNLOCK(&logmsgs);
  1167. if (logthread != AST_PTHREADT_NULL)
  1168. pthread_join(logthread, NULL);
  1169. AST_RWLIST_WRLOCK(&verbosers);
  1170. while ((cur = AST_LIST_REMOVE_HEAD(&verbosers, list))) {
  1171. ast_free(cur);
  1172. }
  1173. AST_RWLIST_UNLOCK(&verbosers);
  1174. AST_RWLIST_WRLOCK(&logchannels);
  1175. if (qlog) {
  1176. fclose(qlog);
  1177. qlog = NULL;
  1178. }
  1179. while ((f = AST_LIST_REMOVE_HEAD(&logchannels, list))) {
  1180. if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
  1181. fclose(f->fileptr);
  1182. f->fileptr = NULL;
  1183. }
  1184. ast_free(f);
  1185. }
  1186. closelog(); /* syslog */
  1187. AST_RWLIST_UNLOCK(&logchannels);
  1188. }
  1189. void ast_callid_strnprint(char *buffer, size_t buffer_size, struct ast_callid *callid)
  1190. {
  1191. snprintf(buffer, buffer_size, "[C-%08x]", (unsigned)callid->call_identifier);
  1192. }
  1193. struct ast_callid *ast_create_callid(void)
  1194. {
  1195. struct ast_callid *call;
  1196. call = ao2_alloc_options(sizeof(*call), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
  1197. if (!call) {
  1198. ast_log(LOG_ERROR, "Could not allocate callid struct.\n");
  1199. return NULL;
  1200. }
  1201. call->call_identifier = ast_atomic_fetchadd_int(&next_unique_callid, +1);
  1202. #ifdef TEST_FRAMEWORK
  1203. ast_debug(3, "CALL_ID [C-%08x] created by thread.\n", (unsigned)call->call_identifier);
  1204. #endif
  1205. return call;
  1206. }
  1207. struct ast_callid *ast_read_threadstorage_callid(void)
  1208. {
  1209. struct ast_callid **callid;
  1210. callid = ast_threadstorage_get(&unique_callid, sizeof(*callid));
  1211. if (callid && *callid) {
  1212. ast_callid_ref(*callid);
  1213. return *callid;
  1214. }
  1215. return NULL;
  1216. }
  1217. int ast_callid_threadassoc_change(struct ast_callid *callid)
  1218. {
  1219. struct ast_callid **id = ast_threadstorage_get(&unique_callid, sizeof(*id));
  1220. if (!id) {
  1221. ast_log(LOG_ERROR, "Failed to allocate thread storage.\n");
  1222. return -1;
  1223. }
  1224. if (*id && (*id != callid)) {
  1225. #ifdef TEST_FRAMEWORK
  1226. ast_debug(3, "CALL_ID [C-%08x] being removed from thread.\n", (unsigned)(*id)->call_identifier);
  1227. #endif
  1228. *id = ast_callid_unref(*id);
  1229. *id = NULL;
  1230. }
  1231. if (!(*id) && callid) {
  1232. /* callid will be unreffed at thread destruction */
  1233. ast_callid_ref(callid);
  1234. *id = callid;
  1235. #ifdef TEST_FRAMEWORK
  1236. ast_debug(3, "CALL_ID [C-%08x] bound to thread.\n", (unsigned)callid->call_identifier);
  1237. #endif
  1238. }
  1239. return 0;
  1240. }
  1241. int ast_callid_threadassoc_add(struct ast_callid *callid)
  1242. {
  1243. struct ast_callid **pointing;
  1244. pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
  1245. if (!(pointing)) {
  1246. ast_log(LOG_ERROR, "Failed to allocate thread storage.\n");
  1247. return -1;
  1248. }
  1249. if (!(*pointing)) {
  1250. /* callid will be unreffed at thread destruction */
  1251. ast_callid_ref(callid);
  1252. *pointing = callid;
  1253. #ifdef TEST_FRAMEWORK
  1254. ast_debug(3, "CALL_ID [C-%08x] bound to thread.\n", (unsigned)callid->call_identifier);
  1255. #endif
  1256. } else {
  1257. ast_log(LOG_WARNING, "Attempted to ast_callid_threadassoc_add on thread already associated with a callid.\n");
  1258. return 1;
  1259. }
  1260. return 0;
  1261. }
  1262. int ast_callid_threadassoc_remove(void)
  1263. {
  1264. struct ast_callid **pointing;
  1265. pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
  1266. if (!(pointing)) {
  1267. ast_log(LOG_ERROR, "Failed to allocate thread storage.\n");
  1268. return -1;
  1269. }
  1270. if (!(*pointing)) {
  1271. ast_log(LOG_ERROR, "Tried to clean callid thread storage with no callid in thread storage.\n");
  1272. return -1;
  1273. } else {
  1274. #ifdef TEST_FRAMEWORK
  1275. ast_debug(3, "CALL_ID [C-%08x] being removed from thread.\n", (unsigned)(*pointing)->call_identifier);
  1276. #endif
  1277. *pointing = ast_callid_unref(*pointing);
  1278. return 0;
  1279. }
  1280. }
  1281. int ast_callid_threadstorage_auto(struct ast_callid **callid)
  1282. {
  1283. struct ast_callid *tmp;
  1284. /* Start by trying to see if a callid is available from thread storage */
  1285. tmp = ast_read_threadstorage_callid();
  1286. if (tmp) {
  1287. *callid = tmp;
  1288. return 0;
  1289. }
  1290. /* If that failed, try to create a new one and bind it. */
  1291. tmp = ast_create_callid();
  1292. if (tmp) {
  1293. ast_callid_threadassoc_add(tmp);
  1294. *callid = tmp;
  1295. return 1;
  1296. }
  1297. /* If neither worked, then something must have gone wrong. */
  1298. return -1;
  1299. }
  1300. void ast_callid_threadstorage_auto_clean(struct ast_callid *callid, int callid_created)
  1301. {
  1302. if (callid) {
  1303. /* If the callid was created rather than simply grabbed from the thread storage, we need to unbind here. */
  1304. if (callid_created == 1) {
  1305. ast_callid_threadassoc_remove();
  1306. }
  1307. callid = ast_callid_unref(callid);
  1308. }
  1309. }
  1310. /*!
  1311. * \internal
  1312. * \brief thread storage cleanup function for unique_callid
  1313. */
  1314. static void unique_callid_cleanup(void *data)
  1315. {
  1316. struct ast_callid **callid = data;
  1317. if (*callid) {
  1318. ast_callid_unref(*callid);
  1319. }
  1320. ast_free(data);
  1321. }
  1322. /*!
  1323. * \brief send log messages to syslog and/or the console
  1324. */
  1325. static void __attribute__((format(printf, 6, 0))) ast_log_full(int level, const char *file, int line, const char *function, struct ast_callid *callid, const char *fmt, va_list ap)
  1326. {
  1327. struct logmsg *logmsg = NULL;
  1328. struct ast_str *buf = NULL;
  1329. struct ast_tm tm;
  1330. struct timeval now = ast_tvnow();
  1331. int res = 0;
  1332. char datestring[256];
  1333. if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE)))
  1334. return;
  1335. if (level != __LOG_VERBOSE && AST_RWLIST_EMPTY(&logchannels)) {
  1336. /*
  1337. * we don't have the logger chain configured yet,
  1338. * so just log to stdout
  1339. */
  1340. int result;
  1341. result = ast_str_set_va(&buf, BUFSIZ, fmt, ap); /* XXX BUFSIZ ? */
  1342. if (result != AST_DYNSTR_BUILD_FAILED) {
  1343. term_filter_escapes(ast_str_buffer(buf));
  1344. fputs(ast_str_buffer(buf), stdout);
  1345. }
  1346. return;
  1347. }
  1348. /* Ignore anything that never gets logged anywhere */
  1349. if (level != __LOG_VERBOSE && !(global_logmask & (1 << level)))
  1350. return;
  1351. /* Build string */
  1352. res = ast_str_set_va(&buf, BUFSIZ, fmt, ap);
  1353. /* If the build failed, then abort and free this structure */
  1354. if (res == AST_DYNSTR_BUILD_FAILED)
  1355. return;
  1356. /* Create a new logging message */
  1357. if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128)))
  1358. return;
  1359. /* Copy string over */
  1360. ast_string_field_set(logmsg, message, ast_str_buffer(buf));
  1361. /* Set type */
  1362. if (level == __LOG_VERBOSE) {
  1363. logmsg->type = LOGMSG_VERBOSE;
  1364. } else {
  1365. logmsg->type = LOGMSG_NORMAL;
  1366. }
  1367. if (display_callids && callid) {
  1368. logmsg->callid = ast_callid_ref(callid);
  1369. /* callid will be unreffed at logmsg destruction */
  1370. }
  1371. /* Create our date/time */
  1372. ast_localtime(&now, &tm, NULL);
  1373. ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
  1374. ast_string_field_set(logmsg, date, datestring);
  1375. /* Copy over data */
  1376. logmsg->level = level;
  1377. logmsg->line = line;
  1378. ast_string_field_set(logmsg, level_name, levels[level]);
  1379. ast_string_field_set(logmsg, file, file);
  1380. ast_string_field_set(logmsg, function, function);
  1381. logmsg->lwp = ast_get_tid();
  1382. /* If the logger thread is active, append it to the tail end of the list - otherwise skip that step */
  1383. if (logthread != AST_PTHREADT_NULL) {
  1384. AST_LIST_LOCK(&logmsgs);
  1385. if (close_logger_thread) {
  1386. /* Logger is either closing or closed. We cannot log this message. */
  1387. logmsg_free(logmsg);
  1388. } else {
  1389. AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list);
  1390. ast_cond_signal(&logcond);
  1391. }
  1392. AST_LIST_UNLOCK(&logmsgs);
  1393. } else {
  1394. logger_print_normal(logmsg);
  1395. logmsg_free(logmsg);
  1396. }
  1397. }
  1398. void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
  1399. {
  1400. struct ast_callid *callid;
  1401. va_list ap;
  1402. callid = ast_read_threadstorage_callid();
  1403. va_start(ap, fmt);
  1404. if (level == __LOG_VERBOSE) {
  1405. __ast_verbose_ap(file, line, function, 0, callid, fmt, ap);
  1406. } else {
  1407. ast_log_full(level, file, line, function, callid, fmt, ap);
  1408. }
  1409. va_end(ap);
  1410. if (callid) {
  1411. ast_callid_unref(callid);
  1412. }
  1413. }
  1414. void ast_log_callid(int level, const char *file, int line, const char *function, struct ast_callid *callid, const char *fmt, ...)
  1415. {
  1416. va_list ap;
  1417. va_start(ap, fmt);
  1418. ast_log_full(level, file, line, function, callid, fmt, ap);
  1419. va_end(ap);
  1420. }
  1421. void ast_log_backtrace(void)
  1422. {
  1423. #ifdef HAVE_BKTR
  1424. struct ast_bt *bt;
  1425. int i = 0;
  1426. char **strings;
  1427. if (!(bt = ast_bt_create())) {
  1428. ast_log(LOG_WARNING, "Unable to allocate space for backtrace structure\n");
  1429. return;
  1430. }
  1431. if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
  1432. ast_debug(1, "Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' ');
  1433. for (i = 3; i < bt->num_frames - 2; i++) {
  1434. ast_debug(1, "#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
  1435. }
  1436. ast_std_free(strings);
  1437. } else {
  1438. ast_debug(1, "Could not allocate memory for backtrace\n");
  1439. }
  1440. ast_bt_destroy(bt);
  1441. #else
  1442. ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n");
  1443. #endif /* defined(HAVE_BKTR) */
  1444. }
  1445. void __ast_verbose_ap(const char *file, int line, const char *func, int level, struct ast_callid *callid, const char *fmt, va_list ap)
  1446. {
  1447. const char *p;
  1448. struct ast_str *prefixed, *buf = NULL;
  1449. int res = 0;
  1450. const char *prefix = level >= 4 ? VERBOSE_PREFIX_4 : level == 3 ? VERBOSE_PREFIX_3 : level == 2 ? VERBOSE_PREFIX_2 : level == 1 ? VERBOSE_PREFIX_1 : "";
  1451. signed char magic = level > 9 ? -10 : -level - 1; /* 0 => -1, 1 => -2, etc. Can't pass NUL, as it is EOS-delimiter */
  1452. /* For compatibility with modules still calling ast_verbose() directly instead of using ast_verb() */
  1453. if (level < 0) {
  1454. if (!strncmp(fmt, VERBOSE_PREFIX_4, strlen(VERBOSE_PREFIX_4))) {
  1455. magic = -5;
  1456. } else if (!strncmp(fmt, VERBOSE_PREFIX_3, strlen(VERBOSE_PREFIX_3))) {
  1457. magic = -4;
  1458. } else if (!strncmp(fmt, VERBOSE_PREFIX_2, strlen(VERBOSE_PREFIX_2))) {
  1459. magic = -3;
  1460. } else if (!strncmp(fmt, VERBOSE_PREFIX_1, strlen(VERBOSE_PREFIX_1))) {
  1461. magic = -2;
  1462. } else {
  1463. magic = -1;
  1464. }
  1465. }
  1466. if (!(prefixed = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE)) ||
  1467. !(buf = ast_str_create(VERBOSE_BUF_INIT_SIZE))) {
  1468. return;
  1469. }
  1470. res = ast_str_set_va(&buf, 0, fmt, ap);
  1471. /* If the build failed then we can drop this allocated message */
  1472. if (res == AST_DYNSTR_BUILD_FAILED) {
  1473. ast_free(buf);
  1474. return;
  1475. }
  1476. ast_str_reset(prefixed);
  1477. /* for every newline found in the buffer add verbose prefix data */
  1478. fmt = ast_str_buffer(buf);
  1479. do {
  1480. if (!(p = strchr(fmt, '\n'))) {
  1481. p = strchr(fmt, '\0') - 1;
  1482. }
  1483. ++p;
  1484. if (ast_opt_timestamp) {
  1485. struct ast_tm tm;
  1486. char date[40];
  1487. struct timeval now = ast_tvnow();
  1488. ast_localtime(&now, &tm, NULL);
  1489. ast_strftime(date, sizeof(date), dateformat, &tm);
  1490. ast_str_append(&prefixed, 0, "%c[%s] %s", (char) magic, date, prefix);
  1491. } else {
  1492. ast_str_append(&prefixed, 0, "%c%s", (char) magic, prefix);
  1493. }
  1494. ast_str_append_substr(&prefixed, 0, fmt, p - fmt);
  1495. fmt = p;
  1496. } while (p && *p);
  1497. ast_log_callid(__LOG_VERBOSE, file, line, func, callid, "%s", ast_str_buffer(prefixed));
  1498. ast_free(buf);
  1499. }
  1500. void __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt, ...)
  1501. {
  1502. struct ast_callid *callid;
  1503. va_list ap;
  1504. callid = ast_read_threadstorage_callid();
  1505. va_start(ap, fmt);
  1506. __ast_verbose_ap(file, line, func, level, callid, fmt, ap);
  1507. va_end(ap);
  1508. if (callid) {
  1509. ast_callid_unref(callid);
  1510. }
  1511. }
  1512. void __ast_verbose_callid(const char *file, int line, const char *func, int level, struct ast_callid *callid, const char *fmt, ...)
  1513. {
  1514. va_list ap;
  1515. va_start(ap, fmt);
  1516. __ast_verbose_ap(file, line, func, level, callid, fmt, ap);
  1517. va_end(ap);
  1518. }
  1519. /* No new code should use this directly, but we have the ABI for backwards compat */
  1520. #undef ast_verbose
  1521. void __attribute__((format(printf, 1,2))) ast_verbose(const char *fmt, ...);
  1522. void ast_verbose(const char *fmt, ...)
  1523. {
  1524. struct ast_callid *callid;
  1525. va_list ap;
  1526. callid = ast_read_threadstorage_callid();
  1527. va_start(ap, fmt);
  1528. __ast_verbose_ap("", 0, "", 0, callid, fmt, ap);
  1529. va_end(ap);
  1530. if (callid) {
  1531. ast_callid_unref(callid);
  1532. }
  1533. }
  1534. /*! Console verbosity level node. */
  1535. struct verb_console {
  1536. /*! List node link */
  1537. AST_LIST_ENTRY(verb_console) node;
  1538. /*! Console verbosity level. */
  1539. int *level;
  1540. };
  1541. /*! Registered console verbosity levels */
  1542. static AST_RWLIST_HEAD_STATIC(verb_consoles, verb_console);
  1543. /*! ast_verb_update() reentrancy protection lock. */
  1544. AST_MUTEX_DEFINE_STATIC(verb_update_lock);
  1545. void ast_verb_update(void)
  1546. {
  1547. struct logchannel *log;
  1548. struct verb_console *console;
  1549. int verb_level;
  1550. ast_mutex_lock(&verb_update_lock);
  1551. AST_RWLIST_RDLOCK(&verb_consoles);
  1552. /* Default to the root console verbosity. */
  1553. verb_level = option_verbose;
  1554. /* Determine max remote console level. */
  1555. AST_LIST_TRAVERSE(&verb_consoles, console, node) {
  1556. if (verb_level < *console->level) {
  1557. verb_level = *console->level;
  1558. }
  1559. }
  1560. AST_RWLIST_UNLOCK(&verb_consoles);
  1561. /* Determine max logger channel level. */
  1562. AST_RWLIST_RDLOCK(&logchannels);
  1563. AST_RWLIST_TRAVERSE(&logchannels, log, list) {
  1564. if (verb_level < log->verbosity) {
  1565. verb_level = log->verbosity;
  1566. }
  1567. }
  1568. AST_RWLIST_UNLOCK(&logchannels);
  1569. ast_verb_sys_level = verb_level;
  1570. ast_mutex_unlock(&verb_update_lock);
  1571. }
  1572. /*!
  1573. * \internal
  1574. * \brief Unregister a console verbose level.
  1575. *
  1576. * \param console Which console to unregister.
  1577. *
  1578. * \return Nothing
  1579. */
  1580. static void verb_console_unregister(struct verb_console *console)
  1581. {
  1582. AST_RWLIST_WRLOCK(&verb_consoles);
  1583. console = AST_RWLIST_REMOVE(&verb_consoles, console, node);
  1584. AST_RWLIST_UNLOCK(&verb_consoles);
  1585. if (console) {
  1586. ast_verb_update();
  1587. }
  1588. }
  1589. static void verb_console_free(void *v_console)
  1590. {
  1591. struct verb_console *console = v_console;
  1592. verb_console_unregister(console);
  1593. ast_free(console);
  1594. }
  1595. /*! Thread specific console verbosity level node. */
  1596. AST_THREADSTORAGE_CUSTOM(my_verb_console, NULL, verb_console_free);
  1597. void ast_verb_console_register(int *level)
  1598. {
  1599. struct verb_console *console;
  1600. console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
  1601. if (!console || !level) {
  1602. return;
  1603. }
  1604. console->level = level;
  1605. AST_RWLIST_WRLOCK(&verb_consoles);
  1606. AST_RWLIST_INSERT_HEAD(&verb_consoles, console, node);
  1607. AST_RWLIST_UNLOCK(&verb_consoles);
  1608. ast_verb_update();
  1609. }
  1610. void ast_verb_console_unregister(void)
  1611. {
  1612. struct verb_console *console;
  1613. console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
  1614. if (!console) {
  1615. return;
  1616. }
  1617. verb_console_unregister(console);
  1618. }
  1619. int ast_verb_console_get(void)
  1620. {
  1621. struct verb_console *console;
  1622. int verb_level;
  1623. console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
  1624. AST_RWLIST_RDLOCK(&verb_consoles);
  1625. if (!console) {
  1626. verb_level = 0;
  1627. } else if (console->level) {
  1628. verb_level = *console->level;
  1629. } else {
  1630. verb_level = option_verbose;
  1631. }
  1632. AST_RWLIST_UNLOCK(&verb_consoles);
  1633. return verb_level;
  1634. }
  1635. void ast_verb_console_set(int verb_level)
  1636. {
  1637. struct verb_console *console;
  1638. console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
  1639. if (!console) {
  1640. return;
  1641. }
  1642. AST_RWLIST_WRLOCK(&verb_consoles);
  1643. if (console->level) {
  1644. *console->level = verb_level;
  1645. } else {
  1646. option_verbose = verb_level;
  1647. }
  1648. AST_RWLIST_UNLOCK(&verb_consoles);
  1649. ast_verb_update();
  1650. }
  1651. int ast_register_verbose(void (*v)(const char *string))
  1652. {
  1653. struct verb *verb;
  1654. if (!(verb = ast_malloc(sizeof(*verb))))
  1655. return -1;
  1656. verb->verboser = v;
  1657. AST_RWLIST_WRLOCK(&verbosers);
  1658. AST_RWLIST_INSERT_HEAD(&verbosers, verb, list);
  1659. AST_RWLIST_UNLOCK(&verbosers);
  1660. return 0;
  1661. }
  1662. int ast_unregister_verbose(void (*v)(const char *string))
  1663. {
  1664. struct verb *cur;
  1665. AST_RWLIST_WRLOCK(&verbosers);
  1666. AST_RWLIST_TRAVERSE_SAFE_BEGIN(&verbosers, cur, list) {
  1667. if (cur->verboser == v) {
  1668. AST_RWLIST_REMOVE_CURRENT(list);
  1669. ast_free(cur);
  1670. break;
  1671. }
  1672. }
  1673. AST_RWLIST_TRAVERSE_SAFE_END;
  1674. AST_RWLIST_UNLOCK(&verbosers);
  1675. return cur ? 0 : -1;
  1676. }
  1677. static void update_logchannels(void)
  1678. {
  1679. struct logchannel *cur;
  1680. AST_RWLIST_WRLOCK(&logchannels);
  1681. global_logmask = 0;
  1682. AST_RWLIST_TRAVERSE(&logchannels, cur, list) {
  1683. make_components(cur);
  1684. global_logmask |= cur->logmask;
  1685. }
  1686. AST_RWLIST_UNLOCK(&logchannels);
  1687. }
  1688. int ast_logger_register_level(const char *name)
  1689. {
  1690. unsigned int level;
  1691. unsigned int available = 0;
  1692. AST_RWLIST_WRLOCK(&logchannels);
  1693. for (level = 0; level < ARRAY_LEN(levels); level++) {
  1694. if ((level >= 16) && !available && !levels[level]) {
  1695. available = level;
  1696. continue;
  1697. }
  1698. if (levels[level] && !strcasecmp(levels[level], name)) {
  1699. ast_log(LOG_WARNING,
  1700. "Unable to register dynamic logger level '%s': a standard logger level uses that name.\n",
  1701. name);
  1702. AST_RWLIST_UNLOCK(&logchannels);
  1703. return -1;
  1704. }
  1705. }
  1706. if (!available) {
  1707. ast_log(LOG_WARNING,
  1708. "Unable to register dynamic logger level '%s'; maximum number of levels registered.\n",
  1709. name);
  1710. AST_RWLIST_UNLOCK(&logchannels);
  1711. return -1;
  1712. }
  1713. levels[available] = ast_strdup(name);
  1714. AST_RWLIST_UNLOCK(&logchannels);
  1715. ast_debug(1, "Registered dynamic logger level '%s' with index %u.\n", name, available);
  1716. update_logchannels();
  1717. return available;
  1718. }
  1719. void ast_logger_unregister_level(const char *name)
  1720. {
  1721. unsigned int found = 0;
  1722. unsigned int x;
  1723. AST_RWLIST_WRLOCK(&logchannels);
  1724. for (x = 16; x < ARRAY_LEN(levels); x++) {
  1725. if (!levels[x]) {
  1726. continue;
  1727. }
  1728. if (strcasecmp(levels[x], name)) {
  1729. continue;
  1730. }
  1731. found = 1;
  1732. break;
  1733. }
  1734. if (found) {
  1735. /* take this level out of the global_logmask, to ensure that no new log messages
  1736. * will be queued for it
  1737. */
  1738. global_logmask &= ~(1 << x);
  1739. ast_free(levels[x]);
  1740. levels[x] = NULL;
  1741. AST_RWLIST_UNLOCK(&logchannels);
  1742. ast_debug(1, "Unregistered dynamic logger level '%s' with index %u.\n", name, x);
  1743. update_logchannels();
  1744. } else {
  1745. AST_RWLIST_UNLOCK(&logchannels);
  1746. }
  1747. }