Skip to end of metadata
Go to start of metadata

Introduction

Channel Event Logging (CEL) provides a series of records describing the state of channels in Asterisk to any of several event recording back-ends. CEL records provide substantially more information than CDRs and thus allow an Asterisk User to construct their own more complex billing system.

As a result of the bridging work done for Asterisk 12, CEL behavior has changed for several events that occur in the system. The most significant changes are:

  • AST_CEL_BRIDGE_ENTER and AST_CEL_BRIDGE_EXIT have been introduced to denote participant changes in bridges. 

  • AST_CEL_BRIDGE_START and AST_CEL_BRIDGE_END have been removed as they no longer applies to the new bridging framework.

  • AST_CEL_BRIDGE_UPDATE has been removed as it no longer applies to the new bridging framework.

  • AST_CEL_LOCAL_OPTIMIZE has been added to describe local channel optimizations that occur.

  • All linkedid accounting and record generation is now handled within the CEL engine.

  • The peer field is only used in BRIDGE_ENTER and BRIDGE_EXIT records.

Scope

This CEL specification applies to Asterisk 12. While some portions of this specification are applicable to prior versions of Asterisk, other portions are specific to Asterisk 12 and their counterparts in prior versions are not discussed.

Terminology

Term

Definition

CEL

Channel Event Logging. The focus of this documentation.

CEL record

An individual event record produced by the CEL engine.

CDR

Call Detail Record. An alternative method of extracting billing information from Asterisk. Simpler, but less flexible.

Stasis

The internal message bus in Asterisk that conveys state to the CEL engine.

Primary

The channel around which a CEL record is focused.

AMI

Asterisk Manager Interface

CSV

Comma Separated Values.  A format commonly used for tabular data when stored outside of a database.

CEL Overview

A CEL record contains information about a system event including a partial dump of the Primary's state and may contain data relevant to that specific record type such as channel names, bridge unique identifiers, channel variable values, or other miscellaneous information. The CEL engine tracks changes in individual channel state and guarantees ordering of records for a given Primary, but does not guarantee ordering of records in relation to other Primaries. The exception to this record ordering occurs with meta-records which occur adjacent to the events they describe. Applicable event ordering is provided in the descriptions below. CEL output does not describe interaction with MeetMe conferences other than MeetMe as an application.

Record Types

The records produced by the CEL engine can be grouped in to three general categories.

  • Stand-Alone Records
  • Interaction Records
  • Meta-Records

Stand-Alone Records

These records convey a channel event on the channel that does not involve channels or bridges other than the Primary.

Channel Start

An AST_CEL_CHANNEL_START record is generated when a channel is created. This record introduces a new Primary and is the first record available for all Primaries.

Channel End

An AST_CEL_CHAN_END record is generated when a channel is destroyed. This record indicates that a Primary is going away and that there will be no further records for this Primary with the exception of AST_CEL_LINKEDID_END.

Answer

An AST_CEL_ANSWER record is generated when a channel is answered. Depending on the state transitions that occur on a Primary, this record may not be generated.

Hangup

An AST_CEL_HANGUP record is generated when a channel is hung up. This record will occur on every Primary prior to channel destruction.

Application Start

An AST_CEL_APP_START record is generated when a channel enters an application. This record will always be generated before its corresponding AST_CEL_APP_END.

Application End

An AST_CEL_APP_END record is generated when a channel exits an application. This record will be generated after its corresponding AST_CEL_APP_START, but is not guaranteed to be generated on hangup.

User Defined

An AST_CEL_USER_DEFINED record is generated when a channel enters the CELGenUserEvent application. The application sets the user defined name field and additional information in the extra field in the "extra" key.

Linked ID End

An AST_CEL_LINKEDID_END record is generated when the last channel using the given linked ID is destroyed or the last instance of a linked ID is overwritten by a different linked ID. This is the only type of record that may occur after AST_CEL_CHANNEL_END.

Interaction Records

These records convey the Primary's interactions with other channels or bridges.

Bridge Enter

An AST_CEL_BRIDGE_ENTER record is generated when a channel enters a bridge. The entering channel is the Primary for this event. Additional information is conveyed in the extra field under the "bridge_id" key. The "bridge_technology" key is available in Asterisk 13+. All other channels in the bridge at the time of entry are available in the peer field as a comma-separated list.

Bridge Exit

An AST_CEL_BRIDGE_EXIT record is generated when a channel exits a bridge. The leaving channel is the Primary for this event. Additional information is conveyed in the extra field under the "bridge_id" key. The "bridge_technology" key is available in Asterisk 13+. All other channels in the bridge at the time of exit are available in the peer field as a comma-separated list.

Forward

An AST_CEL_FORWARD record is generated when a dialing channel is forwarded elsewhere by a dialed channel. The dialing channel is the Primary for this event. Additional information is conveyed in the extra field under the "forward" key.

Park Start

An AST_CEL_PARK_START record is generated when a channel is parked. The parked channel is the Primary for this event. Additional information is conveyed in the extra field under the keys "parker_dial_string" and "parking_lot".

Park End

An AST_CEL_PARK_START record is generated when a channel is unparked. The unparked channel is the Primary for this event. Additional information is conveyed in the extra field under the "reason" key and the "retriever" key when available. This record always occurs after its corresponding AST_CEL_PARK_START.

Pickup

An AST_CEL_PICKUP record is generated when a channel is picked up. The picked up channel (also known as the target) is the Primary for this record. The name of the channel that is picking up is conveyed in the extra field under the "pickup_channel" key.

Meta-Records

These records convey additional context relating to surrounding CEL records

Blind Transfer

An AST_CEL_BLINDTRANSFER record is generated when a blind transfer feature is activated on a bridge. The initiating channel is the Primary for this record. Additional information is conveyed in the extra field under the "extension", "context", and "bridge_id" keys.

Attended Transfer

An AST_CEL_ATTENDEDTRANSFER record is generated when an attended transfer is successfully performed.

Bridge-Bridge Attended Transfers

This type of attended transfer occurs when both involved channels are bridged. The initiating channel is the Primary for this record. Additional information is conveyed in the extra field under the "bridge1_id", "channel2_name", "bridge2_id", "transferee_channel_name", and "transfer_target_channel_name" keys.

The records associated with this type of transfer will vary depending on the configuration of the bridges involved and the number of channels involved. Possible methods of accomplishing the transfer include (but are not limited to) channel swap, bridge merge, and bridge link via a local channel.

Bridge-App Attended Transfers

This type of attended transfer occurs when one involved channel is bridged while the other is running an application. The bridged channel is the Primary for this record. Additional information is conveyed in the extra field under the "bridge1_id", "channel2_name", and "app" keys.

App-App Attended Transfers

Attended transfers involving only channels that are running applications are not currently possible. This is not possible with internal transfers since there is no bridge involved to handle the feature codes and any externally initiated attended transfer that attempts to bridge two app-bound channels will fail.

Local Channel Optimization

An AST_CEL_LOCAL_OPTIMIZE record is generated when a local channel optimization attempt completes successfully. The semi-one (local channel ending in ';1') channel is the Primary for this event. The name of the semi-two (local channel ending in ';2') channel is conveyed in the extra field under the "local_two" key.

Removed Records

The following record types are no longer available as of Asterisk 12:

  • AST_CEL_BRIDGE_START

  • AST_CEL_BRIDGE_END

  • AST_CEL_CONF_START

  • AST_CEL_CONF_END

  • AST_CEL_CONF_ENTER

  • AST_CEL_CONF_EXIT

  • AST_CEL_HOOKFLASH

  • AST_CEL_3WAY_START

  •  AST_CEL_3WAY_END

  • AST_CEL_BRIDGE_UPDATE

  • AST_CEL_TRANSFER

