Call Detail Records

The CDR system in Asterisk is used to log the history of calls in the system. In some deployments, these records are used for billing purposes. In others, call records are used for analyzing call volumes over time. They can also be used as a debugging tool by Asterisk administrators.

CDR Contents

A CDR has a number of fields that are included by default. Table 24.2, “Default CDR fields” lists them.

Table 24.2. Default CDR fields

OptionValue/ExampleNotes
accountcode12345An account ID. This field is user-defined and is empty by default.
src12565551212The calling party’s caller ID number. It is set automatically and is read-only.
dst102The destination extension for the call. This field is set automatically and is read-only.
dcontextPublicExtensionsThe destination context for the call. This field is set automatically and is read-only.
clid"Big Bird" <12565551212>The full caller ID, including the name, of the calling party. This field is set automatically and is read-only.
channelSIP/0004F2040808-a1bc23efThe calling party’s channel. This field is set automatically and is read-only.
dstchannelSIP/0004F2046969-9786b0b0The called party’s channel. This field is set automatically and is read-only.
lastappDialThe last dialplan application that was executed. This field is set automatically and is read-only.
lastdataSIP/0004F2046969,30,tTThe arguments passed to the lastapp. This field is set automatically and is read-only.
start2010-10-26 12:00:00The start time of the call. This field is set automatically and is read-only.
answer2010-10-26 12:00:15The answered time of the call. This field is set automatically and is read-only.
end2010-10-26 12:03:15The end time of the call. This field is set automatically and is read-only.
duration195The number of seconds between the start and end times for the call. This field is set automatically and is read-only.
billsec180The number of seconds between the answer and end times for the call. This field is set automatically and is read-only.
dispositionANSWEREDAn indication of what happened to the call. This may be NO ANSWER, FAILED, BUSY, ANSWERED, or UNKNOWN.
amaflagsDOCUMENTATIONThe Automatic Message Accounting (AMA) flag associated with this call. This may be one of the following: OMIT, BILLING, DOCUMENTATION, or Unknown.
userfieldPerMinuteCharge:0.02A general-purpose user field. This field is empty by default and can be set to a user-defined string.[a]
uniqueid1288112400.1The unique ID for the src channel. This field is set automatically and is read-only.

[a] The userfield is not as relevant now as it used to be. Custom CDR variables are a more flexible way to get custom data into CDRs.


All fields of the CDR record can be accessed in the Asterisk dialplan by using the CDR() function. The CDR() function is also used to set the fields of the CDR that are user-defined.

exten => 115,1,Verbose(Call start time: ${CDR(start)})
   same => n,Set(CDR(userfield)=zombie pancakes)

In addition to the fields that are always included in a CDR, it is possible to add custom fields. This is done in the dialplan by using the Set() application with the CDR() function:

exten => 115,1,NoOp()
   same => n,Set(CDR(mycustomfield)=coffee)
   same => n,Verbose(I need some more ${CDR(mycustomfield)})

Note

If you choose to use custom CDR variables, make sure that the CDR backend that you choose is capable of logging them.

To view the built-in documentation for the CDR() function, run the following command at the Asterisk console:

*CLI> core show function CDR

In addition to the CDR() function, there are some dialplan applications that may be used to influence CDR records. We’ll look at these next.

Dialplan Applications

There are a few dialplan applications that can be used to influence CDRs for the current call. To get a list of the CDR applications that are loaded into the current version of Asterisk, we can use the following CLI command:

*CLI> core show applications like CDR
    -= Matching Asterisk Applications =-
               ForkCDR: Forks the Call Data Record. 
                 NoCDR: Tell Asterisk to not maintain a CDR for the current call 
              ResetCDR: Resets the Call Data Record. 
    -= 3 Applications Matching =-

Each application has documentation built into the Asterisk application, which can be viewed using the following command:

*CLI> core show application <application name>

cdr.conf

The cdr.conf file has a [general] section that contains options that apply to the entire CDR system. Additional optional sections may exist in this file that apply to specific CDR logging backend modules. Table 24.3, “cdr.conf [general] section” lists the options available in the [general] section.

Table 24.3. cdr.conf [general] section

