Skip to content

Instantly share code, notes, and snippets.

@razvancrainea
Last active July 18, 2021 07:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save razvancrainea/dbc19ea779bca5bc2852374e851026f3 to your computer and use it in GitHub Desktop.
Save razvancrainea/dbc19ea779bca5bc2852374e851026f3 to your computer and use it in GitHub Desktop.
ClueCon TGI2021: Configs for Quality Based Routing statistics
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": 1,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 6,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "7.4.0",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "CALLS",
"hide": true,
"interval": "",
"legendFormat": "CALLS Total",
"refId": "A"
},
{
"expr": "CALLS_GW0",
"hide": false,
"interval": "",
"legendFormat": "CALLS GW0",
"refId": "B"
},
{
"expr": "CALLS_GW1",
"hide": false,
"interval": "",
"legendFormat": "CALLS GW1",
"refId": "C"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Total number of calls",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"hiddenSeries": false,
"id": 2,
"interval": "10",
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"maxDataPoints": null,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "7.4.0",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "PDD",
"interval": "",
"legendFormat": "PDD AVG",
"refId": "A"
},
{
"expr": "PDD_GW0",
"hide": false,
"interval": "",
"legendFormat": "PDD GW0",
"refId": "B"
},
{
"expr": "PDD_GW1",
"hide": false,
"interval": "",
"legendFormat": "PDD GW1",
"refId": "C"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "PDD - Post Dial Delay",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"description": "",
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 8
},
"hiddenSeries": false,
"id": 10,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "7.4.0",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "CCR",
"interval": "",
"legendFormat": "CCR AVG",
"refId": "A"
},
{
"expr": "CCR_GW0",
"hide": false,
"interval": "",
"legendFormat": "CCR GW0",
"refId": "B"
},
{
"expr": "CCR_GW1",
"hide": false,
"interval": "",
"legendFormat": "CCR GW1",
"refId": "C"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "CCR - Call Completion Ratio",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 8
},
"hiddenSeries": false,
"id": 12,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "7.4.0",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"exemplar": false,
"expr": "AST",
"hide": false,
"interval": "",
"legendFormat": "AST AVG",
"refId": "A"
},
{
"expr": "AST_GW0",
"hide": false,
"interval": "",
"legendFormat": "AST GW0",
"refId": "B"
},
{
"expr": "AST_GW1",
"hide": false,
"instant": false,
"interval": "",
"legendFormat": "AST GW1",
"refId": "C"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "AST - Average Setup Time",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"description": "",
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 16
},
"hiddenSeries": false,
"id": 8,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "7.4.0",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "ASR",
"interval": "",
"legendFormat": "ASR AVG",
"refId": "A"
},
{
"expr": "ASR_GW0",
"hide": false,
"interval": "",
"legendFormat": "ASR GW0",
"refId": "B"
},
{
"expr": "ASR_GW1",
"hide": false,
"interval": "",
"legendFormat": "ASR GW1",
"refId": "C"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "ASR - Answer Seizure Ratio",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"description": "",
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 16
},
"hiddenSeries": false,
"id": 4,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "7.4.0",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "ACD",
"interval": "",
"legendFormat": "ACD AVG",
"refId": "A"
},
{
"expr": "ACD_GW0",
"hide": false,
"interval": "",
"legendFormat": "ACD GW0",
"refId": "B"
},
{
"expr": "ACD_GW1",
"hide": false,
"interval": "",
"legendFormat": "ACD GW1",
"refId": "C"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "ACD - Average Call Duration",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
}
],
"refresh": "10s",
"schemaVersion": 27,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-5m",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "ClueCon TGI2021",
"uid": "yGBd6ZPMk",
"version": 3
}
#
# OpenSIPS loadbalancer script
# by OpenSIPS Solutions <team@opensips-solutions.com>
#
# This script was generated via "make menuconfig", from
# the "Load Balancer" scenario.
# You can enable / disable more features / functionalities by
# re-generating the scenario with different options.
#
# Please refer to the Core CookBook at:
# https://opensips.org/Resources/DocsCookbooks
# for a explanation of possible statements, functions and parameters.
#
####### Global Parameters #########
/* uncomment the following lines to enable debugging */
#debug_mode=yes
log_level=3
xlog_level=3
log_stderror=no
log_facility=LOG_LOCAL0
udp_workers=10
/* uncomment the next line to enable the auto temporary blacklisting of
not available destinations (default disabled) */
#disable_dns_blacklist=no
/* uncomment the next line to enable IPv6 lookup after IPv4 dns
lookup failures (default disabled) */
#dns_try_ipv6=yes
socket=udp:eth1:5060
####### Modules Section ########
#set module path
mpath="/usr/lib/x86_64-linux-gnu/opensips/modules/"
#mpath="modules/"
#### SIGNALING module
loadmodule "signaling.so"
#### StateLess module
loadmodule "sl.so"
#### Transaction Module
loadmodule "tm.so"
modparam("tm", "fr_timeout", 5)
modparam("tm", "fr_inv_timeout", 30)
modparam("tm", "restart_fr_on_each_reply", 0)
modparam("tm", "onreply_avp_mode", 1)
#### Record Route Module
loadmodule "rr.so"
/* do not append from tag to the RR (no need for this script) */
modparam("rr", "append_fromtag", 0)
#### MAX ForWarD module
loadmodule "maxfwd.so"
#### SIP MSG OPerationS module
loadmodule "sipmsgops.so"
#### FIFO Management Interface
loadmodule "mi_fifo.so"
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)
#### MYSQL module
loadmodule "db_mysql.so"
#### AVPOPS module
loadmodule "avpops.so"
#### EVENT ROUTE module
loadmodule "event_route.so"
#### ACCounting module
loadmodule "acc.so"
/* what special events should be accounted ? */
modparam("acc", "early_media", 0)
modparam("acc", "report_cancels", 0)
/* by default we do not adjust the direct of the sequential requests.
if you enable this parameter, be sure to enable "append_fromtag"
in "rr" module */
modparam("acc", "detect_direction", 0)
modparam("acc", "extra_fields","evi: gw")
#### STATS: define the series profiles ####
#### STATISTICS module
loadmodule "statistics.so"
modparam("statistics", "stat_series_profile", "perc: algorithm=percentage window=30 group=stats")
modparam("statistics", "stat_series_profile", "avg: algorithm=average window=30 group=stats")
modparam("statistics", "stat_series_profile", "acc: algorithm=accumulate window=30 group=stats")
#### STATS ###
#### ConFiG module
loadmodule "cfgutils.so"
#### PROM: load the rest client ####
#### REST CLIENT module
loadmodule "rest_client.so"
#### PROM ####
#### DIALOG module
loadmodule "dialog.so"
modparam("dialog", "dlg_match_mode", 1)
modparam("dialog", "default_timeout", 21600) # 6 hours timeout
modparam("dialog", "db_mode", 2)
modparam("dialog", "db_url",
"mysql://opensips:opensipsrw@localhost/opensips")
#### DYNAMIC ROUTING module
loadmodule "drouting.so"
modparam("drouting", "db_url",
"mysql://opensips:opensipsrw@localhost/opensips")
modparam("drouting", "gw_id_avp", '$avp(gw_id)')
modparam("drouting", "rule_id_avp", '$avp(rule_id)')
#### QBR: load the module and define params ####
#### QUALITY ROUTING module
loadmodule "qrouting.so"
modparam("qrouting", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
# for fast testing
modparam("qrouting", "sampling_interval", 2)
modparam("qrouting", "min_samples_asr", 0)
modparam("qrouting", "min_samples_ccr", 0)
modparam("qrouting", "min_samples_pdd", 0)
modparam("qrouting", "min_samples_ast", 0)
modparam("qrouting", "min_samples_acd", 0)
modparam("qrouting", "decimal_digits", 3)
#### QBR ####
#### MOS: define the extra routing ####
modparam("qrouting", "extra_stats", "+mos/1")
#### MOS ####
loadmodule "proto_udp.so"
####### Routing Logic ########
# main request routing logic
route{
if ($si != $socket_in(ip)) {
# only allowing traffic from the same host
exit;
}
if (!mf_process_maxfwd_header(10)) {
send_reply(483,"Too Many Hops");
exit;
}
if (has_totag()) {
# handle hop-by-hop ACK (no routing required)
if ( is_method("ACK") && t_check_trans() ) {
t_relay();
exit;
}
# sequential request withing a dialog should
# take the path determined by record-routing
if ( !loose_route() ) {
# we do record-routing for all our traffic, so we should not
# receive any sequential requests without Route hdr.
send_reply(404,"Not here");
exit;
}
# validate the sequential request against dialog
if ( $DLG_status!=NULL && !validate_dialog() ) {
xlog("[$ci][main] in-dialog $rm from $si is not valid according to dialog\n");
## exit;
}
if (is_method("BYE"))
t_on_reply("get_mos");
# route it out to whatever destination was set by loose_route()
# in $du (destination URI).
route(RELAY);
exit;
}
#### INITIAL REQUESTS
# CANCEL processing
if (is_method("CANCEL")) {
if (t_check_trans())
t_relay();
exit;
} else if (!is_method("INVITE")) {
send_reply(405,"Method Not Allowed");
exit;
}
if ($rU==NULL) {
# request with no Username in RURI
send_reply(484,"Address Incomplete");
exit;
}
xlog("[$ci][main] new call to $ru received, doing routing\n");
t_check_trans();
# record routing
record_route();
create_dialog("B");
if (!do_routing(0)) {
send_reply(500,"No PSTN Route found");
exit;
}
$dlg_val(rule_id) = $avp(rule_id);
#### STATS: engage evi CDR events ####
# we're only accouting gateways statistics
do_accounting("evi", "cdr|missed");
# store the moment the call started
get_accurate_time($avp(call_start_s), $avp(call_start_us));
t_on_reply("stats");
$acc_extra(gw) = $avp(gw_id);
route(calculate_stats_calls, "");
$var(suffix) = "_" + $acc_extra(gw);
route(calculate_stats_calls, $var(suffix));
#### STATS ####
xlog("[$ci][main] routing to $acc_extra(gw) @ $rd:$rp\n");
route(RELAY);
}
#### STATS: compute stats routes ####
onreply_route[stats] {
route(calculate_stats_reply, $avp(call_start_s), $avp(call_start_us), "");
$var(suffix) = "_" + $acc_extra(gw);
route(calculate_stats_reply, $avp(call_start_s), $avp(call_start_us), $var(suffix));
}
route[calculate_stats_reply] {
# expects:
# - param 1: timestamp (in seconds) when the initial request was received
# - param 2: timestamp (in microseconds) when the initial request was received
# - param 3: statistic identifier; for global, empty string is used
if ($rs == "180" || $rs == "183" || $rs == "200"
|| $rs == "400" || $rs == "403" || $rs == "408"
|| $rs == "480" || $rs == "487") {
if (!isflagset("FLAG_PDD_CALCULATED")) {
get_accurate_time($var(now_s), $var(now_us));
ts_usec_delta($var(now_s), $var(now_us), $param(1), $param(2), $var(pdd_us));
$var(pdd_ms) = $var(pdd_us) / 1000; # milliseconds
$avp(pdd) = $var(pdd_ms);
setflag("FLAG_PDD_CALCULATED");
} else {
$var(pdd_ms) = $avp(pdd);
}
update_stat_series("avg", "PDD$param(3)", $var(pdd_ms));
}
if ($rs >= 200 && $rs < 300) {
update_stat_series("perc", "ASR$param(3)", 1);
update_stat_series("perc", "NER$param(3)", 1);
update_stat_series("perc", "CCR$param(3)", 1);
get_accurate_time($var(now_s), $var(now_us));
ts_usec_delta($var(now_s), $var(now_us), $param(1), $param(2), $var(ast_us));
$var(ast_us) = $var(ast_us) / 1000; # milliseconds
update_stat_series("avg", "AST$param(3)", $var(ast_us));
}
}
event_route[E_ACC_CDR] {
route(calculate_stats_cdr, $param(duration), $param(setuptime), "");
$var(suffix) = "_" + $param(gw);
route(calculate_stats_cdr, $param(duration), $param(setuptime), $var(suffix));
}
route[calculate_stats_cdr] {
# expects:
# - param 1: duration (in seconds) of the call
# - param 2: setuptime (in seconds) of the call
# - param 3: optional - statistic identifier; global is empty string
$var(total_duration) = $param(1) + $param(2);
update_stat_series("avg", "ACD$param(3)", $var(total_duration));
}
event_route[E_ACC_MISSED_EVENT] {
route(calculate_stats_failure, $param(sip_code), "");
$var(suffix) = "_" + $param(gw);
route(calculate_stats_failure, $param(sip_code), $var(suffix));
}
route[calculate_stats_failure] {
# expects:
# - param 1: failure code
# - param 2: statistic identifier; global is empty string
update_stat_series("perc", "ASR$param(2)", -1);
if ($param(1) == "486") {
update_stat_series("perc", "NER$param(2)", 1);
} else {
update_stat_series("perc", "NER$param(2)", -1);
}
if ($(param(1){s.int}) > 499) {
update_stat_series("perc", "CCR$param(2)", -1);
} else {
update_stat_series("perc", "CCR$param(2)", 1);
}
}
route[calculate_stats_calls] {
# expects:
# - param 1: statistic identifier; global is empty string
update_stat_series("acc", "CALLS$param(1)", 1);
}
#### STATS ####
route[RELAY] {
if (!t_relay()) {
sl_reply_error();
}
exit;
}
#### MOS: push to QBR ####
onreply_route[get_mos] {
if (is_present_hf("X-MOS"))
qr_set_xstat( $(dlg_val(rule_id){s.int}), $acc_extra(gw), "mos", $hdr(X-MOS));
}
#### MOS ####
#### PROM: push statistics to promethus ####
timer_route[stats, 10] {
stat_iter_init("stats", "iter");
while (stat_iter_next($var(stat), $var(val), "iter")) {
rest_post("http://localhost:9091/metrics/job/$var(stat)",
"$var(stat) $var(val)\n",
"application/x-www-form-urlencoded", $var(ret));
}
}
#### PROM ####
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment