CDR details

CDRs (Call Detail Records) are generated by cdrbuild and cdrfile Yate modules (loaded by default in YateUCN and YateSMSC equipment)

  • Configuration files can be found on: /etc/yate/ucn/cdrbuild.conf and /etc/yate/ucn/cdrfile.conf (/etc/yate/smsc/cdrbuild.conf ; /etc/yate/smsc/cdrfile.conf )
  • They are stored by default in /var/log/yate-ucn-cdr.tsv ; /var/log/yate-smsc-cdr.tsv files, which are rotated by logrotate utility.
    » These locations can be changes and you should check that these new files are log rotated –
    » See file ‘/etc/logrotate.d/yate-ucn’; ‘/etc/logrotate.d/yate-ucn’
  • We have three on top services to handle Yate products CDR logs.
    yate-cdrfifo → provides a CDR FIFO and JSON despooler for Yate based products
    yate-cdrpush → provides a script for pushing CDRs to a remote SFTP server for Yate based products
    ✔ yate-cdrenrich → provides a CDR enricher for YateUCN and YateSMSC that makes JSON requests to YateHSS

CDR files format

Question: Are the records in the CDR files always mixed ?
Answer: Yes, the CDR files are always mixed, there is no warranty regarding the order they are written in the file, you should correlate them by billid.
The records are always build as described in cdrfile.conf file.
This is the header of the table. If a certain value is missing, it won’t be added to CDRs and there will be spaces instead of it.

[root@yate-ucn /etc/yate/ucn]# cat cdrfile.conf 
format=${time} ${route_type$call} ${component}${connection_id} ${billid} ${chan} ${address} ${caller} ${called} \
${billtime} ${ringtime} ${duration} ${direction} ${status} ${reason} ${rtp_stats} \
${charging_id} ${imsi} ${imeisv} ${nsapi} ${qci} ${qos} ${ipv4} ${ipv6} \
${inp_pkt} ${inp_oct} ${out_pkt} ${out_oct} ${rat_type} ${plmn} ${loc_info}
[root@yate-ucn /etc/yate/ucn]#

Question: How can we add new fields in the CDR files? (Usage: To record the caller number when he is anonymous)

Answer: First you should add parameter in the cdrfile.conf (the name of the field) and the ‘name_of_variable’
Ex: ,${asserted_caller},${rn},

Then also add that parameter name in cdrbuild.conf

echo “asserted_caller=true” >> /etc/yate/ucn/cdrbuild.conf
echo “rn=true” >> /etc/yate/ucn/cdrbuild.conf

Then assure that these params are copied from other Yate modules.

Any extra parameters can be added in [parameters] section of cdrbuild.conf file

  » rn=true -> updates everytime if it is present

  » rn=false -> it is freezed like this, first time when will be found and is not empty

cdrbuild module will store it when it appears in different monitored messages.
For this to appear in chan.startup of each outbound chan – we should set copyparams=rn from call.route or call.execute

If copyparams already contains some other parameters, we should keep those also, so set like this:


It is alright to have some extra commas.

: In CRDs, the records with same billid are they calculated like one SMS? Answer: Yes. In the example below there are two call legs: incoming and outgoing
Is comming through MAP in the SMSC (40744003001) and is sent over HTTP to

[root@yate-smsc old-cdr]# grep 1543926687-18 core_server2__2018-12-04_15-59-11__yate-smsc-cdr.tsv
1543934906.092 msg SMSC 1543926687-18 MAP 40740003001 40746820086 40744003001 0.002 incoming 001010302000035
1543934907.104 msg SMSC 1543926687-18 HTTP 40746820086 40744003001 0.080 outgoing 4
[root@yate-smsc old-cdr]#


Question: The ‘billid’ is always unique? In which cases there is only one row for a call?
Answer: Yes, the billid is always uniq.
For Voice and SMSes CDRs: It is composed of a timestamp (date when Yate service was started) + uniq ID (which is growing incrementally)

[root@yate-ucn old-cdr]# seelogs core_server1__2018-11-29_13-08-57__yate-ucn-cdr.tsv
2018-11-29_13:08:54.249 call fixed 1543418964-26 sip/51 +40747553298 +40747735711 0.000 0.000 3.565 incoming progressing Request Terminated
2018-11-29_13:08:54.250 call mvno 1543418964-26 sip/52 +40747553298 +40747735711 0.000 0.000 3.567 outgoing progressing Cancelled
[root@yate-ucn old-cdr]# seelogs core_server1__2018-11-27_11-59-07__yate-ucn-cdr.tsv
2018-11-27_11:58:56.399 call mvno 1542795110-172 sip/343 +40746008701 +40745300058 5.686 2.948 11.196 incoming answered
2018-11-27_11:58:56.400 call mno 1542795110-172 sip/344 +40746008701 +40745300058 5.691 2.948 11.200 outgoing answered
[root@yate-ucn old-cdr]#

For data: Is composed of timestamp (UNIX start time of yate in hexa) – name of GTP-C EP – TEI-C in hexa

[root@yate-ucn old-cdr]# seelogs core_server1__2018-11-28_18-51-14__yate-ucn-cdr.tsv
2018-11-28_18:45:22.028 call f2m 1543418964-2 sip/3 +40742211451 +40741456923 0.000 0.000 4.934 incoming progressing Request Terminated
2018-11-28_18:45:22.029 call mvno 1543418964-2 sip/4 +40742211451 +40741456923 0.000 0.000 4.938 outgoing progressing Cancelled
2018-11-28_18:47:00.233 call m2m 1543418964-3 sip/6 +40744600870 +40740300058 3.130 4.748 13.704 outgoing answered
2018-11-28_18:47:00.232 call mvno 1543418964-3 sip/5 +40744600870 +40740300058 3.135 4.748 13.710 incoming answered
2018-11-28_18:50:18.309 data PGW 5bfeb454-pgw0-c/6b2e28f2 pgw0-u/0/6c320ba 40744600870 internet_apn 56.370 56.370 incoming 113451194 001010302010072 3579990570930006 6 9 1b921f7396fefe74831040006400 0 0 0 0 1 00101 0192f41000651eb9
[root@yate-ucn old-cdr]#

Question: Some details about ${loc_info}? Is supposed to be decodable then for extra location information.

Answer: ${loc_info} holds the 3GPP-User-Location-Info, please see TS 29.06116.4.7.2 (3GPP Type: 22) for the encoding used in RADIUS and Diameter.

If you want to decode the loc_info field (User Location Info in binary format), take a look at the examples below:

01 = Contains CGI (GSM)
CGI: 3+2+2 octets
130062 = PLMN 310-260
2775 = LAC 0x2775 = 10101
5aca = Cell ID 0x5aca = 23242

82 = Contains TAI and ECGI (LTE)
TAI: 3 + 2 octets
32f401 = TAI PLMN 234-10
1080 = TAC 0x1080 = 4224
ECGI: 3 + 4 octets
32f401 = ECGI PLMN 234-10
0 = unused
7a2417c = E-UTRAN Cell 0x7a2417c = 128074108

82 = Contains TAI and ECGI (LTE)
TAI: 3 + 2 octets
32f401 = TAI PLMN 234-10
1080 = TAC 0x1080 = 4224
ECGI: 3 + 4 octets
32f401 = ECGI PLMN 234-10
0 = unused
7a24178 = E-UTRAN Cell 0x7a24178 = 128074104

If you just want a Serving PLMN ID you can skip first octet (type) / 2 characters, take the following 3 octets / 6 characters and do a bit of swapping.
The order of nibbles / characters is:

  1. MCC digit 2
  2. MCC digit 1
  3. MNC digit 3 (or F if MNC is 2 digits long)
  4. MCC digit 3
  5. MNC digit 2
  6. MNC digit 1

So if the string is xxABCDEFxxx… the PLMN will be BAD-FEC or BAD-FE

Question: If sms is successfully delivered, the reason field is not filled in the log file (empty). Why?


Answer: Empty reason is actually used to indicate success. CDRs for delivery may look like:

attempt#1 tries:10 reason:failure
attempt#2 tries:9 reason:absent
attempt#3 tries:8 (no reason = success)

or maybe

attempt#10 tries:1 reason:absent
attempt#11 tries:0 reason:absent (final because tries left is zero)


Question: Is there more that two rows for one call ?

  • coming to Yate (incoming)
  • going out from Yate (outgoing)
  • 1 incoming: Q is calling X (through Yate)
  • 2 outgoing: Yate to X (X has CF to Z) and Yate to Z

Question: Why is the time different. Should it be billtime + ringtime = duration, if this is the case why ringtime is 0.000
Answer: Signaling (session negotiation) till 180 Ringing is received; signaling is not ringtime
Voice: if there is no billtime, there is no bill.

  • assuming A-MVNO user is roaming in Spain -> and B-MVNO user is calling A (in Spain) -> and you want bill both A (as is called in roaming) and B (as it calls to roaming)
  • you need to bill both incoming and outgoing. This it won’t work if called is not your MVNO subscriber


Question: Can we get all the scenarios for the status column and reason too?

one of incoming, outgoing, ringing, answered or connected, reflecting the current state of the call referred to by this CDR
a (mostly) human readable reason for this CDR.


[root@yate-smsc smsc]# cat cdrfile.conf 
format=${time} ${route_type$msg} ${component}${connection_id} \
${billid} ${protocol} ${address} ${caller} ${called} \
${duration} ${direction} ${retries} ${reason} \
${charging_id} ${imsi}
[root@yate-smsc smsc]#

Question: The column that is +1 in the CDR files always has value of 4 what is that value?
Answer: This value of 4 is the ${retries} initial value, it begins with 4 (meaning that has maximum 4 retries), if does not succeed, goes to 3, then to 2, then to 1

  • SMS Attempts:: Optional, integer, range [1,30]. How many attempts to make to deliver each SMS. Taken from Extra params if missing.

Question: Is there any way to count the characters of the message so we could incorporate in our billing payment for more than 1 message?
Answer: Below are the CDRs for one SMS that was longer than 160 chars. “just sent sms from +40745867112 to +40747827112”
You don’t need to make anything special (the SMSC dispatch the long SMSes as two messages and bills them separately)
For each SMS there is a CDR entry, for long SMSes there are two/or more entries in the CDRs each with different billid

${time} ${route_type$msg} ${component} ${connection_id} ${billid} ${protocol} ${address} ${caller} ${called} ${duration} ${direction} ${retries} ${reason} ${charging_id} ${imsi} 

receiving SMSes by SMSC from your_MNO
2018-11-29_14:56:02.315 msg SMSC 1541755391-105 MAP 40744003001 40745867112 40747827112 0.002 incoming 001010302000034
2018-11-29_14:56:02.467 msg SMSC 1541755391-106 MAP 40744003001 40745867112 40747827112 0.002 incoming 001010302000034

sending SMSes:
2018-11-29_14:56:03.277 msg SMSC 1541755391-105 MAP 40744003001 40745867112 40747827112 1.448 outgoing 4 001010302000036
2018-11-29_14:56:04.727 msg SMSC 1541755391-106 MAP 40744003001 40745867112 40747827112 0.156 outgoing 4 001010302000036

sending delivery report:
2018-11-29_14:56:27.158 msg SMSC 1541755391-107 MAP 40740003001 40744600869 40744600867 0.002 incoming 001010302000036
2018-11-29_14:56:28.327 msg SMSC 1541755391-107 MAP 40740003001 40744600869 40744600867 0.692 outgoing 4 001010302000034

Default Values

Question: What is the default value of the CDR closing interval?
Answer: Taken from the configuration file: /etc/yate/yateucn.conf.sample:

; Minimum interval in seconds between interim (status) data CDR messages
; Can be overridden by MME, SGSN or PGW
; Valid values 30 – 86400, default 0 which disables status CDRs
; Maximum interval in seconds at which to finalize a CDR and start a new one
; Can be overridden by MME, SGSN or PGW
; Valid values 300 – 2678400 (31 days), default 0 which disables restarting CDRs


All generated CDRs with all operations are stored in a sqlite database implementing a First Input First Output strategy (queue).The register module is used to append these CDR records to the database table (queue tail).

The yate-cdrfifo service extracts a number of CDRs of a certain type from the start of the table (queue head) and creates a HTTP request from them.
If the HTTP result is positive (2xx) the CDR entries are deleted from the database.
If any network or HTTP error occurs the entries are not deleted and will be retries at the next cycle.


The CDR enrichment takes place before the record is put in FIFO.

[MSC] --\ /-> [register module] -> CDR FIFO -> [yate-cdrfifo service] -> HTTP request
[PGW] -----> CDR message -> [CDR enrichment] ----> [cdrfile module] -> /var/log/yate-*-cdr.tsv
[SMSC] -/ \-> [yradius module] -> RADIUS request

The FIFO contains the final version of the record so it will back up everything.

Our solutions