OptionValue/ExampleNotes
enableyesEnable CDR logging. The default is yes.
unanswerednoLog unanswered calls. Normally, only answered calls result in a CDR. Logging all call attempts can result in a large number of extra call records that most people do not care about. The default value is no.
end before hextennoClose out CDRs before running the h extension in the Asterisk dialplan. Normally CDRs are not closed until the dialplan is completely finished running. The default value is no.
initiated secondsnoWhen calculating the billsec field, always round up. For example, if the difference between when the call was answered and when the call ended is 1 second and 1 microsecond, billsec will be set to 2 seconds. This helps ensure that Asterisk’s CDRs match the behavior used by telcos. The default value is no.
batchnoQueue up CDRs to be logged in batches instead of logging synchronously at the end of every call. This prevents CDR logging from blocking the completion of the call teardown process within Asterisk. The default value is no, but we recommend turning it on.[a]
size100Set the number of CDRs to queue up before they are logged during batch mode. The default value is 100.
time300Set the maximum number of seconds that CDRs will wait in the batch queue before being logged. The CDR batch logging process will run at the end of this time period, even if size has not been reached. The default value is 300 seconds.
scheduler onlynoSet whether CDR batch processing should be done by spawning a new thread, or within the context of the CDR batch scheduler. The default value is no, and we recommend not changing it.
safe shutdownyesBlock Asterisk shutdown to ensure that all queued CDR records are logged. The default is yes, and we recommend leaving it that way, as this option prevents important data loss.

[a] The disadvantage of enabling this option is that if Asterisk were to crash or die for some reason, the CDR records would be lost, as they are only stored in memory while the Asterisk process exists. See safeshutdown for more information.


Backends

Asterisk CDR backend modules provide a way to log CDRs. Most CDR backends require specific configuration to get them going.

cdr_adaptive_odbc

As the name suggests, the cdr_adaptive_odbc module allows CDRs to be stored in a database through ODBC. The “adaptive” part of the name refers to the fact that it works to adapt to the table structure: there is no static table structure that must be used with this module. When the module is loaded (or reloaded), it reads the table structure. When logging CDRs, it looks for a CDR variable that matches each column name. This applies to both the built-in CDR variables and custom variables. If you want to log the built-in channel CDR variable, just create a column called channel.

Adding custom CDR content is as simple as setting it in the dialplan. For example, if we wanted to log the User-Agent that is provided by a SIP device, we could add that as a custom CDR variable:

exten => 105,n,Set(CDR(useragent)=${CHANNEL(useragent)})

To have this custom CDR variable inserted into the database by cdr_adaptive_odbc, all we have to do is create a column called useragent.

Multiple tables may be configured in the cdr_adaptive_odbc configuration file. Each goes into its own configuration section. The name of the section can be anything; the module does not use it. Here is an example of a simple table configuration:

[mytable]

connection = asterisk
table = asterisk_cdr

A more detailed example of setting up a database for logging CDRs can be found in the section called “Storing Call Detail Records (CDRs)”.

Table 24.4, “cdr_adaptive_odbc.conf table configuration options” lists the options that can be specified in a table configuration section in the cdr_adaptive_odbc.conf file.

Table 24.4. cdr_adaptive_odbc.conf table configuration options

OptionValue/ExampleNotes
connectionpgsql1The database connection to be used. This is a reference to the configured connection in res_odbc.conf. This field is required.
tableasterisk_cdrThe table name. This field is required.
usegmtimenoIndicates whether to log timestamps using GMT instead of local time. The default value for this option is no.

In addition to the key/value pair fields that are shown in the previous table, cdr_adaptive_odbc.conf allows for a few other configuration items. The first is a column alias. Normally, CDR variables are logged to columns of the same name. An alias allows the variable name to be mapped to a column with a different name. The syntax is:

alias <CDR variable> => <column name>

Here is an example column mapping using the alias option:

alias src => source

It is also possible to specify a content filter. This allows you to specify criteria that must match for records to be inserted into the table. The syntax is:

filter <CDR variable> => <content>

Here is an example content filter:

filter accountcode => 123

Finally, cdr_adaptive_odbc.conf allows static content for a column to be defined. This can be useful when used along with a set of filters. This static content can help differentiate records that were inserted into the same table by different configuration sections. The syntax for static content is:

static <"Static Content Goes Here"> => <column name>

Here is an example of specifying static content to be inserted with CDRs:

static "My Content" => my_identifier

cdr_csv

The cdr_csv module is a very simple CDR backend that logs CDRs into a CSV (comma separated values) file. The file is /var/log/asterisk/cdr-csv/Master.csv. As long as CDR logging is enabled in cdr.conf and this module has been loaded, CDRs will be logged to the Master.csv file.

While no options are required to get this module working, there are some options that customize its behavior. These options, listed in Table 24.5, “cdr.conf [csv] section options”, are placed in the [csv] section of cdr.conf.

Table 24.5. cdr.conf [csv] section options

