One feature of FreeSWITCH's mod_xml_cdr is that it can use HTTP POST actions to send CDR data to a web server, which in turn can process them, and perhaps put them into a database. This mechanism has several advantages:
f Modern web servers can handle enormous amounts of traffic f Multiple FreeSWITCH servers can post to a single CDR Server f Multiple web servers can be set up to allow failover and redundancy
It will automatically retry in the event of a failure, on the same web server or on another web server. Eventually, if all the retries on all the web servers fail, it will write to the disk so that the record can be processed later.
The recipe presented here will focus on the steps needed to get a web server set up to process incoming POST requests with XML CDR data.
Getting ready
You will need an operational web server that you control. Most Linux/Unix and Windows systems can get an Apache web server installed. Detailed instructions on configuring a web server are beyond the scope of this book, but such instructions are available in numerous books and on the Internet. This recipe will assume a clean installation of the Apache web server, but the principles apply to other servers as well, such as Lighttpd and Nginx. For this example, we will assume that the Apache server is on the same machine as your FreeSWITCH installation.
How to do it...
Enable mod_xml_cdr on your server (refer to the Using XML CDRs recipe earlier in this chapter). Next, follow these steps:
1. Open conf/autoload_configs/xml_cdr.conf.xml and locate this line:
<!-- <param name="url"
value="http://localhost/cdr_curl/post.php"/> -->
2. Change it to the following:
<param name="url" value="http://localhost/cgi-bin/cdr.pl"/>
3. Save the file and exit.
4. In your system's cgi-bin directory, create a new file named cdr.pl (the cgi-bin directory is usually at /usr/lib/cgi-bin, but it may be different on older systems). Add these lines to the file:
#!/usr/bin/perl use strict; use warnings; use CGI; $|++; my $q = CGI->new; my $raw_cdr = $q->param('cdr'); open (FILEOUT,'>','/tmp/cdr.txt'); print FILEOUT $raw_cdr;
close(FILEOUT); print $q->header();
5. Save the file and exit.
6. Make the file executable with this command:
7. Log in to fs_cli and issue the reloadxml command. Also, use "reload mod_ xml_cdr.".
8. Make a test call. You should see the XML CDR contents in the /tmp/cdr.txt file.
How it works...
This is a simple Perl-based CGI script. All it does is pull the cdr parameter out of the POST data that is submitted by mod_xml_curl. Once it has this value (in the $raw_cdr variable) it dumps the CDR into a temporary file named /tmp/cdr.txt.
While this example is not particularly useful for production, it demonstrates the minimal steps required to get the POSTed CDR data into the system. If you are more comfortable with another scripting language, such as PHP, Python, or Ruby, you may just as easily process the CDRs with that language. Here is a simple version in PHP:
$raw_cdr = $_POST['cdr'];
$writefile = fopen('/tmp/dump.txt',"w"); fwrite($writefile, $raw_cdr);
fclose($writefile);
Once you have the data in your program, you can choose how to process it.
There's more...
A common practice with handling XML CDR data with a CGI script (or Fast CGI, or some other appropriate method to handle an HTTP POST request) is to process the data and then put it into a database. This section describes how to insert the CDR into the same database table that we created in the previous recipe, Inserting CDRs into a backend database.
Assume that you have a database named cdr, with a table also named cdr. You can use this modified cdr.pl script to insert the records right into the database.
You will need to use the cpan tool to install the DBI module and the DBD driver for your database. Common ones are DBD::mysql
and DBD::PgPP. This example assumes DBD::PgPP, the Postgres "pure Perl" database driver.
The modified cdr.pl script is as follows:
#!/usr/bin/perl use strict; use warnings; use CGI;
use DBI;
use Data::Dump qw(dump); $|++;
my $q = CGI->new;
my $raw_cdr = $q->param('cdr');
my @all_fields = qw(caller_id_name caller_id_number
destination_number context start_stamp answer_stamp end_stamp duration billsec hangup_cause uuid bleg_uuid
accountcode read_codec write_codec); my @fields;
my @values;
foreach my $field (@all_fields) {
next unless $raw_cdr =~ m/$field>(.*?)</; push @fields, $field;
push @values, "'" . urldecode($1) . "'"; }
my $cdr_line;
my $query = sprintf(
"INSERT INTO %s (%s) VALUES (%s);",
'cdr', join(',', @fields), join(',', @values) ); my $db = DBI->connect('DBI:PgPP:dbname=cdr;host=localhost', 'postgres', 'postgres'); $db->do($query); print $q->header(); sub urldecode { my $url = shift; $url =~ s/%([a-fA-F0-9]{2,2})/chr(hex($1))/eg; return $url; }
This script is a simple example of inserting records into the database. The @all_fields array is a list of every field in the cdr table. We cycle through this list looking for the
corresponding values. If we find one, we use urldecode and then add the field name to the @fields list, while its value goes into @values. From there, we create a query string using the @fields and @values arrays, and then insert them into the database.
See also
f Refer to the Using XML CDRs and Inserting CDRs into a backend database recipes covered earlier in this chapter