[svn-commits] tilghman: trunk r278307 - in /trunk: ./ configs/ contrib/realtime/mysql/ main...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jul 20 18:23:33 CDT 2010


Author: tilghman
Date: Tue Jul 20 18:23:25 2010
New Revision: 278307

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=278307
Log:
Separate queue_log arguments into separate fields, and allow the text file to be used, even when realtime is used.

(closes issue #17082)
 Reported by: coolmig
 Patches: 
       20100720__issue17082.diff.txt uploaded by tilghman (license 14)
 Tested by: coolmig

Added:
    trunk/contrib/realtime/mysql/queue_log.sql   (with props)
Modified:
    trunk/CHANGES
    trunk/configs/logger.conf.sample
    trunk/main/logger.c
    trunk/res/res_config_pgsql.c

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=278307&r1=278306&r2=278307
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Tue Jul 20 18:23:25 2010
@@ -270,6 +270,11 @@
    queues for which he is a member, not just the queue that failed to reach
    the member.
  * Added dialplan function QUEUE_EXISTS to check if a queue exists
+ * The queue logger now allows events to optionally propagate to a file,
+   even when realtime logging is turned on.  Additionally, realtime logging
+   supports sending the event arguments to 5 individual fields, although it
+   will fallback to the previous data definition, if the new table layout is
+   not found.
 
 mISDN channel driver (chan_misdn) changes
 ----------------------------------------

Modified: trunk/configs/logger.conf.sample
URL: http://svnview.digium.com/svn/asterisk/trunk/configs/logger.conf.sample?view=diff&rev=278307&r1=278306&r2=278307
==============================================================================
--- trunk/configs/logger.conf.sample (original)
+++ trunk/configs/logger.conf.sample Tue Jul 20 18:23:25 2010
@@ -26,18 +26,27 @@
 ; (defaults to yes).
 ;queue_log = no
 ;
+; Determines whether the queue_log always goes to a file, even
+; when a realtime backend is present (defaults to no).
+;queue_log_to_file = yes
+;
 ; Set the queue_log filename
 ; (defaults to queue_log)
 ;queue_log_name = queue_log
 ;
 ; Log rotation strategy:
 ; sequential:  Rename archived logs in order, such that the newest
-;              has the highest sequence number [default].
+;              has the highest sequence number [default].  When
+;              exec_after_rotate is set, ${filename} will specify
+;              the new archived logfile.
 ; rotate:  Rotate all the old files, such that the oldest has the
 ;          highest sequence number [this is the expected behavior
-;          for Unix administrators].
+;          for Unix administrators].  When exec_after_rotate is
+;          set, ${filename} will specify the original root filename.
 ; timestamp:  Rename the logfiles using a timestamp instead of a
 ;             sequence number when "logger rotate" is executed.
+;             When exec_after_rotate is set, ${filename} will
+;             specify the new archived logfile.
 ;rotatestrategy = rotate
 ;
 ; Run a system command after rotating the files.  This is mainly

Added: trunk/contrib/realtime/mysql/queue_log.sql
URL: http://svnview.digium.com/svn/asterisk/trunk/contrib/realtime/mysql/queue_log.sql?view=auto&rev=278307
==============================================================================
--- trunk/contrib/realtime/mysql/queue_log.sql (added)
+++ trunk/contrib/realtime/mysql/queue_log.sql Tue Jul 20 18:23:25 2010
@@ -1,0 +1,24 @@
+CREATE TABLE queue_log (
+	-- Event date and time
+	time datetime,
+	-- "REALTIME", "NONE", or channel uniqueid
+	callid char(50),
+	-- Name of the queue affected
+	queuename char(50),
+	-- Interface name of the queue member
+	agent char(50),
+	-- One of ADDMEMBER, REMOVEMEMBER, RINGNOANSWER, EXITEMPTY, TRANSFER,
+	-- AGENTDUMP, ABANDON, SYSCOMPAT, CONNECT, COMPLETECALLER, COMPLETEAGENT,
+	-- PAUSEALL, UNPAUSEALL, PAUSE, UNPAUSE, PENALTY, ENTERQUEUE,
+	-- EXITWITHTIMEOUT, EXITEMPTY, EXITWITHKEY, or another defined by the user.
+	event char(20),
+	-- data1 through data5 are possible arguments to the event, the definitions
+	-- of which are dependent upon the type of event.
+	data1 char(50),
+	data2 char(50),
+	data3 char(50),
+	data4 char(50),
+	data5 char(50),
+	index bydate (time),
+	index qname (queuename,datetime)
+);