OptionValue/ExampleNotes
usegmtimenoLog timestamps using GMT instead of local time. The default is no.
loguniqueidnoLog the uniqueid CDR variable. The default is no.
loguserfieldnoLog the userfield CDR variable. The default is no.
accountlogsyesCreate a separate CSV file for each different value of the accountcode CDR variable. The default is yes.

The order of CDR variables in CSV files created by the cdr_csv module is:

<accountcode>,<src>,<dst>,<dcontext>,<clid>,<channel>,<dstchannel>,<lastapp>, \
    <lastadata>,<start>,<answer>,<end>,<duration>,<billsec>,<disposition>, \
    <amaflags>[,<uniqueid>][,<userfield>]

cdr_custom

This CDR backend allows for custom formatting of CDR records in a log file. This module is most commonly used for customized CSV output. The configuration file used for this module is /etc/asterisk/cdr_custom.conf. A single section called [mappings] should exist in this file. The [mappings] section contains mappings between a filename and the custom template for a CDR. The template is specified using Asterisk dialplan functions.

The following example shows a sample configuration for cdr_custom that enables a single CDR log file, Master.csv. This file will be created as /var/log/asterisk/cdr-custom/Master.csv. The template that has been defined uses both the CDR() and CSV_QUOTE() dialplan functions. The CDR() function retrieves values from the CDR being logged. The CSV_QUOTE() function ensures that the values are properly escaped for the CSV file format:

[mappings]

Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},
   ${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},
   ${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},
   ${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},
   ${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},
   ${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},
   ${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},
   ${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},
   ${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})}

Note

In the actual configuration file, the value in the Master.csv mapping should be on a single line.

cdr_manager

The cdr_manager backend emits CDRs as events on the Asterisk Manager Interface (AMI), which we discussed in detail in Chapter 20, Asterisk Manager Interface (AMI). This module is configured in the /etc/asterisk/cdr_manager.conf file. The first section in this file is the [general] section, which contains a single option to enable this module (the default value is no):

[general]

enabled = yes

The other section in cdr_manager.conf is the [mappings] section. This allows for adding custom CDR variables to the manager event. The syntax is:

<CDR variable> => <Header name>

Here is an example of adding two custom CDR variables:

[mappings]

rate => Rate
carrier => Carrier

With this configuration in place, CDR records will appear as events on the manager interface. To generate an example manager event, we will use the following dialplan example:

exten => 110,1,Answer()
    same => n,Set(CDR(rate)=0.02)
    same => n,Set(CDR(carrier)=BS&S)
    same => n,Hangup()

This is the command used to execute this extension and generate a sample manager event:

*CLI> console dial 110@testing

Finally, this is an example manager event produced as a result of this test call:

Event: Cdr
Privilege: cdr,all
AccountCode: 
Source: 
Destination: 110
DestinationContext: testing
CallerID: 
Channel: Console/dsp
DestinationChannel: 
LastApplication: Hangup
LastData: 
StartTime: 2010-08-23 08:27:21
AnswerTime: 2010-08-23 08:27:21
EndTime: 2010-08-23 08:27:21
Duration: 0
BillableSeconds: 0
Disposition: ANSWERED
AMAFlags: DOCUMENTATION
UniqueID: 1282570041.3
UserField: 
Rate: 0.02
Carrier: BS&S

cdr_mysql

This module allows posting of CDRs to a MySQL database. We recommend that new installations use cdr_adaptive_odbc instead.

cdr_odbc

This module enables the legacy ODBC interface for CDR logging. New installations should use cdr_adaptive_odbc instead.

cdr_pgsql

This module allows posting of CDRs to a PostgreSQL database. We recommend that new installations use cdr_adaptive_odbc instead.

cdr_radius

The cdr_radius backend allows posting of CDRs to a RADIUS server. When using this module, each CDR is reported to the RADIUS server as a single stop event. This module is configured in the /etc/asterisk/cdr.conf file. Options for this module are placed in a section called [radius]. The available options are listed in Table 24.6, “cdr.conf [radius] section options”.

Table 24.6. cdr.conf [radius] section options

OptionValue/ExampleNotes
usegmtimenoEnables logging of timestamps using GMT instead of local time. The default is yes.
log unique idnoEnables logging of the uniqueid CDR variable. The default is yes.
loguserfieldnoEnables logging of the userfield CDR variable. The default is yes.
radiuscfg /etc/ radius client -ng/ radius client .confSets the location of the radiusclient-ng configuration file. The default is /etc/radiusclient-ng/radiusclient.conf.

cdr_sqlite

This module allows posting of CDRs to a SQLite database using SQLite version 2. Unless you have a specific need for SQLite version 2 as opposed to version 3, we recommend that all new installations use cdr_sqlite3_custom.

