Patch for mysql logging of queue_log

Hello all,

I know this is a little ugly coded, but it works and seems to be ok (at least for me).

It is a patch for logger.c that duplicates the messages in queue_log into a mysql table.

It would be great if somebody with more knowledge of the asterisk coding standards would integrate this into the code, because it is really useful when you want to have a call center with statistics for agents in realtime.

To use it, you have to add in logger.conf a section like:

[mysql]
hostname=localhost
dbname=asterisk
table=queue_log
password=*****
user=asterisk
port=3306
sock=/var/lib/mysql/mysql.sock

The patch is:

[code]
diff -u -r orig/asterisk-1.2.3/Makefile asterisk-1.2.3/Makefile
— orig/asterisk-1.2.3/Makefile 2005-12-05 08:47:51.000000000 +0200
+++ asterisk-1.2.3/Makefile 2006-01-26 18:19:45.000000000 +0200
@@ -217,7 +217,7 @@
M4=/usr/local/bin/m4
endif

-INCLUDE+=-Iinclude -I…/include
+INCLUDE+=-Iinclude -I…/include -I/usr/include/mysql
ASTCFLAGS+=-pipe -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE #-DMAKE_VALGRIND_HAPPY
ASTCFLAGS+=$(OPTIMIZE)
ASTOBJ=-o asterisk
@@ -356,7 +356,7 @@
endif

ifeq ($(OSARCH),Linux)

  • LIBS+=-ldl -lpthread -lncurses -lm -lresolv #-lnjamd
  • LIBS+=-ldl -lpthread -lncurses -lm -lresolv -L/usr/lib/mysql -lmysqlclient #-lnjamd
    else
    LIBS+=-lncurses -lm
    endif
    diff -u -r orig/asterisk-1.2.3/logger.c asterisk-1.2.3/logger.c
    — orig/asterisk-1.2.3/logger.c 2006-01-17 18:55:30.000000000 +0200
    +++ asterisk-1.2.3/logger.c 2006-01-27 10:53:35.000000000 +0200
    @@ -32,6 +32,7 @@
    #include <stdlib.h>
    #include <errno.h>
    #include <sys/stat.h>
    +#include <mysql.h>

#define SYSLOG_NAMES /* so we can map syslog facilities names to their numeric values,
from <syslog.h> which is included by logger.h */
@@ -78,6 +79,17 @@

static char dateformat[256] = “%b %e %T”; /* Original Asterisk Format */