Propchange: trunk/contrib/realtime/mysql/queue_log.sql
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: trunk/contrib/realtime/mysql/queue_log.sql
------------------------------------------------------------------------------
    svn:keywords = 'Date Author Id Revision Yoyo'

Propchange: trunk/contrib/realtime/mysql/queue_log.sql
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: trunk/main/logger.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/logger.c?view=diff&rev=278307&r1=278306&r2=278307
==============================================================================
--- trunk/main/logger.c (original)
+++ trunk/main/logger.c Tue Jul 20 18:23:25 2010
@@ -74,6 +74,7 @@
 
 static int filesize_reload_needed;
 static unsigned int global_logmask = 0xFFFF;
+static int queuelog_init;
 
 static enum rotatestrategy {
 	SEQUENTIAL = 1 << 0,     /* Original method - create a new file, in order */
@@ -83,6 +84,8 @@
 
 static struct {
 	unsigned int queue_log:1;
+	unsigned int queue_log_to_file:1;
+	unsigned int queue_adaptive_realtime:1;
 } logfiles = { 1 };
 
 static char hostname[MAXHOSTNAMELEN];
@@ -206,6 +209,8 @@
 AST_THREADSTORAGE(log_buf);
 #define LOG_BUF_INIT_SIZE       256
 
+static void logger_queue_init(void);
+
 static unsigned int make_components(const char *s, int lineno)
 {
 	char *w;
@@ -291,41 +296,49 @@
 	const char *s;
 	struct ast_flags config_flags = { 0 };
 
-	if (!(cfg = ast_config_load2("logger.conf", "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID)
-		return;
+	if (!(cfg = ast_config_load2("logger.conf", "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
+		return;
+	}
 
 	/* delete our list of log channels */
-	if (!locked)
+	if (!locked) {
 		AST_RWLIST_WRLOCK(&logchannels);
-	while ((chan = AST_RWLIST_REMOVE_HEAD(&logchannels, list)))
+	}
+	while ((chan = AST_RWLIST_REMOVE_HEAD(&logchannels, list))) {
 		ast_free(chan);
+	}
 	global_logmask = 0;
-	if (!locked)
+	if (!locked) {
 		AST_RWLIST_UNLOCK(&logchannels);
-	
+	}
+
 	errno = 0;
 	/* close syslog */
 	closelog();
-	
+
 	/* If no config file, we're fine, set default options. */
 	if (!cfg) {
-		if (errno)
+		if (errno) {
 			fprintf(stderr, "Unable to open logger.conf: %s; default settings will be used.\n", strerror(errno));
-		else
+		} else {
 			fprintf(stderr, "Errors detected in logger.conf: see above; default settings will be used.\n");
-		if (!(chan = ast_calloc(1, sizeof(*chan))))
+		}
+		if (!(chan = ast_calloc(1, sizeof(*chan)))) {
 			return;
+		}
 		chan->type = LOGTYPE_CONSOLE;
 		chan->logmask = __LOG_WARNING | __LOG_NOTICE | __LOG_ERROR;
-		if (!locked)
+		if (!locked) {
 			AST_RWLIST_WRLOCK(&logchannels);
+		}
 		AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
 		global_logmask |= chan->logmask;
-		if (!locked)
+		if (!locked) {
 			AST_RWLIST_UNLOCK(&logchannels);
-		return;
-	}
-	
+		}
+		return;
+	}
+
 	if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
 		if (ast_true(s)) {
 			if (gethostname(hostname, sizeof(hostname) - 1)) {
@@ -340,21 +353,28 @@
 		ast_copy_string(dateformat, s, sizeof(dateformat));
 	else
 		ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
-	if ((s = ast_variable_retrieve(cfg, "general", "queue_log")))
+	if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
 		logfiles.queue_log = ast_true(s);
-	if ((s = ast_variable_retrieve(cfg, "general", "queue_log_name")))
+	}
+	if ((s = ast_variable_retrieve(cfg, "general", "queue_log_to_file"))) {
+		logfiles.queue_log_to_file = ast_true(s);
+	}
+	if ((s = ast_variable_retrieve(cfg, "general", "queue_log_name"))) {
 		ast_copy_string(queue_log_name, s, sizeof(queue_log_name));
-	if ((s = ast_variable_retrieve(cfg, "general", "exec_after_rotate")))
+	}
+	if ((s = ast_variable_retrieve(cfg, "general", "exec_after_rotate"))) {
 		ast_copy_string(exec_after_rotate, s, sizeof(exec_after_rotate));
+	}
 	if ((s = ast_variable_retrieve(cfg, "general", "rotatestrategy"))) {
-		if (strcasecmp(s, "timestamp") == 0)
+		if (strcasecmp(s, "timestamp") == 0) {
 			rotatestrategy = TIMESTAMP;
-		else if (strcasecmp(s, "rotate") == 0)
+		} else if (strcasecmp(s, "rotate") == 0) {
 			rotatestrategy = ROTATE;
-		else if (strcasecmp(s, "sequential") == 0)
+		} else if (strcasecmp(s, "sequential") == 0) {
 			rotatestrategy = SEQUENTIAL;
-		else
+		} else {
 			fprintf(stderr, "Unknown rotatestrategy: %s\n", s);
+		}
 	} else {
 		if ((s = ast_variable_retrieve(cfg, "general", "rotatetimestamp"))) {
 			rotatestrategy = ast_true(s) ? TIMESTAMP : SEQUENTIAL;
@@ -362,17 +382,27 @@
 		}
 	}
 
-	if (!locked)
+	if (!locked) {
 		AST_RWLIST_WRLOCK(&logchannels);
+	}
 	var = ast_variable_browse(cfg, "logfiles");
 	for (; var; var = var->next) {
-		if (!(chan = make_logchannel(var->name, var->value, var->lineno)))
+		if (!(chan = make_logchannel(var->name, var->value, var->lineno))) {
 			continue;
+		}
 		AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
 		global_logmask |= chan->logmask;
 	}
-	if (!locked)
+	if (qlog) {
+		char tmp[4096];
+		fclose(qlog);
+		snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
+		qlog = fopen(tmp, "a");
+	}
+
+	if (!locked) {
 		AST_RWLIST_UNLOCK(&logchannels);
+	}
 
 	ast_config_destroy(cfg);
 }
@@ -429,29 +459,69 @@
 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
 {
 	va_list ap;
+	struct timeval tv;
+	struct ast_tm tm;
 	char qlog_msg[8192];
 	int qlog_len;
-	char time_str[16];
+	char time_str[30];
+
+	if (!queuelog_init) {
+		queuelog_init = 1;
+		logger_queue_init();
+	}
 
 	if (ast_check_realtime("queue_log")) {
+		tv = ast_tvnow();
+		ast_localtime(&tv, &tm, NULL);
+		ast_strftime(time_str, sizeof(time_str), "%F %T.%6q", &tm);
 		va_start(ap, fmt);
 		vsnprintf(qlog_msg, sizeof(qlog_msg), fmt, ap);
 		va_end(ap);
-		snprintf(time_str, sizeof(time_str), "%ld", (long)time(NULL));
-		ast_store_realtime("queue_log", "time", time_str, 
-						"callid", callid, 
-						"queuename", queuename, 
-						"agent", agent, 
-						"event", event,
-						"data", qlog_msg,
-						SENTINEL);
-	} else {
-		if (qlog) {
-			va_start(ap, fmt);
-			qlog_len = snprintf(qlog_msg, sizeof(qlog_msg), "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
-			vsnprintf(qlog_msg + qlog_len, sizeof(qlog_msg) - qlog_len, fmt, ap);
-			va_end(ap);
-		}
+		if (logfiles.queue_adaptive_realtime) {
+			AST_DECLARE_APP_ARGS(args,
+				AST_APP_ARG(data)[5];
+			);
+			AST_NONSTANDARD_APP_ARGS(args, qlog_msg, '|');
+			/* Ensure fields are large enough to receive data */
+			ast_realtime_require_field("queue_log", "data1", RQ_CHAR, strlen(S_OR(args.data[0], "")),
+				"data2", RQ_CHAR, strlen(S_OR(args.data[1], "")),
+				"data3", RQ_CHAR, strlen(S_OR(args.data[2], "")),
+				"data4", RQ_CHAR, strlen(S_OR(args.data[3], "")),
+				"data5", RQ_CHAR, strlen(S_OR(args.data[4], "")),
+				SENTINEL);
+
+			/* Store the log */
+			ast_store_realtime("queue_log", "time", time_str,
+				"callid", callid,
+				"queuename", queuename,
+				"agent", agent,
+				"event", event,
+				"data1", S_OR(args.data[0], ""),
+				"data2", S_OR(args.data[1], ""),
+				"data3", S_OR(args.data[2], ""),
+				"data4", S_OR(args.data[3], ""),
+				"data5", S_OR(args.data[4], ""),
+				SENTINEL);
+		} else {
+			ast_store_realtime("queue_log", "time", time_str,
+				"callid", callid,
+				"queuename", queuename,
+				"agent", agent,
+				"event", event,
+				"data", qlog_msg,
+				SENTINEL);
+		}
+
+		if (!logfiles.queue_log_to_file) {
+			return;
+		}
+	}
+
+	if (qlog) {
+		va_start(ap, fmt);
+		qlog_len = snprintf(qlog_msg, sizeof(qlog_msg), "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
+		vsnprintf(qlog_msg + qlog_len, sizeof(qlog_msg) - qlog_len, fmt, ap);
+		va_end(ap);
 		AST_RWLIST_RDLOCK(&logchannels);
 		if (qlog) {
 			fprintf(qlog, "%s\n", qlog_msg);
@@ -481,6 +551,8 @@
 		if (rename(filename, new)) {
 			fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
 			res = -1;
+		} else {
+			filename = new;
 		}
 		break;
 	case TIMESTAMP:
@@ -488,6 +560,8 @@
 		if (rename(filename, new)) {
 			fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
 			res = -1;
+		} else {
+			filename = new;
 		}
 		break;
 	case ROTATE:
@@ -553,25 +627,25 @@
 	int queue_rotate = rotate;
 	struct logchannel *f;
 	int res = 0;
-	struct stat st;
 
 	AST_RWLIST_WRLOCK(&logchannels);
 
 	if (qlog) {
 		if (rotate < 0) {
 			/* Check filesize - this one typically doesn't need an auto-rotate */
-			snprintf(old, sizeof(old), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
-			if (stat(old, &st) != 0 || st.st_size > 0x40000000) { /* Arbitrarily, 1 GB */
+			if (ftello(qlog) > 0x40000000) { /* Arbitrarily, 1 GB */
 				fclose(qlog);
 				qlog = NULL;
-			} else
+			} else {
 				queue_rotate = 0;
+			}
 		} else {
 			fclose(qlog);
 			qlog = NULL;
 		}
-	} else 
+	} else {
 		queue_rotate = 0;
+	}
 
 	ast_mkdir(ast_config_AST_LOG_DIR, 0777);
 
@@ -581,10 +655,16 @@
 			manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
 		}
 		if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
+			int rotate_this = 0;
+			if (ftello(f->fileptr) > 0x40000000) { /* Arbitrarily, 1 GB */
+				/* Be more proactive about rotating massive log files */
+				rotate_this = 1;
+			}
 			fclose(f->fileptr);	/* Close file */
 			f->fileptr = NULL;
-			if (rotate)
+			if (rotate || rotate_this) {
 				rotate_file(f->filename);
+			}
 		}
 	}
 
@@ -593,20 +673,42 @@
 	init_logger_chain(1 /* locked */);
 
 	if (logfiles.queue_log) {
-		snprintf(old, sizeof(old), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
-		if (queue_rotate)
-			rotate_file(old);
-
-		qlog = fopen(old, "a");
-		if (qlog) {
-			AST_RWLIST_UNLOCK(&logchannels);
-			ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
-			AST_RWLIST_WRLOCK(&logchannels);
-			ast_verb(1, "Asterisk Queue Logger restarted\n");
-		} else {
-			ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
-			res = -1;
-		}
+		do {
+			ast_unload_realtime("queue_log");
+			if (ast_check_realtime("queue_log")) {
+				if (!ast_realtime_require_field("queue_log",
+						"time", RQ_DATETIME, 26, "data1", RQ_CHAR, 20,
+						"data2", RQ_CHAR, 20, "data3", RQ_CHAR, 20,
+						"data4", RQ_CHAR, 20, "data5", RQ_CHAR, 20, SENTINEL)) {
+					logfiles.queue_adaptive_realtime = 1;
+				} else {
+					logfiles.queue_adaptive_realtime = 0;
+				}
+
+				if (!logfiles.queue_log_to_file) {
+					/* Skip the following section */
+					break;
+				}
+			}
+
+			fclose(qlog);
+			qlog = NULL;
+			snprintf(old, sizeof(old), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
+			if (queue_rotate) {
+				rotate_file(old);
+			}
+
+			qlog = fopen(old, "a");
+			if (qlog) {
+				AST_RWLIST_UNLOCK(&logchannels);
+				ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
+				AST_RWLIST_WRLOCK(&logchannels);
+				ast_verb(1, "Asterisk Queue Logger restarted\n");
+			} else {
+				ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
+				res = -1;
+			}
+		} while (0);
 	}
 
 	AST_RWLIST_UNLOCK(&logchannels);
@@ -927,11 +1029,26 @@
 	return NULL;
 }
 
+static void logger_queue_init(void)
+{
+	/* Preloaded modules are up. */
+	ast_unload_realtime("queue_log");
+	if (logfiles.queue_log && ast_check_realtime("queue_log")) {
+		if (!ast_realtime_require_field("queue_log",
+				"time", RQ_DATETIME, 26, "data1", RQ_CHAR, 20,
+				"data2", RQ_CHAR, 20, "data3", RQ_CHAR, 20,
+				"data4", RQ_CHAR, 20, "data5", RQ_CHAR, 20, SENTINEL)) {
+			logfiles.queue_adaptive_realtime = 1;
+		} else {
+			logfiles.queue_adaptive_realtime = 0;
+		}
+	}
+
+	ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
+}
+
 int init_logger(void)
 {
-	char tmp[256];
-	int res = 0;
-
 	/* auto rotate if sig SIGXFSZ comes a-knockin */
 	sigaction(SIGXFSZ, &handle_SIGXFSZ, NULL);
 
@@ -946,16 +1063,11 @@
 	ast_cli_register_multiple(cli_logger, ARRAY_LEN(cli_logger));
 
 	ast_mkdir(ast_config_AST_LOG_DIR, 0777);
-  
+
 	/* create log channels */
 	init_logger_chain(0 /* locked */);
 
-	if (logfiles.queue_log) {
-		snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
-		qlog = fopen(tmp, "a");
-		ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
-	}
-	return res;
+	return 0;
 }
 
 void close_logger(void)

Modified: trunk/res/res_config_pgsql.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_config_pgsql.c?view=diff&rev=278307&r1=278306&r2=278307
==============================================================================
--- trunk/res/res_config_pgsql.c (original)
+++ trunk/res/res_config_pgsql.c Tue Jul 20 18:23:25 2010
@@ -1182,6 +1182,9 @@
 				} else if (strncmp(column->type, "float", 5) == 0 && !ast_rq_is_int(type) && type != RQ_FLOAT) {
 					ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
 					res = -1;
+				} else if (strncmp(column->type, "timestamp", 9) == 0 && type != RQ_DATETIME) {
+					ast_log(LOG_WARNING, "Column %s cannot be a %s\n", column->name, column->type);
+					res = -1;
 				} else { /* There are other types that no module implements yet */
 					ast_log(LOG_WARNING, "Possibly unsupported column type '%s' on column '%s'\n", column->type, column->name);
 					res = -1;




More information about the svn-commits mailing list