This module requires no configuration to work. If the module has been compiled and loaded into Asterisk, it will insert CDRs into a table called cdr in a database located at /var/log/asterisk/cdr.db.

cdr_sqlite3_custom

This CDR backend inserts CDRs into a SQLite database using SQLite version 3. The database created by this module lives at /var/log/asterisk/master.db. This module requires a configuration file, /etc/asterisk/cdr_sqlite3_custom.conf. The configuration file identifies the table name, as well as customizes which CDR variables will be inserted into the database:

[master]

table = cdr

;
; List the column names to use when inserting CDRs.
;
columns => calldate, clid, dcontext, channel, dstchannel, lastapp, lastdata,
    duration, billsec, disposition, amaflags, accountcode, uniqueid, userfield, 
    test


;
; Map CDR contents to the previously specified columns.
;
values => '${CDR(start)}','${CDR(clid)}','${CDR(dcontext)}','${CDR(channel)}',
    '${CDR(dstchannel)}','${CDR(lastapp)}','${CDR(lastdata)}','${CDR(duration)}',
    '${CDR(billsec)}','${CDR(disposition)}','${CDR(amaflags)}',
    '${CDR(accountcode)}','${CDR(uniqueid)}','${CDR(userfield)}','${CDR(test)}'

Note

In the cdr_sqlite3_custom.conf file, the contents of the columns and values options must each be on a single line.

cdr_syslog

This module allows logging of CDRs using syslog. To enable this, first add an entry to the system’s syslog configuration file, /etc/syslog.conf. For example:

local4.*      /var/log/asterisk/asterisk-cdr.log

The Asterisk module has a configuration file, as well. Add the following section to /etc/asterisk/cdr_syslog.conf:

[cdr]

facility = local4
priority = info
template = "We received a call from ${CDR(src)}"

Here is an example syslog entry using this configuration:

$ cat /var/log/asterisk/asterisk-cdr.log

Aug 12 19:17:36 pbx cdr: "We received a call from 2565551212"

cdr_tds

The cdr_tds module uses the FreeTDS library to post CDRs to a Microsoft SQL Server or Sybase database. It is possible to use FreeTDS with unixODBC, so we recommend using cdr_adaptive_odbc instead of this module.

Example Call Detail Records

We will use the cdr_custom module to illustrate some example CDR records for different call scenarios. The configuration used for /etc/asterisk/cdr_custom.conf is shown in the section called “cdr_custom”.

Single-party call

In this example, we’ll show what a CDR looks like for a simple one-party call. Specifically, we will use the example of a user calling in to check her voicemail. Here is the extension from /etc/asterisk/extensions.conf:

exten => *98,1,VoiceMailMain(@${GLOBAL(VOICEMAIL_CONTEXT)})

This is the CDR from /var/log/asterisk/cdr-custom/Master.csv that was created as a result of calling this extension:

"""Console"" <2565551212>","2565551212","*98","UserServices","Console/dsp","",
    "VoiceMailMain","@shifteight.org","2010-08-16 01:08:44","2010-08-16 01:08:44",
    "2010-08-16 01:08:53","9","9","ANSWERED","DOCUMENTATION","","1281935324.0","",0

Two-party call

For this next example, we show what a CDR looks like for a simple two-party call. We’ll have one SIP phone place a call to another SIP phone. The call is answered and then hung up after a short period of time. Here is the extension that was dialed:

exten => 101,1,Dial(SIP/0000FFFF0002)

Here is the CDR that was logged to Master.csv as a result of this call:

"""Console"" <2565551212>","2565551212","101","LocalSets","Console/dsp",
    "SIP/0000FFFF0002-00000000","Dial","SIP/0000FFFF0002","2010-08-16 01:16:10",
    "2010-08-16 01:16:16","2010-08-16 01:16:29","19","13","ANSWERED",
    "DOCUMENTATION","","1281935770.2","",2

Caveats

The CDR system in Asterisk works very well for fairly simple call scenarios. However, as call scenarios get more complicated, involving calls to multiple parties, transfers, parking, and other such features, the CDR system starts to fall short. Many users report that the records do not show all of the information that they expect. Many bug fixes have been made to address some of the issues, but the cost of regressions or changes in behavior when making changes in this area is very high since these records are used for billing.

As a result, the Asterisk development team has become increasingly resistant to making additional changes to the CDR system. Instead, a new system, channel event logging (CEL), has been developed that is intended to help address logging of more complex call scenarios. Bear in mind that call detail records are simpler and easier to consume, though, so we still recommend using CDRs if they suit your needs.