+static MYSQL logdb;
+static char my_hostname[100];
+static char my_dbname[100];
+static char my_table[100];
+static char my_password[100];
+static char my_user[100];
+static unsigned int my_port;
+static char my_sock[100];
+static int use_mysql;
+
+
AST_MUTEX_DEFINE_STATIC(msglist_lock);
AST_MUTEX_DEFINE_STATIC(loglock);
static int filesize_reload_needed = 0;
@@ -335,6 +347,37 @@
logfiles.event_log = ast_true(s);
}

  •   if ((s = ast_variable_retrieve(cfg, "mysql", "hostname"))) {
    
  •           ast_copy_string(my_hostname, s, sizeof(my_hostname));
    
  •   }
    
  •   if ((s = ast_variable_retrieve(cfg, "mysql", "dbname"))) {
    
  •           ast_copy_string(my_dbname, s, sizeof(my_dbname));
    
  •   }
    
  •   if ((s = ast_variable_retrieve(cfg, "mysql", "table"))) {
    
  •           ast_copy_string(my_table, s, sizeof(my_table));
    
  •   }
    
  •   if ((s = ast_variable_retrieve(cfg, "mysql", "password"))) {
    
  •           ast_copy_string(my_password, s, sizeof(my_password));
    
  •   }
    
  •   if ((s = ast_variable_retrieve(cfg, "mysql", "user"))) {
    
  •           ast_copy_string(my_user, s, sizeof(my_user));
    
  •   }
    
  •   if ((s = ast_variable_retrieve(cfg, "mysql", "port"))) {
    
  •            if (sscanf(s, "%d", &my_port) < 1) {
    
  •                    my_port = 0;
    
  •            }
    
  •   }
    
  •   if ((s = ast_variable_retrieve(cfg, "mysql", "sock"))) {
    
  •           ast_copy_string(my_sock, s, sizeof(my_sock));
    
  •   }
    
  •   if(!mysql_real_connect(&logdb, my_hostname, my_user, my_password, my_dbname, my_port, my_sock, 0)){
    
  •           ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", my_dbname, my_hostname);
    
  •           use_mysql = 0;
    
  •   } else {
    
  •           use_mysql = 1;
    
  •   }
    
  •   var = ast_variable_browse(cfg, "logfiles");
      while(var) {
              chan = make_logchannel(var->name, var->value, var->lineno);
    

@@ -362,6 +405,49 @@
fprintf(qlog, “%ld|%s|%s|%s|%s|”, (long)time(NULL), callid, queuename, agent, event);
vfprintf(qlog, fmt, ap);
fprintf(qlog, “\n”);
+

  •           if(use_mysql == 1) {
    
  •                   char *myquery           = malloc(500);
    
  •                   char *myquery_ap        = malloc(100);
    
  •                   char *myfmt             = malloc(strlen(fmt)*3+1>8?strlen(fmt)*3+1:9);
    
  •                   int x,y;
    
  •                   int fmt_count = 0;
    
  •                   int len = 500;
    
  •                   if(snprintf(myquery, 500, "insert into %s(time,callid,queuename,agent,event,arg1,arg2,arg3) values(from_unixtime(%ld),'%s','%s','%s','%s',", my_table, (long)time(NULL), callid, queuename, agent, event)<500) {
    
  •                           len = 500 - strlen(myquery);
    
  •                           myfmt[0] = '\'';
    
  •                           for(x=0,y=0; x<strlen(fmt); x++) {
    
  •                                   if(fmt[x] == '|') {
    
  •                                           myfmt[++y] = '\'';
    
  •                                           myfmt[++y] = ',';
    
  •                                           myfmt[++y] = '\'';
    
  •                                           fmt_count ++;
    
  •                                   } else {
    
  •                                           myfmt[++y] = fmt[x];
    
  •                                   }
    
  •                           }
    
  •                           for(;fmt_count<2; fmt_count++) {
    
  •                                   myfmt[++y] = '\'';
    
  •                                   myfmt[++y] = ',';
    
  •                                   myfmt[++y] = '\'';
    
  •                           }
    
  •                           myfmt[++y] = '\'';
    
  •                           myfmt[++y] = 0;
    
  •                           if(vsnprintf(myquery_ap, 100, myfmt, ap)<100) {
    
  •                                   strncat(myquery, myquery_ap, len-1);
    
  •                                   len = 500 - strlen(myquery);
    
  •                                   strncat(myquery, ")", len-1);
    
  •                                   if(mysql_real_query(&logdb, myquery, strlen(myquery)+1)){
    
  •                                           printf(mysql_error(&logdb));
    
  •                                   }
    
  •                           }
    
  •                   }
    
  •                   free(myfmt);
    
  •                   free(myquery_ap);
    
  •                   free(myquery);
    
  •           }
    
  •           va_end(ap);
              fflush(qlog);
      }
    

[/code][/code]

nice job! i can’t vouch for coding or anything like that (me dumb) but this feature has been NEEDED for a while! anyone who runs a call center or uses call queues needs to be able to access this data in a user-friendly format.

you might submit a FEATURE bug over at bugs.digium.com - i’m guessing this would be added to the source pretty quick, as lots of users are looking for this functionality!

i will probably test our patch box and try this out - then i can finally get around to recoding our queue-stats app!

thanks!

Wes

I have forgot a small, but essential detail: the table structure as I have designed it for my code:

CREATE TABLE `queue_log` (
  `time` datetime NOT NULL default '0000-00-00 00:00:00',
  `callid` varchar(20) NOT NULL default '',
  `queuename` varchar(20) NOT NULL default '',
  `agent` varchar(20) NOT NULL default '',
  `event` varchar(20) NOT NULL default '',
  `arg1` varchar(100) NOT NULL default '',
  `arg2` varchar(100) NOT NULL default '',
  `arg3` varchar(100) NOT NULL default ''
)

As for submiting a FEATURE bug… I am using asterisk for only three days and I have to admit that I know very little about the coding standards of this project, about the ways of integrating patches to the code, and most important, I have no idea about the future plans of the mantainer of logger.c.

So if anybody is willing to take this from here and do whatever is needed to integrate it to the main tree, I will be very happy. Unfortunatelly I don’t have the time to do it myself now.

By the way, a small explanation of the code in its current status.

First, I have added the section that reads the parameters from the logger.conf file, and connects to the database. If it succeeds, it will use mysql. If not, mysql will not be used.