Record Fields

Primary Fields

These fields are populated exclusively from their corresponding fields on the Primary in a consistent manner for every CEL record.

CallerID Name

The name identifying the caller for this channel.

CallerID Number

The number identifying the caller for this channel.

CallerID ANI

Automatic Number Identification caller information provided for this channel.

CallerID RDNIS

Redirecting information for this channel.

CallerID DNID 

Dialed Number Identification for this channel.

Extension

The extension in which this channel is currently executing.

Context 

The context in which this channel is currently executing.

Channel Name 

The name of this channel.

Application Name

The name of the application that this channel is currently executing.

Application Data

The data provided to the application being executed.

Account Code

The account code used for billing.

Peer Account Code

The peer channel's account code.

Unique ID

This channel's instance unique identifier.

Linked ID

This channel's current linked ID which is affected by bridging operations. This identifier starts as the channel's unique ID.

AMA Flags

This channel's Automated Message Accounting flags.

Record Type Specific Fields

These fields vary or may be blank depending on the CEL record type.

User Defined Name

This field is only used for AST_CEL_USER_DEFINED and conveys the user-specified event type.

Extra

This field contains a JSON blob describing additional record-type-specific information.

Logging Backends

CEL provides several methods of logging records to be processed at a later time. CEL only publishes record types to backends that are enabled in the general CEL configuration. Sample configurations are provided with the Asterisk 12 source for all of these backends.

Custom

The Custom CEL output module provides logging capability to a CSV file in a format described in the configuration file. This module is configured in cel_custom.conf.

Manager

The manager CEL output module publishes records over AMI as CEL events with the record type published under the "EventName" key. This module is configured in cel.conf in the [manager] section.

ODBC

The ODBC CEL output module provides logging capability to any ODBC-compatible database. This module is configured in cel_odbc.conf.

PGSQL

The PGSQL CEL output module provides logging capability to PostgreSQL databases when it is desirable to avoid the ODBC abstraction layer. This module is configured in cel_pgsql.conf.

RADIUS

The RADIUS CEL output module allows the CEL engine to publish records to a RADIUS server. This module is configured in cel.conf in the [radius] section.

SQLite

The SQLite CEL output module provides logging capability to a SQLite3 database in a format described in its configuration file. This module is configured in cel_sqlite3_custom.conf.

TDS

The TDS CEL output module provides logging capability to Sybase or Microsoft SQL Server databases when it is desirable to avoid the ODBC abstraction layer. This module is configured in cel_tds.conf.

Example Scenarios

For the following scenarios, assume the CEL engine is configured to generate the following record types:

  • AST_CEL_CHANNEL_START

  • AST_CEL_CHAN_END

  • AST_CEL_BRIDGE_ENTER

  • AST_CEL_BRIDGE_EXIT

Two-Participant Bridge

The following scenario demonstrates channel creation, channel destruction, bridge start, and bridge end:

EventRecordPrimaryExtra
Channel Alice is createdAST_CEL_CHANNEL_STARTAlice 
Channel Bob is createdAST_CEL_CHANNEL_STARTBob 
Bridge Link is created   
Alice enters bridge LinkAST_CEL_BRIDGE_ENTERAlice{"bridge_id": "Link"}
Bob enters bridge LinkAST_CEL_BRIDGE_ENTERBob{"bridge_id": "Link"}
Bob exits bridge LinkAST_CEL_BRIDGE_EXITBob{"bridge_id": "Link"}
Bob is destroyedAST_CEL_CHAN_ENDBob 
Alice exits bridge LinkAST_CEL_BRIDGE_EXITAlice{"bridge_id": "Link"}
Alice is destroyedAST_CEL_CHAN_ENDAlice 

Multi-participant Conference

 

The following scenario demonstrates conversion of a bridge to a multi-participant conference:

Event

Record

Primary

Extra

Channel Alice is created

AST_CEL_CHANNEL_START

Alice

 

