Skip to content
This repository has been archived by the owner on May 6, 2020. It is now read-only.

Reporting and cdr

mpermar edited this page Sep 1, 2011 · 2 revisions

Rayo lets you configure how you want to store your CDRs. Basically there is four different storage options:

  • Filesystem
  • JMS destinations
  • XMPP PubSub nodes
  • AMQP destinations

Additionally you can write and plug very easily your own CDR storage implementations as you will see in the documentation below.

The CDR

This is a sample CDR. Note that Rayo is currently under ongoing development so this structure may be slightly changed at the time of reading this.

A Rayo CDR is typically made of a set of attributes that define the call and a complete transcript that shows how the call has gone through the system. This is an example:

<?xml version="1.0"?>
<cdr xmlns="http://tropo.com/schema/cdr" xmlns:cdr="http://tropo.com/schema/cdr"
  callId="eed317db-b126-4ed7-83b5-ac2007132015" 
  from="sip:martin@192.168.1.33:6089" 
  to="sip:userc@127.0.0.1:5060" 
  start="2011-10-06 12:17:42.20+0200" 
  end="2011-10-06 12:17:42.31+0200" state="DISCONNECTED">
  <offer xmlns="urn:xmpp:rayo:1" to="sip:userc@127.0.0.1:5060" from="sip:martin@192.168.1.33:6089" cdr:ts="2011-10-06 12:17:42.20+0200">
    <header name="Max-Forwards" value="70"/>
    <header name="Subject" value="Phone call"/>
    <header name="Content-Length" value="406"/>
    <header name="Contact" value="&lt;sip:martin@127.0.0.1:6089&gt;"/>
    <header name="Allow" value="INVITE"/>
    <header name="To" value="PrismLocal &lt;sip:userc@127.0.0.1:5060&gt;"/>
    <header name="CSeq" value="20 INVITE"/>
    <header name="User-Agent" value="Linphone/3.3.2 (eXosip2/3.3.0)"/>
    <header name="Via" value="SIP/2.0/UDP 192.168.1.33:6089;rport=6089;branch=z9hG4bK223660164;received=127.0.0.1"/>
    <header name="Call-ID" value="1083438027"/>
    <header name="Content-Type" value="application/sdp"/>
    <header name="From" value="&lt;sip:martin@192.168.1.33:6089&gt;;tag=1790499602"/>
  </offer>
  <answer xmlns="urn:xmpp:rayo:1" cdr:ts="2011-10-06 12:17:42.20+0200"/>
  <say xmlns="urn:xmpp:tropo:say:1" cdr:ts="2011-10-06 12:17:42.20+0200">
    <audio xmlns="" src="http://ccmixter.org/content/DoKashiteru/DoKashiteru_-_you_(na-na-na-na).mp3"/>
  </say>
  <todo cdr:ts="2011-10-06 12:17:42.20+0200">TODO: Empty IQ Result</todo>
  <ref xmlns="urn:xmpp:rayo:1" jid="eed317db-b126-4ed7-83b5-ac2007132015@localhost/e2765ecc-1624-45c2-9f74-5787aa656d13" cdr:ts="2011-10-06 12:17:42.20+0200"/>
  <complete xmlns="urn:xmpp:tropo:say:1" reason="HANGUP" cdr:ts="2011-10-06 12:17:42.20+0200"/>
  <end xmlns="urn:xmpp:rayo:1" cdr:ts="2011-10-06 12:17:42.20+0200">
    <hangup/>
  </end>
</cdr>

Configuring CDR storage

CDR storage configuration is done via editing the rayo-context.xml Spring configuration file. The following snippet shows a sample configuration that has enabled all the different types of supported CDR storages.

  	<bean id="cdrErrorHandler" class="com.rayo.server.cdr.DefaultErrorHandler"/>
  	<bean id="cdrManager" class="com.rayo.server.CdrManager">
  		<property name="errorHandler" ref="cdrErrorHandler"/>
  		<property name="storageStrategies">
  			<list>
  				<ref bean="fileCdrStorageStrategy"/>
  				<ref bean="jmsCdrStorageStrategy"/> 
                                <ref bean="xmppCdrStorageStrategy"/>
                                <ref bean="amqpCdrStorageStrategy"/>
  			</list>
  		</property>
  	</bean>

Let's go through that file. The first line defines an error handler that will be used to handle exceptions. Rayo comes with a default error handler that logs every error to the console, but you can provide your own error handlers should you want to.

The second bean configured is the CDR Manager. First we set up the error handler, and the second part of the bean is a list of storage strategies. In this example, we are enabling all the available storage strategies that come bundled with Rayo, a filesystem-based storage strategy, a JMS-based storage strategy, an XMPP PubSub storage strategy and an AMQP CDR storage strategy. But, again, you can create your own implementations of the CdrStorageStrategy interface if you need it.

When multiple storage strategies are set, Rayo will deliver the CDR to all strategies. In the example above, Rayo would first store the CDR in an audit log using the fileCdrStorageStrategy, then it would send the CDR to a JMS queue using the jmsCdrStorageStrategy, third it would send the CDR to a PubSub node within an XMPP server and finally it would deliver the CDR to an AMQP destination.

Below you will learn how to enable all the individual CDR storage strategies:

Filesystem based CDR storage

The file system based storage lets you specify a file where your CDRs will stored. The definition is as follows:

  	<bean id="fileCdrStorageStrategy" class="com.rayo.server.cdr.FileCdrStorageStrategy" 
  		  init-method="init"
  		  destroy-method="shutdown">
  		<property name="path" value="/tmp/test.log"/>
  	</bean>

