Changing the CDRs generated by Sentinel
Sentinel defines the CDR format, and a number of mappers for building CDRs using the code generated by the Google protobuf compiler.
You have two options for generating your own CDRs:
Option number one is the preferred and recommended approach.
For more details on mappers, see the Mappers overview. |
The examples given assume the SDK was installed for (vendor=Acme Inc, vendorKey=acme, version=1.5)
|
CDR Mapper Module Packs
Sentinel Express includes three module packs that can be used to extend Sentinel CDRs:
-
sentinel-diameter-cdr-mappers
for Diameter. -
sentinel-ss7-cdr-mappers
for SS7.
Creating a Module Pack
To view the available module-packs, type the following command inside the sdkadm tool:
list-modules +module-pack
Where you see a version number of 4.1.0 use the version number of the product you have downloaded. |
Now create a new module from the module pack published in opencloud#sentinel-diameter-cdr-mappers#sentinel-diameter/4.1;4.1.0
. This requires two steps:
1 |
Run the command: create-module acme-diameter-cdr-mappers opencloud#sentinel-diameter-cdr-mappers#sentinel-diameter/4.1;4.1.0 This command:
When prompted, answer as shown in the example output below. Numbered annotations mark the prompts, and their answers are listed by number immediately after the example output. > create-module acme-diameter-cdr-mappers opencloud#sentinel-diameter-cdr-mappers#sentinel-diameter/4.1;4.1.0 downloading https://repo.rhino.metaswitch.com/artifactory/opencloud-internal-snapshots/opencloud/sentinel-diameter/4.1/sentinel-diameter-cdr-mappers/4.1.0/sentinel-diameter-cdr-mappers-module-pack-4.1.0.zip ... ... (18kB) .. (0kB) [SUCCESSFUL ] opencloud#sentinel-diameter-cdr-mappers#sentinel-diameter/4.1;4.1.0!sentinel-diameter-cdr-mappers-module-pack.zip(module-pack) (81ms) Extracting '/home/testuser/sentinel-express-sdk/build/target/ivy-caches/online-resolvers.cache/opencloud/sentinel-diameter-cdr-mappers/sentinel-diameter/4.1/module-packs/sentinel-diameter-cdr-mappers-module-pack-4.1.0.zip' to '/home/testuser/sentinel-express-sdk/acme-diameter-cdr-mappers'. Command line invocation did not contain enough rename arguments to rename all modules. To specify rename arguments on the command line, include <oldvalue>:<newvalue> pairs as additional arguments. Missing values will now be prompted for interactively. Please enter a name for the top level module, usually this will match the name of the directory for the new module Rename top level module 'sentinel-diameter-cdr-mappers' to [acme-diameter-cdr-mappers]: Please enter names for the following sub-module(s) in the module-pack Rename module 'sentinel-diameter-cdr-format' to [sentinel-diameter-cdr-format]: acme-diameter-cdr-format The longest common package prefix is 'com.opencloud.sentinel'. Rename package prefix 'com.opencloud.sentinel' to [com.opencloud.sentinel]: com.acme.sentinel Command line invocation did not contain enough rename arguments to rename all mappers. To specify rename arguments on the command line, include <oldvalue>:<newvalue> pairs as additional arguments. Missing values will now be prompted for interactively. Rename mapper 'CCRToCDR' to [CCRToCDR]: AcmeCCRToCDR Re-writing source files with new package declarations. Renaming ivy modules and updating dependencies. Renaming symbolic property references in source files. Checking "deps.properties" for missing values. Done. New module(s) should now be available at: /home/testuser/sentinel-express-sdk/acme-diameter-cdr-mappers
|
---|
Adding Fields to Sentinel CDRs
Below are instructions for Extending Google protocol buffers, Defining your own fields and Using your fields in CDR mappers.
Extending Google protocol buffers
Google protocol buffers may be extended with additional fields, without prior knowledge, by using the protocol buffer extensions mechanism.
Extensions let you declare that a range of field numbers in a message are available for third-party extensions. Other people can then declare new fields for your message type with those numeric tags in their own .proto files without having to edit the original file.
The Sentinel protocol buffer CDR definitions define a range of field numbers for extensions.
-
The CDR
.proto
files for Diameter are artifacts of thesentinel-diameter-cdr-format
module. -
The CDR
.proto
files for SS7 are artifacts of thesentinel-ss7-cdr-format
module.
Here is an excerpt from the Diameter sentinel-diameter-cdr-format.proto
file:
package com.opencloud.sentinel.cdr;
message DiameterChargingCdr {
// ...
extensions 50 to max;
So field numbers 50 (and above) may be used for your extensions.
Defining your own fields
After creating a module from sentinel-diameter-cdr-mappers
or
sentinel-ss7-cdr-mappers
you can add any CDR fields in the
acme-diameter-cdr-format
and acme-ss7-cdr-format
*.proto
files.
package com.acme.sentinel.cdr;
import "com/opencloud/sentinel/cdr/base-cdr-types.proto";
// Diameter Service CDR
message DiameterChargingCdr {
optional string subscriber = 1;
optional int64 initiatingRequestId = 2 [default = -1];
optional com.opencloud.sentinel.cdr.Time eventInitiated = 3;
optional com.opencloud.sentinel.cdr.Time sessionInitiated = 4;
optional com.opencloud.sentinel.cdr.Time sessionEnded = 5;
optional com.opencloud.sentinel.cdr.CdrSessionCounters sessionCounters = 6;
repeated int32 ocsLatencySamples = 19 [packed=true];
optional string clientSessionId = 20;
repeated string ocsSessionIDs = 21;
optional string sentinelSelectionKey = 22;
optional ReleaseReason releaseReason = 23;
extensions 50 to max;
message ReleaseReason {
optional string cause = 1;
optional string description = 2;
}
}
Here we define a structure for the ReleaseReason
that has two fields, a
cause
and a description
. One of the artifacts generated by the
acme-diameter-cdr-format
module is acme-diameter-cdr-format.jar
, which
contains the compiled code generated by the Google protobuf compiler for your
fields.
Using your fields in CDR mappers
Sentinel provides a number of Mappers
for generating CDRs. These mappers can
be extended by the SDK to include any additional fields you have defined. The
Sentinel SDK includes mapper modules for Diameter and SS7, which lets you
extend existing mappers. These modules include custom mapper implementations
for adding support for your own fields.
In the acme-diameter-cdr-mappers
module see:
-
com.acme.sentinel.cdr.mapper.CCRtoCDR
In the acme-ss7-cdr-mappers
module see:
-
com.acme.sentinel.cdr.mapper.CAP1InitialDPArgToCdr
-
com.acme.sentinel.cdr.mapper.CAP3InitialDPSMSArgToCdr
-
com.acme.sentinel.cdr.mapper.CS1InitialDPArgToCdr
-
com.acme.sentinel.cdr.mapper.DialogOpenRequestEventToCdr
-
com.acme.sentinel.cdr.mapper.EventTypeBCSMToCdrConnectCause
-
com.acme.sentinel.cdr.mapper.HttpRequestToSS7CallCdr
Each mapper defines a protected method you override to add your own mapping behaviour. For example, to add the release cause and description to the CDR in the Diameter service update the AcmeCCRtoCDR
mapper like this:
/**
* Add extensions to the generated CDR
*
* @param cdrBuilder the protobuf builder for the CDR
* @param intiatingCCR the CCR that initiated the session
* @param ss the sentinel session state
* @param facilities facilities for tracing and so on
*/
protected void addCdrExtensions(DiameterChargingCdr.Builder cdrBuilder, CreditControlRequest intiatingCCR, SentinelDiameterSessionState ss, MapperFacilities facilities) throws MapperException {
// to be overridden by SDK defined mappers
// get values to include from session state
final String releaseCause = "extensionReleaseCause";
final String releaseDescription = "extensionReleaseDescription";
DiameterChargingCdr.ReleaseReason.Builder rrBuilder = DiameterChargingCdr.ReleaseReason.newBuilder();
// construct ReleaseReason field for the CDR
rrBuilder.setCause(releaseCause);
rrBuilder.setDescription(releaseDescription);
cdrBuilder.setReleaseReason(rrBuilder.build());
}
Creating your own CDRs
To create your your own CDRs you:
Write your own CDR protobuf definition
-
Refer to the Google protobuf documentation to learn how to use protobuf and write your own protobuf CDR definition.
You can also refer to the following Sentinel protobuf artifacts for inspiration:
-
In the
acme-diameter-cdr-format
module:
target/libs/self/sentinel-cdr-common-base-cdr-types-*.proto
src/com/acme/sentinel/cdr/sentinel-diameter-cdr-format.proto
-
In the
acme-ss7-cdr-format
module:
target/libs/self/sentinel-cdr-common-base-cdr-types-*.proto
src/com/acme/sentinel/cdr/sentinel-ss7-cdr-format-*.proto
src/com/acme/sentinel/cdr/sentinel-ss7-sms-cdr-format-*.proto
The simplest approach is to update the *.proto
file in the com.acme.sentinel.cdr
package. Remove the import statement (that corresponds to the Sentinel core CDR format) and create your own protobuf definition. If you adopt this approach then you do not need to change build.xml
or change any dependencies.
Write your own CDR mappers
As mentioned in Using your fields in CDR mappers, each mappers module in the SDK includes custom CDR mapper implementations for adding support for your own fields. You can edit these mappers by:
-
removing the extends clause
-
implement the
Mapper
interface directly
For example, in the acme-ss7-mappers
module:
/**
* Copyright (c) 2014 Open Cloud Limited, a company incorporated in England and Wales (Registration Number 6000941) with its principal place of business at Edinburgh House, St John's Innovation Park, Cowley Road, Cambridge CB4 0DS.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* 3 The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
*
* 4 The source code may not be used to create, develop, use or distribute software for use on any platform other than the Open Cloud Rhino and Open Cloud Rhino Sentinel platforms or any successor products.
*
* 5 Full license terms may be found https://developer.opencloud.com/devportal/display/OCDEV/Feature+Source+License
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXCLUDED TO THE FULLEST EXTENT PERMITTED BY LAW.
*
* TO THE FULLEST EXTENT PERMISSIBLE BY LAW, THE AUTHOR SHALL NOT BE LIABLE FOR ANY LOSS OF REVENUE, LOSS OF PROFIT, LOSS OF FUTURE BUSINESS, LOSS OF DATA OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, PUNITIVE OR OTHER LOSS OR DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE, WHETHER ARISING IN CONTRACT, TORT (INCLUDING NEGLIGENCE) MISREPRESENTATION OR OTHERWISE AND REGARDLESS OF WHETHER OPEN CLOUD HAS BEEN ADVISED OF THE POSSIBILITY OF ANY SUCH LOSS OR DAMAGE. THE AUTHORS MAXIMUM AGGREGATE LIABILITY WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, SHALL NOT EXCEED EUR100.
*
* NOTHING IN THIS LICENSE SHALL LIMIT THE LIABILITY OF THE AUTHOR FOR DEATH OR PERSONAL INJURY RESULTING FROM NEGLIGENCE, FRAUD OR FRAUDULENT MISREPRESENTATION.
*
* Visit Open Cloud Developer's Portal for how-to guides, examples, documentation, forums and more: http://developer.opencloud.com
*/
package com.opencloud.sentinel.cdr.mapper.impl;
import com.google.protobuf.Message;
import com.opencloud.sentinel.annotations.Mapping;
import com.opencloud.sentinel.annotations.SentinelMapper;
import com.opencloud.sentinel.cdr.SentinelSs7CdrFormat.Ss7CallCdr;
import com.opencloud.sentinel.common.SentinelSs7SessionState;
import com.opencloud.sentinel.mapper.MapperException;
import com.opencloud.sentinel.mapper.MapperFacilities;
import com.opencloud.sentinel.util.LongByteArray;
import com.opencloud.slee.resources.cgin.callcontrol.CCCallInformationReportArg;
import com.opencloud.slee.resources.cgin.cap_v1.CAP1InitialDPArg;
import com.opencloud.slee.resources.cgin.cap_v2.CAP2CallInformationReportArg;
import com.opencloud.slee.resources.cgin.cap_v2.CAP2InitialDPArg;
import com.opencloud.slee.resources.cgin.cap_v3.CAP3InitialDPArg;
import com.opencloud.slee.resources.cgin.cap_v4.CAP4InitialDPArg;
import com.opencloud.slee.resources.in.datatypes.cc.LegType.EncodedValue;
/**
* Maps {@link com.opencloud.slee.resources.cgin.cap_v1.CAP1InitialDPArg}, {@link com.opencloud.slee.resources.cgin.cap_v2.CAP2InitialDPArg}, {@link com.opencloud.slee.resources.cgin.cap_v3.CAP3InitialDPArg} or {@link com.opencloud.slee.resources.cgin.cap_v4.CAP4InitialDPArg} to
* a google protobuf {@link com.google.protobuf.Message}.
*/
@SentinelMapper(mappings = { @Mapping(name = "CAP1InitialDPArgToCdr", fromClass = CAP1InitialDPArg.class, toClass = Message.class),
@Mapping(name = "CAP2InitialDPArgToCdr", fromClass = CAP2InitialDPArg.class, toClass = Message.class),
@Mapping(name = "CAP3InitialDPArgToCdr", fromClass = CAP3InitialDPArg.class, toClass = Message.class),
@Mapping(name = "CAP4InitialDPArgToCdr", fromClass = CAP4InitialDPArg.class, toClass = Message.class) })
public class CAP1InitialDPArgToCdr extends BaseCCInitialDPArgToCdr {
@Override
public Object map(Object arg, SentinelSs7SessionState sessionState, MapperFacilities facilities) throws MapperException {
final Ss7CallCdr.Builder cdrBuilder = map(sessionState, facilities);
final CAP1InitialDPArg idp = (CAP1InitialDPArg) arg;
// This method on the super class fills in all builder fields which are common to both CS1 and CAP
populateCommonCDRFields(idp, sessionState, facilities, cdrBuilder);
//
// CAP specific logic start here.
//
// Called Party Number
switch (sessionState.getCallType()) {
case MobileOriginating:
case EmergencyCall:
case NetworkInitiated:
if (idp.hasCalledPartyBCDNumber())
cdrBuilder.setCalledPartyNumber(idp.getCalledPartyBCDNumber().getAddress());
break;
default:
if (idp.hasCalledPartyNumber())
cdrBuilder.setCalledPartyNumber(idp.getCalledPartyNumber().getAddress());
}
// MSC address
if (idp.hasMscAddress())
cdrBuilder.setMscNumber(idp.getMscAddress().getAddress());
// Tele or Bearer Service
if (idp.hasExt_basicServiceCode() && idp.getExt_basicServiceCode().isExt_TeleserviceChosen())
cdrBuilder.setTeleService(idp.getExt_basicServiceCode().getExt_Teleservice()[0]);
if (idp.hasExt_basicServiceCode() && idp.getExt_basicServiceCode().isExt_BearerServiceChosen())
cdrBuilder.setBearerService(idp.getExt_basicServiceCode().getExt_BearerService()[0]);
// Event initiated time - time event emitted by client (in this case idp.TimeAndTimezone)
if (idp instanceof CAP2InitialDPArg) {
CAP2InitialDPArg cap2idp = (CAP2InitialDPArg) idp;
if (cap2idp.hasTimeAndTimezone()) {
cdrBuilder.setEventInitiated(getCdrTime(cap2idp.getTimeAndTimezone().toCalendar().getTimeInMillis(), cap2idp.getTimeAndTimezone().toCalendar().getTimeZone()));
}
}
// Call reference number
if (idp.hasCallReferenceNumber())
cdrBuilder.setCallReferenceNumber(LongByteArray.getLongVal(idp.getCallReferenceNumber()));
// add any extensions to the CDR
addCdrExtensions(cdrBuilder, idp, sessionState, facilities);
return cdrBuilder.build();
}
/**
* Add extensions to the generated CDR
*
* @param cdrBuilder the protobuf builder for the CDR
* @param idp the InitialDP that initiated the session
* @param ss the sentinel session state
* @param facilities facilities for tracing and so on
*/
protected void addCdrExtensions(Ss7CallCdr.Builder cdrBuilder, CAP1InitialDPArg idp, SentinelSs7SessionState ss, MapperFacilities facilities) throws MapperException {
// to be overridden by SDK defined mappers
}
@Override
protected EncodedValue getLegType(CCCallInformationReportArg cirp) {
if (cirp instanceof CAP2CallInformationReportArg)
return ((CAP2CallInformationReportArg) cirp).getLegID().getReceivingSideID().getEncodedValue();
// Assume called party leg for CS1 as the report is comparable to CAMEL's report for this leg
return EncodedValue.CALLED_PARTY;
}
}