Regarding the change itself in the ast_queue_log function, the alghoritm is very easy:

  • if mysql should be used:
  1. it puts the static arguments of the ast_queue_log function into myquery string.
  2. it converts the format fmt into a myfmt suitable for the sql query
  3. it prints the remaining (variable list) arguments using myfmt into myquery_ap
  4. it concatenates myquery with myquery_ap
  5. it executes the query

The ugly thing here is the conversion from fmt to myfmt. A better/nicer way to do it would be to call imediatelly after ast_queue_log another new function, ast_mysql_queue_log, passing the same arguments, but with the fmt argument changed accordingly (by hand). But as this would require changes to app_queue.c in many places, I have preffered to alter only one function instead of this, and generate automatically myfmt from fmt (instead of harcoding it the way fmt is already hardcoded).

I hope I was reasonably clear in my explanation.

Will this work for Asterisk 1.2.7.1?

Not for me. I tried to patch the logger.c with that patch , but not sucessfully … i understand why but i was wondering if vixtor could help us in this version(Asterisk 1.2.7.1). I already send a private msg to him.

Anyway and in side of the same subject i found a post of Whoiswes (http://forums.digium.com/viewtopic.php?t=6326&highlight=transfer+queue)
telling us that when call is answered in a queue and we transfer that call the queue_log dont show the talking time as he show in the example, but take a look at the post

ex:[color=indigo]1146749806|1146749743.203897|AML_COLLECTIONS|SIP/2040-4633|TRANSFER|2008|from-inside[/color]

Hello,

Can you please be more specific about what is not working anymore? I have patched it (and it worked), and then built it. I cannot install&run it on the production system, and I don’t have enough time to install another machine now for testing.

You say that you understand why it is not working anymore. Please give me as much information as you can, so I can adapt the patch.

Btw, I am still running 1.2.6 with my patch, and it works fine. What has changed so much between 1.2.6 and 1.2.7.1?

actually from 1.2.5 to 1.2.7.1 nothing have changed …
But from 1.2.3 to 1.2.7.1 there was some big changes …
And I tried to apply the patch on logger.c (on 1.2.7.1 : patch -p0 < /loggerc.patch ) and the output logger.c.rej was:

[code]+ char *myquery = malloc(500);

  •                    char *myquery_ap        = malloc(100);
    
  •                    if(snprintf(myquery, 500, "insert into %s(time,callid,queuename,agent,event,arg1,arg2,arg3) values(from_unixtime(%ld),'%s','%s','%s','%s',", my_table, (long)time(NULL), callid, queuename, agent, event)<500) {
    
  •                            len = 500 - strlen(myquery);
    
  •                            if(vsnprintf(myquery_ap, 100, myfmt, ap)<100) {
    
  •                                    strncat(myquery, myquery_ap, len-1);
    
  •                                    len = 500 - strlen(myquery);
    
  •                                    strncat(myquery, ")", len-1);
    
  •                                    if(mysql_real_query(&logdb, myquery, strlen(myquery)+1)){
    
  •                    free(myquery_ap);
    
  •                    free(myquery); [/code]
    

Please tell me if you have any idea …
And if you can please leave an opinion about the 2 problem on the queues (when there is a transfer call from a queue number, look at my post).

Sorry, I have first thought about finding the problem, but I have posted twice the same patch, so I deleted my last answer.

I have looked again, and the patch published here creates no rejects on 1.2.7.1. This is what I get:

asterisk:~/asterisk-1.2.7.1 # cat ../asterisk.diff | patch -p1
patching file Makefile
Hunk #1 succeeded at 220 with fuzz 1 (offset 3 lines).
Hunk #2 succeeded at 359 (offset 3 lines).
patching file logger.c
Hunk #3 succeeded at 357 (offset 10 lines).
Hunk #4 succeeded at 412 (offset 7 lines).

Ok maybe i’m very dumb , :open_mouth: .
If is possible can you tell me step by step how do you patch the logger.c ?
I mean the cmd you do. I called my file with your code for patch “patchloggerc.patch” so here is an other try i made (i made a copy to an other folder to don’t destroy the orginal logger.c, and i tried to patch it ):

[code]
[root@atenas01 logger]# cat patchloggerc.patch | patch -p1
can’t find file to patch at input line 4
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:

|diff -u -r orig/asterisk-1.2.3/Makefile asterisk-1.2.3/Makefile
|— orig/asterisk-1.2.3/Makefile 2005-12-05 08:47:51.000000000 +0200

+++ asterisk-1.2.3/Makefile 2006-01-26 18:19:45.000000000 +0200

File to patch: logger.c
patching file logger.c
Hunk #1 FAILED at 217.
Hunk #2 FAILED at 356.
2 out of 2 hunks FAILED – saving rejects to file logger.c.rej
patching file logger.c
Hunk #1 succeeded at 32 with fuzz 1.
Hunk #2 succeeded at 79 with fuzz 2.
Hunk #3 FAILED at 347.
patch unexpectedly ends in middle of line
Hunk #4 FAILED at 405.
2 out of 4 hunks FAILED – saving rejects to file logger.c.rej [/code]

What I did was

wget http://ftp.digium.com/pub/asterisk/releases/asterisk-1.2.7.1.tar.gz
tar zxvf asterisk-1.2.7.1.tar.gz
cat ../asterisk.diff | patch -p1

In which asterisk.diff contains all the code in my initial post (not just for logger.c).

Now, on the other side, I am thinking that maybe there are some problems with tab/space formatting on this web forum. Can you try to download the diff from: http://www.americantrains.ro/asterisk.diff ?

Exactly :smile:… It’s a copy paste problem.
Ok the patch wrote just fine.
Can you give a word about the other post (on the version 1.2.7.1) when someone make a call to a queue and the queue transfer it to anywhrere the log file doesn’t tell the time that call took.

Just if you can or the subject is important for you to. Otherwise i will continue tring it on the other post …

Once more thank you for the help on teh copy / paste :stuck_out_tongue:

(i had some erros but it was because i was trying to patch it from an other folder with just the logger.c) {LAMER I’M }…

Unfortunatelly I didn’t had time to investigate the other problem until now (it is useful when working correctly, but not that high on my priorities list). Anyway, it is not related to this patch, so maybe it would be better to continue discussing it on the other post.

How about in 1.2.9 from 1.2.7.1? Did it change?

the patches i wrote for 1.2.7.1 would not work in 1.2.8 for app_queue, so they won’t work for 1.2.9 either, i would bet.

whoiswes, I don’t know about your patches, but my patch (that we are talking about here :smile: ) works fine with 1.2.9.1. I am using it right now.

For me too. The patch wrote by vixtor and patched by me ( :smiley: ) is working good with 1.2.9.1.

you guys were patching logger.c, i was patching app_queue.c…i know that there have been quite a few changes to app_queue, which is probably why my patches needed to be modified for the newer versions…

Well, I know this is a REALLY old thread, but I found myself in desperate need of this feature, so I manually applied this patch to 1.2.14 . It compiles fine, and but I have yet to test it in production. Preliminary results show that it appears to be working, in the sense that it logs the restarts to database. I will be testing this more over the next couple of days, and I expect it to be on a production server right away. I’ll post the results. This needs to be a feature in Asterisk. This works, but it is a bit of a hack(no offense to the author) it just isn’t appropriate to be logging from the queue to logger. It needs to be structure more like the CDR facility. If Asterisk is to be used in large installations, this is critical information. I wish I had the time to fix it up right. I’m sure a lot of users feel the same way. It doesn’t appear to have changed in 1.4… Oh well.

diff -urNp asterisk-1.2.13/logger.c asterisk-queue-log-mysql/logger.c
--- asterisk-1.2.13/logger.c	2006-09-06 20:14:14.000000000 -0600
+++ asterisk-queue-log-mysql/logger.c	2006-12-03 22:21:39.000000000 -0700
@@ -18,7 +18,7 @@
 
 /*! \file
  * \brief Asterisk Logger
- * 
+ *
  * Logging routines
  *
  */
@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <sys/stat.h>
+#include <mysql.h>
 
 #define SYSLOG_NAMES /* so we can map syslog facilities names to their numeric values,
 		        from <syslog.h> which is included by logger.h */
@@ -78,6 +79,18 @@ static int syslog_level_map[] = {
 
 static char dateformat[256] = "%b %e %T";		/* Original Asterisk Format */
 
+
+static MYSQL logdb;
+static char my_hostname[100];
+static char my_dbname[100];
+static char my_table[100];
+static char my_password[100];
+static char my_user[100];
+static unsigned int my_port;
+static char my_sock[100];
+static int use_mysql;
+
+
 AST_MUTEX_DEFINE_STATIC(msglist_lock);
 AST_MUTEX_DEFINE_STATIC(loglock);
 static int filesize_reload_needed = 0;
@@ -148,7 +161,7 @@ static int make_components(char *s, int 
 	while(w) {
 		while(*w && (*w < 33))
 			w++;
-		if (!strcasecmp(w, "error")) 
+		if (!strcasecmp(w, "error"))
 			res |= (1 << __LOG_ERROR);
 		else if (!strcasecmp(w, "warning"))
 			res |= (1 << __LOG_WARNING);
@@ -214,41 +227,41 @@ static struct logchannel *make_logchanne
 		}
 #else
 		chan->facility = -1;
-		if (!strcasecmp(facility, "kern")) 
+		if (!strcasecmp(facility, "kern"))
 			chan->facility = LOG_KERN;
-		else if (!strcasecmp(facility, "USER")) 
+		else if (!strcasecmp(facility, "USER"))
 			chan->facility = LOG_USER;
-		else if (!strcasecmp(facility, "MAIL")) 
+		else if (!strcasecmp(facility, "MAIL"))
 			chan->facility = LOG_MAIL;
-		else if (!strcasecmp(facility, "DAEMON")) 
+		else if (!strcasecmp(facility, "DAEMON"))
 			chan->facility = LOG_DAEMON;
-		else if (!strcasecmp(facility, "AUTH")) 
+		else if (!strcasecmp(facility, "AUTH"))
 			chan->facility = LOG_AUTH;
-		else if (!strcasecmp(facility, "SYSLOG")) 
+		else if (!strcasecmp(facility, "SYSLOG"))
 			chan->facility = LOG_SYSLOG;
-		else if (!strcasecmp(facility, "LPR")) 
+		else if (!strcasecmp(facility, "LPR"))
 			chan->facility = LOG_LPR;
-		else if (!strcasecmp(facility, "NEWS")) 
+		else if (!strcasecmp(facility, "NEWS"))
 			chan->facility = LOG_NEWS;
-		else if (!strcasecmp(facility, "UUCP")) 
+		else if (!strcasecmp(facility, "UUCP"))
 			chan->facility = LOG_UUCP;
-		else if (!strcasecmp(facility, "CRON")) 
+		else if (!strcasecmp(facility, "CRON"))
 			chan->facility = LOG_CRON;
-		else if (!strcasecmp(facility, "LOCAL0")) 
+		else if (!strcasecmp(facility, "LOCAL0"))
 			chan->facility = LOG_LOCAL0;
-		else if (!strcasecmp(facility, "LOCAL1")) 
+		else if (!strcasecmp(facility, "LOCAL1"))
 			chan->facility = LOG_LOCAL1;
-		else if (!strcasecmp(facility, "LOCAL2")) 
+		else if (!strcasecmp(facility, "LOCAL2"))
 			chan->facility = LOG_LOCAL2;
-		else if (!strcasecmp(facility, "LOCAL3")) 
+		else if (!strcasecmp(facility, "LOCAL3"))
 			chan->facility = LOG_LOCAL3;
-		else if (!strcasecmp(facility, "LOCAL4")) 
+		else if (!strcasecmp(facility, "LOCAL4"))
 			chan->facility = LOG_LOCAL4;
-		else if (!strcasecmp(facility, "LOCAL5")) 
+		else if (!strcasecmp(facility, "LOCAL5"))
 			chan->facility = LOG_LOCAL5;
-		else if (!strcasecmp(facility, "LOCAL6")) 
+		else if (!strcasecmp(facility, "LOCAL6"))
 			chan->facility = LOG_LOCAL6;
-		else if (!strcasecmp(facility, "LOCAL7")) 
+		else if (!strcasecmp(facility, "LOCAL7"))
 			chan->facility = LOG_LOCAL7;
 #endif /* Solaris */
 
@@ -263,13 +276,13 @@ static struct logchannel *make_logchanne
 		openlog("asterisk", LOG_PID, chan->facility);
 	} else {
 		if (channel[0] == '/') {
-			if(!ast_strlen_zero(hostname)) { 
+			if(!ast_strlen_zero(hostname)) {
 				snprintf(chan->filename, sizeof(chan->filename) - 1,"%s.%s", channel, hostname);
 			} else {
 				ast_copy_string(chan->filename, channel, sizeof(chan->filename));
 			}
-		}		  
-		
+		}
+
 		if(!ast_strlen_zero(hostname)) {
 			snprintf(chan->filename, sizeof(chan->filename), "%s/%s.%s",(char *)ast_config_AST_LOG_DIR, channel, hostname);
 		} else {
@@ -279,7 +292,7 @@ static struct logchannel *make_logchanne
 		if (!chan->fileptr) {
 			/* Can't log here, since we're called with a lock */
 			fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno));
-		} 
+		}
 		chan->type = LOGTYPE_FILE;
 	}
 	chan->logmask = make_components(components, lineno);
@@ -303,14 +316,14 @@ static void init_logger_chain(void)
 	}
 	logchannels = NULL;
 	ast_mutex_unlock(&loglock);
-	
+
 	global_logmask = 0;
 	errno = 0;
 	/* close syslog */
 	closelog();
-	
+
 	cfg = ast_config_load("logger.conf");
-	
+
 	/* If no config file, we're fine, set default options. */
 	if (!cfg) {
 		if (errno)
@@ -326,7 +339,7 @@ static void init_logger_chain(void)
 		global_logmask |= chan->logmask;
 		return;
 	}
-	
+
 	ast_mutex_lock(&loglock);
 	if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
 		if(ast_true(s)) {
@@ -349,6 +362,36 @@ static void init_logger_chain(void)
 		logfiles.event_log = ast_true(s);
 	}
 
+    if ((s = ast_variable_retrieve(cfg, "mysql", "hostname"))) {
+         ast_copy_string(my_hostname, s, sizeof(my_hostname));
+    }
+    if ((s = ast_variable_retrieve(cfg, "mysql", "dbname"))) {
+         ast_copy_string(my_dbname, s, sizeof(my_dbname));
+    }
+    if ((s = ast_variable_retrieve(cfg, "mysql", "table"))) {
+         ast_copy_string(my_table, s, sizeof(my_table));
+    }
+    if ((s = ast_variable_retrieve(cfg, "mysql", "password"))) {
+         ast_copy_string(my_password, s, sizeof(my_password));
+    }
+    if ((s = ast_variable_retrieve(cfg, "mysql", "user"))) {
+         ast_copy_string(my_user, s, sizeof(my_user));
+    }
+    if ((s = ast_variable_retrieve(cfg, "mysql", "port"))) {
+              if (sscanf(s, "%d", &my_port) < 1) {
+                   my_port = 0;
+              }
+    }
+    if ((s = ast_variable_retrieve(cfg, "mysql", "sock"))) {
+         ast_copy_string(my_sock, s, sizeof(my_sock));
+    }
+    if(!mysql_real_connect(&logdb, my_hostname, my_user, my_password, my_dbname, my_port, my_sock, 0)){
+         ast_log(LOG_ERROR, "Failed to connect to mysql database %s on %s.\n", my_dbname, my_hostname);
+         use_mysql = 0;
+    } else {
+         use_mysql = 1;
+    }
+
 	var = ast_variable_browse(cfg, "logfiles");
 	while(var) {
 		chan = make_logchannel(var->name, var->value, var->lineno);
@@ -372,7 +415,50 @@ void ast_queue_log(const char *queuename
 		va_start(ap, fmt);
 		fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
 		vfprintf(qlog, fmt, ap);
-		fprintf(qlog, "\n");
+        fprintf(qlog, "\n");
+
+        if(use_mysql == 1) {
+            char *myquery           = malloc(500);
+            char *myquery_ap        = malloc(100);
+            char *myfmt             = malloc(strlen(fmt)*3+1>8?strlen(fmt)*3+1:9);
+            int x,y;
+            int fmt_count = 0;
+            int len = 500;
+
+            if(snprintf(myquery, 500, "insert into %s(time,callid,queuename,agent,event,arg1,arg2,arg3) values(from_unixtime(%ld),'%s','%s','%s','%s',", my_table, (long)time(NULL), callid, queuename, agent, event)<500) {
+                len = 500 - strlen(myquery);
+                myfmt[0] = '\'';
+                for(x=0,y=0; x<strlen(fmt); x++) {
+                    if(fmt[x] == '|') {
+                        myfmt[++y] = '\'';
+                        myfmt[++y] = ',';
+                        myfmt[++y] = '\'';
+                        fmt_count ++;
+                    } else {
+                        myfmt[++y] = fmt[x];
+                    }
+                }
+                for(;fmt_count<2; fmt_count++) {
+                    myfmt[++y] = '\'';
+                    myfmt[++y] = ',';
+                    myfmt[++y] = '\'';
+                }
+                myfmt[++y] = '\'';
+                myfmt[++y] = 0;
+                if(vsnprintf(myquery_ap, 100, myfmt, ap)<100) {
+                     strncat(myquery, myquery_ap, len-1);
+                     len = 500 - strlen(myquery);
+                     strncat(myquery, ")", len-1);
+                     if(mysql_real_query(&logdb, myquery, strlen(myquery)+1)){
+                        printf(mysql_error(&logdb));
+                     }
+                 }
+             }
+             free(myfmt);
+             free(myquery_ap);
+             free(myquery);
+         }
+
 		va_end(ap);
 		fflush(qlog);
 	}
@@ -390,15 +476,15 @@ int reload_logger(int rotate)
 
 	ast_mutex_lock(&msglist_lock);	/* to avoid deadlock */
 	ast_mutex_lock(&loglock);
-	if (eventlog) 
+	if (eventlog)
 		fclose(eventlog);
-	else 
+	else
 		event_rotate = 0;
 	eventlog = NULL;
 
-	if (qlog) 
+	if (qlog)
 		fclose(qlog);
-	else 
+	else
 		queue_rotate = 0;
 	qlog = NULL;
 
@@ -415,7 +501,7 @@ int reload_logger(int rotate)
 			f->fileptr = NULL;
 			if(rotate) {
 				ast_copy_string(old, f->filename, sizeof(old));
-	
+
 				for(x=0;;x++) {
 					snprintf(new, sizeof(new), "%s.%d", f->filename, x);
 					myf = fopen((char *)new, "r");
@@ -425,7 +511,7 @@ int reload_logger(int rotate)
 						break;
 					}
 				}
-	    
+
 				/* do it */
 				if (rename(old,new))
 					fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
@@ -449,7 +535,7 @@ int reload_logger(int rotate)
 				else
 					break;
 			}
-	
+
 			/* do it */
 			if (rename(old,new))
 				ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
@@ -477,7 +563,7 @@ int reload_logger(int rotate)
 				else
 					break;
 			}
-	
+
 			/* do it */
 			if (rename(old, new))
 				ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
@@ -518,7 +604,7 @@ static int handle_logger_rotate(int fd, 
 		return RESULT_SUCCESS;
 }
 
-/*--- handle_logger_show_channels: CLI command to show logging system 
+/*--- handle_logger_show_channels: CLI command to show logging system
  	configuration */
 static int handle_logger_show_channels(int fd, int argc, char *argv[])
 {
@@ -536,19 +622,19 @@ static int handle_logger_show_channels(i
 		ast_cli(fd, FORMATL, chan->filename, chan->type==LOGTYPE_CONSOLE ? "Console" : (chan->type==LOGTYPE_SYSLOG ? "Syslog" : "File"),
 			chan->disabled ? "Disabled" : "Enabled");
 		ast_cli(fd, " - ");
-		if (chan->logmask & (1 << __LOG_DEBUG)) 
+		if (chan->logmask & (1 << __LOG_DEBUG))
 			ast_cli(fd, "Debug ");
-		if (chan->logmask & (1 << __LOG_DTMF)) 
+		if (chan->logmask & (1 << __LOG_DTMF))
 			ast_cli(fd, "DTMF ");
-		if (chan->logmask & (1 << __LOG_VERBOSE)) 
+		if (chan->logmask & (1 << __LOG_VERBOSE))
 			ast_cli(fd, "Verbose ");
-		if (chan->logmask & (1 << __LOG_WARNING)) 
+		if (chan->logmask & (1 << __LOG_WARNING))
 			ast_cli(fd, "Warning ");
-		if (chan->logmask & (1 << __LOG_NOTICE)) 
+		if (chan->logmask & (1 << __LOG_NOTICE))
 			ast_cli(fd, "Notice ");
-		if (chan->logmask & (1 << __LOG_ERROR)) 
+		if (chan->logmask & (1 << __LOG_ERROR))
 			ast_cli(fd, "Error ");
-		if (chan->logmask & (1 << __LOG_EVENT)) 
+		if (chan->logmask & (1 << __LOG_EVENT))
 			ast_cli(fd, "Event ");
 		ast_cli(fd, "\n");
 		chan = chan->next;
@@ -556,7 +642,7 @@ static int handle_logger_show_channels(i
 	ast_cli(fd, "\n");
 
 	ast_mutex_unlock(&loglock);
- 		
+
 	return RESULT_SUCCESS;
 }
 
@@ -578,22 +664,22 @@ static char logger_show_channels_help[] 
 "Usage: logger show channels\n"
 "       Show configured logger channels.\n";
 
-static struct ast_cli_entry logger_show_channels_cli = 
-	{ { "logger", "show", "channels", NULL }, 
+static struct ast_cli_entry logger_show_channels_cli =
+	{ { "logger", "show", "channels", NULL },
 	handle_logger_show_channels, "List configured log channels",
 	logger_show_channels_help };
 
-static struct ast_cli_entry reload_logger_cli = 
-	{ { "logger", "reload", NULL }, 
+static struct ast_cli_entry reload_logger_cli =
+	{ { "logger", "reload", NULL },
 	handle_logger_reload, "Reopens the log files",
 	logger_reload_help };
 
-static struct ast_cli_entry rotate_logger_cli = 
-	{ { "logger", "rotate", NULL }, 
+static struct ast_cli_entry rotate_logger_cli =
+	{ { "logger", "rotate", NULL },
 	handle_logger_rotate, "Rotates and reopens the log files",
 	logger_rotate_help };
 
-static int handle_SIGXFSZ(int sig) 
+static int handle_SIGXFSZ(int sig)
 {
 	/* Indicate need to reload */
 	filesize_reload_needed = 1;
@@ -614,7 +700,7 @@ int init_logger(void)
 	ast_cli_register(&logger_show_channels_cli);
 
 	mkdir((char *)ast_config_AST_LOG_DIR, 0755);
-  
+
 	/* create log channels */
 	init_logger_chain();
 
@@ -661,7 +747,7 @@ void close_logger(void)
 	return;
 }
 
-static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args) 
+static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args)
 {
 	char buf[BUFSIZ];
 	char *s;
@@ -699,12 +785,12 @@ void ast_log(int level, const char *file
 	char date[256];
 
 	va_list ap;
-	
+
 	if (!logchannels)
 	{
-		/* 
+		/*
 		 * we don't have the logger chain configured yet,
-		 * so just log to stdout 
+		 * so just log to stdout
 		*/
 		if (level != __LOG_VERBOSE) {
 			va_start(ap, fmt);
@@ -728,7 +814,7 @@ void ast_log(int level, const char *file
 	/* Ignore anything that never gets logged anywhere */
 	if (!(global_logmask & (1 << level)))
 		return;
-	
+
 	/* Ignore anything other than the currently debugged file if there is one */
 	if ((level == __LOG_DEBUG) && !ast_strlen_zero(debug_filename) && strcasecmp(debug_filename, file))
 		return;
@@ -773,7 +859,7 @@ void ast_log(int level, const char *file
 					term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
 					term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
 					term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
-				
+
 				ast_console_puts(buf);
 				va_start(ap, fmt);
 				vsnprintf(buf, sizeof(buf), fmt, ap);
@@ -793,7 +879,7 @@ void ast_log(int level, const char *file
 				} else
 					fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
 				manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
-				chan->disabled = 1;	
+				chan->disabled = 1;
 			} else {
 				/* No error message, continue printing */
 				va_start(ap, fmt);
@@ -827,7 +913,7 @@ void ast_verbose(const char *fmt, ...)
 	int olen;
 	struct msglist *m;
 	struct verb *v;
-	
+
 	va_list ap;
 	va_start(ap, fmt);
 
@@ -908,7 +994,7 @@ void ast_verbose(const char *fmt, ...)
 	if (len) {
 		if (!complete)
 			replacelast = 1;
-		else 
+		else
 			replacelast = len = 0;
 	}
 
@@ -929,7 +1015,7 @@ int ast_verbose_dmesg(void (*v)(const ch
 	return 0;
 }
 
-int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete)) 
+int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
 {
 	struct msglist *m;
 	struct verb *tmp;
diff -urNp asterisk-1.2.13/Makefile asterisk-queue-log-mysql/Makefile
--- asterisk-1.2.13/Makefile	2006-09-06 14:09:10.000000000 -0600
+++ asterisk-queue-log-mysql/Makefile	2006-12-03 22:10:27.000000000 -0700
@@ -225,7 +225,7 @@ ifeq ($(OSARCH),SunOS)
   INSTALL=ginstall
 endif
 
-INCLUDE+=-Iinclude -I../include
+INCLUDE+=-Iinclude -I../include -I/usr/include/mysql
 ASTCFLAGS+=-pipe  -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE #-DMAKE_VALGRIND_HAPPY
 ASTCFLAGS+=$(OPTIMIZE)
 ASTOBJ=-o asterisk
@@ -367,7 +367,7 @@ ifeq ($(wildcard $(CROSS_COMPILE_TARGET)
 endif
 
 ifeq ($(OSARCH),Linux)
-  LIBS+=-ldl -lpthread -lncurses -lm -lresolv  #-lnjamd
+  LIBS+=-ldl -lpthread -lncurses -lm -lresolv  -L/usr/lib/mysql -lmysqlclient #-lnjamd
 else
   ifeq ($(OSARCH),SunOS)
     LIBS+=-lm -lcurses