There is two properties that you can specify:

  • path: The path for the file where the CDRs will be stored
  • append: You can specify whether you want to append information to the file or not. This field is optional. The default value is true.

JMS based CDR storage

The JMS based CDR storage lets you send CDRs to any JMS queue. You only need to define the JMS server connection and queue details in the configuration file. Here is an example:

        <util:map id="env" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.String">
		<entry>
			<key><util:constant static-field="javax.naming.Context.INITIAL_CONTEXT_FACTORY"/></key>
			<value>org.apache.activemq.jndi.ActiveMQInitialContextFactory</value>
		</entry>
		<entry>
			<key><util:constant static-field="javax.naming.Context.PROVIDER_URL"/></key>
			<value>tcp://localhost:61616</value>
		</entry>
        </util:map>
  	
  	<bean id="jmsCdrStorageStrategy" class="com.rayo.server.cdr.JMSCdrStorageStrategy" 
  		  init-method="init"
  		  destroy-method="shutdown">
		<property name="environment" ref="env"/>
		<property name="connectionFactory" value="QueueConnectionFactory"/>
		<property name="queue" value="example.A"/>
  	</bean>

Don't let the verbosity of this configuration to scare you. It is fairly simple. First there is a map of configuration options defined by the util:map block of code. In that map you need to define two options:

  • Initial Context Factory: You need to define the class that is used to create connections with your JMS server. This value depends on the application server you are going to use. Please also remember that whatever connection factory you use, you will need to include a JAR file with that class in your application. So for example, on the above example you would have to include activemq-core.jar in your WEB-INF/lib folder when deploying Rayo's WAR file.
  • Provider URL: The URL of your JMS Server like for example tcp://localhost:61616

Finally, in the bean section you need to define a couple of extra variables:

  • Connection Factory name: The JNDI name of the connection factory you are going to use. So for example if you are going to send messages to an ActiveMQ queue you would use the JNDI name QueueConnectionFactory.
  • Queue name: The JNDI name of the queue where the CDR messages will be sent.

XMPP PubSub based CDR storage

The XMPP based CDR storage lets you publish CDRs to any PubSub destination. You will only have to define the connection settings for the XMPP server and the name of the node where the CDRs will be sent. Here is an example:

  	<bean id="xmppCdrStorageStrategy" class="com.rayo.server.cdr.XmppCdrStorageStrategy"
  		  init-method="init"
  		  destroy-method="shutdown">
  		  <property name="server" value="yourxmppserverhere"/>
  		  <property name="port" value="5222"/>
  		  <property name="username" value="admin"/>
  		  <property name="password" value="admin"/>
  		  <property name="node" value="rayo-cdr"/>
  	</bean>

So, as you can see on the code above, you only need to define a few variables:

  • Server: Name or IP of the XMPP Server.
  • Port: The port where that XMPP server is listening to.
  • Username: The username that will connect to the server.
  • Password: The password for that username.
  • Node: This is the name of the PubSub node where messages will be published. Any consumers subscribed to that node will receive the CDRs.

AMQP based CDR storage

The AMQP based CDR storage lets you publish CDRs to any AMQP destination. You will only have to define the connection settings for the XMPP server and the name of the node where the CDRs will be sent. Here is an example that uses RabbitMQ:

  	<bean id="amqpCdrStorageStrategy" class="com.rayo.server.cdr.AmqpCdrStorageStrategy"
  		  init-method="init"
  		  destroy-method="shutdown">
  		  <property name="server" value="localhost"/>
  		  <property name="port" value="5672"/>
  		  <property name="username" value="guest"/>
  		  <property name="password" value="guest"/>
  		  <property name="exchange" value="rayo-exchange"/>
  		  <property name="route" value="rayo-route"/>
  	</bean>

So, as you can see on the code above, you only need to define a few variables:

  • Server: Name or IP of the AMQP Server.
  • Port: The port where that AMQP server is listening to.
  • Username: The username that will connect to the server.
  • Password: The password for that username.
  • Exchange: The name of the exchange where messages will be sent to.
  • Route: The name of the route where messages will be sent to.

And that is it. Any consumer subscribed to the specified exchange and route will receive the CDRs.

Viewing active CDRs in real time

You can view active CDRs in real time by using JMX. Check out the JMX Rayo Monitoring wiki page to find out how.

Configuring CDR storage in real time

Some CDR storage services can be configured by using JMX. Be sure to check out the JMX Rayo Monitoring wiki page to find out how.

Plugging in your own CDR Storage implementations

Chances are you don't want to use any of the provided CDR Storage mechanisms. You may want to store CDR in other places like Databases, or send the CDR to your Web Services or store them at remote locations like Amazon S3. In such cases you can plug your own CDR Storage implementations into Tropo very easily thanks to the SPI support.

The first thing you need to do is to create a service that implements the CdrStorageStrategy interface:

public interface CdrStorageStrategy {

	public void init() throws IOException;
	public void store(Cdr cdr) throws CdrException;
	public void shutdown();
}

Once you got your service ready you need to package it in a JAR file. But before doing that, you need to add an SPI resource descriptor file. As you will see, this is not a very hard task. However you may find the official docs at Oracle's website.

Basically you need to create the following text file and add it to your JAR file:

   META-INF/services/com.rayo.server.cdr.CdrStorageStrategy

And inside that text file you add one line for each of your implementations of the CdrStorageStrategy interface, like for example

com.acme.company.S3CdrStorageStrategy    # Amazon S3 based CDR Storage Service

And that is it. You can find an example of such file here.