Channel Bob is created

AST_CEL_CHANNEL_START

Bob

 

Channel Charlie is created

AST_CEL_CHANNEL_START

Charlie

 

Channel David is created

AST_CEL_CHANNEL_START

David

 

Bridge Link is created

   

Alice enters bridge Link

AST_CEL_CONF_ENTER

Alice

{"bridge_id", "Link"}

Bob enters bridge Link

AST_CEL_CONF_ENTER

Bob

{"bridge_id", "Link"}

Charlie enters bridge Link

AST_CEL_CONF_ENTER

Charlie

{"bridge_id", "Link"}

David enters bridge Link

AST_CEL_CONF_ENTER

David

{"bridge_id", "Link"}

Alice exits bridge Link

AST_CEL_CONF_EXIT

Alice

{"bridge_id", "Link"}

Alice is destroyed

AST_CEL_CHAN_END

Alice

 

Bob exits bridge Link

AST_CEL_CONF_EXIT

Bob

{"bridge_id", "Link"}

Bob is destroyed

AST_CEL_CHAN_END

Bob

 

Charlie exits bridge Link

AST_CEL_CONF_EXIT

Charlie

{"bridge_id", "Link"}

Charlie is destroyed

AST_CEL_CHAN_END

Charlie

 

David exits bridge Link

AST_CEL_CONF_EXIT

David

{"bridge_id", "Link"}

David is destroyed

AST_CEL_CHAN_END

David

 

Dial Nominal

For this scenario, assume that AST_CEL_ANSWER, AST_CEL_HANGUP, AST_CEL_APP_START, and AST_CEL_APP_END are configured in addition to the aforementioned record types and that "Dial" is configured to be watched.

The following scenario demonstrates a Dial that results in an answer followed by bridging and hangup:

EventRecordPrimaryExtra
Channel Alice is createdAST_CEL_CHANNEL_STARTAlice 
Alice executes Dial(SIP/Bob)AST_CEL_APP_STARTAlice 
Channel Bob is createdAST_CEL_CHANNEL_STARTBob 
Bob answersAST_CEL_ANSWERBob 
Alice answersAST_CEL_ANSWERAlice 
Bridge Link is created   
Alice enters bridge LinkAST_CEL_BRIDGE_ENTERAlice{"bridge_id": "Link"}
Bob enters bridge LinkAST_CEL_BRIDGE_ENTERBob{"bridge_id": "Link"}
Bob initiates hangup, exits bridge LinkAST_CEL_BRIDGE_EXITBob{"bridge_id": "Link"}
Bob completes hang upAST_CEL_HANGUPBob{"hangupcause":16,"dialstatus":"","hangupsource":"Bob"}
Bob is destroyedAST_CEL_CHAN_ENDBob 
Alice exits bridge LinkAST_CEL_BRIDGE_EXITAlice{"bridge_id": "Link"}
Alice is hung upAST_CEL_HANGUPAlice{"hangupcause":16,"dialstatus":"ANSWER","hangupsource":""}
Alice is destroyedAST_CEL_CHAN_ENDAlice 

Dial Busy

For this scenario, assume that AST_CEL_ANSWER, AST_CEL_HANGUP, AST_CEL_APP_START, and AST_CEL_APP_END are configured in addition to the aforementioned record types and that "Dial" is configured to be watched. The following scenario demonstrates a Dial that results in a busy:

EventRecordPrimaryExtra
Channel Alice is createdAST_CEL_CHANNEL_STARTAlice 
Alice executes Dial(SIP/Bob)AST_CEL_APP_STARTAlice 
Channel Bob is createdAST_CEL_CHANNEL_STARTBob 
Bob responds BUSYAST_CEL_HANGUPBob {"hangupcause":21,"dialstatus":"","hangupsource":""}
Bob is destroyedAST_CEL_CHAN_ENDBob 
Alice is hung upAST_CEL_HANGUPAlice{"hangupcause":17,"dialstatus":"BUSY","hangupsource":""}
Alice is destroyedAST_CEL_CHAN_ENDAlice 

 

Blind Transfer

For this scenario, assume that AST_CEL_HANGUP is configured in addition to the aforementioned record types. The following scenario demonstrates a blind transfer:
 

EventRecordPrimaryExtra
Channel Alice is createdAST_CEL_CHANNEL_STARTAlice 
Channel Bob is createdAST_CEL_CHANNEL_STARTBob 
Alice answersAST_CEL_ANSWERAlice 
Bob answersAST_CEL_ANSWERBob 
Bridge Link is created   
Bob enters bridge LinkAST_CEL_BRIDGE_ENTERBob{"bridge_id":"Link"}
Alice enters bridge LinkAST_CEL_BRIDGE_ENTERAlice{"bridge_id":"Link"}
Alice initiates a blind transfer to [email protected]AST_CEL_BLINDTRANSFERAlice{"bridge_id":"Link","extension":"exten","context":"context"}
Alice exits bridge LinkAST_CEL_BRIDGE_EXITAlice{"bridge_id":"Link"}
Alice is hung upAST_CEL_HANGUPAlice{"hangupcause":16,"dialstatus":"","hangupsource":""}
Alice is destroyedAST_CEL_CHANNEL_ENDAlice 
A local channel pair is created to handle dialplanAST_CEL_CHANNEL_STARTLocal1 
 AST_CEL_CHANNEL_STARTLocal2 
Local1 enters bridge LinkAST_CEL_BRIDGE_ENTERLocal1{"bridge_id":"Link"}
Local2 executes dialplan at [email protected]   
Local2 is eventually hung up by the dialplanAST_CEL_HANGUPLocal2{"hangupcause":16,"dialstatus":"","hangupsource":""}
Hangup is initiated on Local1, exiting bridge LinkAST_CEL_BRIDGE_EXITLocal1{"bridge_id":"Link"}
Local1 is hung upAST_CEL_HANGUPLocal1{"hangupcause":16,"dialstatus":"","hangupsource":""}
Local1 is destroyedAST_CEL_CHANNEL_ENDLocal1 
Local2 is destroyedAST_CEL_CHANNEL_ENDLocal2 
Bob is the last channel and so is hung upAST_CEL_HANGUPBob{"hangupcause":16,"dialstatus":"","hangupsource":""}
Bob is destroyedAST_CEL_CHANNEL_ENDBob 

Attended Transfer

For this scenario, assume that AST_CEL_ANSWER and AST_CEL_HANGUP are configured in addition to the aforementioned record types. The following scenario demonstrates a channel-swapping attended transfer:

EventRecordPrimaryExtra
Channel Alice is createdAST_CEL_CHANNEL_STARTAlice 
Channel Bob is createdAST_CEL_CHANNEL_STARTBob 
Alice answersAST_CEL_ANSWERAlice 
Bob answersAST_CEL_ANSWERBob 
Bridge Link1 is created   
Bob enters bridge Link1AST_CEL_BRIDGE_ENTERBob{"bridge_id":"Link1"}
Alice enters bridge Link1AST_CEL_BRIDGE_ENTERAlice{"bridge_id":"Link1"}
Channel Charlie is createdAST_CEL_CHANNEL_STARTCharlie 
Channel David is createdAST_CEL_CHANNEL_STARTDavid 
Charlie answersAST_CEL_ANSWERCharlie 
David answersAST_CEL_ANSWERDavid 
Bridge Link2 is created   
David enters bridge Link2AST_CEL_BRIDGE_ENTERBob{"bridge_id":"Link2"}
Charlie enters bridge Link2AST_CEL_BRIDGE_ENTERAlice{"bridge_id":"Link2"}
An attended transfer between Alice and David begins   
Bob exits bridge Link1AST_CEL_BRIDGE_EXITBob{"bridge_id":"Link1"}
Bob enters bridge Link2AST_CEL_BRIDGE_ENTERBob{"bridge_id":"Link2"}
David exits bridge Link2AST_CEL_BRIDGE_EXITDavid{"bridge_id":"Link2"}
David is hung upAST_CEL_HANGUPDavid{"hangupcause":16,"dialstatus":"","hangupsource":""}
David is destroyedAST_CEL_CHANNEL_ENDDavid 
Alice and David execute an attended transfer AST_CEL_ATTENDEDTRANSFERAlice{"bridge1_id":"Link1","channel2_name":"David","bridge2_id":"Link2"}
Alice exits bridge Link1AST_CEL_BRIDGE_EXITAlice{"bridge_id":"Link1"}
Alice is hung upAST_CEL_HANGUPAlice{"hangupcause":16,"dialstatus":"","hangupsource":""}
Alice is destroyedAST_CEL_CHANNEL_ENDAlice 
Bob exits bridge Link2AST_CEL_BRIDGE_EXITBob{"bridge_id":"Link2"}
Charlie exits bridge Link2AST_CEL_BRIDGE_EXITCharlie{"bridge_id":"Link2"}
Bob is hung upAST_CEL_HANGUPBob{"hangupcause":16,"dialstatus":"","hangupsource":""}
Bob is destroyedAST_CEL_CHANNEL_ENDBob 
Charlie is hung upAST_CEL_HANGUPCharlie{"hangupcause":16,"dialstatus":"","hangupsource":""}
Charlie is destroyedAST_CEL_CHANNEL_ENDCharlie 

Note that the ATTENDEDTRANSFER event does not necessarily occur before or after the records it is related to.

  • No labels

2 Comments

  1. Noticed a few things that should to be fixed or improved in this article.

     

    An AST_CEL_CHAN_END record is generated when a channel is destroyed. This record indicates that a Primary is going away and that there will be no further records for this Primary with the exception of AST_CEL_LINKEDID_END.

    > For the following scenarios, assume the CEL engine is configured to generate the following record types:
    > AST_CEL_CHANNEL_START
    > AST_CEL_CHAN_END

    Should these not be AST_CEL_CHANNEL_END instead of AST_CEL_CHAN_END? The Asterisk enumeration has 'CHANNEL' instead of 'CHAN', but the database gets the event logged as 'CHAN'. Seems maybe someone got the two confused, or it was corrected in a later commit. The tables that show example events already use the correct enumeration name.

     

    An AST_CEL_PARK_START record is generated when a channel is unparked. The unparked channel is the Primary for this event. Additional information is conveyed in the extra field under the "reason" key and the "retriever" key when available. This record always occurs after its corresponding AST_CEL_PARK_START.

    Should this not be AST_CEL_PARK_END in the first sentence? The event type in the CEL table is PARK_END, the AST_CEL_PARK_END enumeration does exist in include/asterisk/cel.h, and it doesn't really make sense to log a second start record when a park is ending.

     

    The CDR specification article contains a list of fields with database data types for each. Any chance someone can add the same sort of table to this article? It's a bit annoying to have to go to third party sites or dig into the source code to determine which database fields should be in the CEL table and to determine how the fields have changed with an Asterisk upgrade.

     

    This article is missing what the CEL event types are when logged to a database, there is some discrepancy in the naming compared to the internal Asterisk CEL enumerations. For ease of reference, here are the Asterisk 12/13 event types as logged to the database (pulled from main/cel.c): CHAN_START, CHAN_END, ANSWER, HANGUP, APP_START, APP_END, PARK_START, PARK_END, USER_DEFINED, BRIDGE_ENTER, BRIDGE_EXIT, BLINDTRANSFER, ATTENDEDTRANSFER, PICKUP, FORWARD, LINKEDID_END, LOCAL_OPTIMIZE

    1. Actually, it does seem some of the example tables incorrectly use AST_CEL_CHAN_END instead of AST_CEL_CHANNEL_END .