Featured image of post opensips acc模块介绍

opensips acc模块介绍

背景

acc 模块用来记录会话信息到syslog,数据库, AAAEVENTS中,do_accounting()函数并不是记录信息,只是标记会话信息,当会话完成时才去记录。

最小的记录信息包括:

  • 请求method
  • From 头的tag
  • To 头的tag
  • Call-ID
  • 响应的code
  • 响应的reason
  • 会话完成的时间戳

官方文档地址: acc,本次测试的opensips版本是:

version: opensips 3.3.10 (x86_64/linux)

重要参数解析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 记录响铃
modparam("acc", "early_media", 1)
# 上报CANCEL消息
modparam("acc", "report_cancels", 1)
# 控制请求方向
modparam("acc", "detect_direction", 1)
# 定义额外的参数
modparam("acc", "extra_fields", "log: a->My_a_Field; b")
# 定义多条腿的参数
modparam("acc", "leg_fields", "log: a->My_a_Field; b")
# 定义日志级别
modparam("acc", "log_level", 2)
# 定义数据表名
modparam("acc", "db_table_acc", "acc")
# 定义失败的数据表名
modparam("acc", "db_table_missed_calls", "missed_calls")
# 数据库地址
modparam("acc", "db_url", "DBURL")

重要函数解析

do_accounting(type, [flags], [table])

  • type: 类型,有以下几种类型:

    • log: syslog
    • db: database
    • aaa: aaa
    • evi: event
  • flags: 标志位,有以下几种标志位:

    • cdr: 记录CDR
    • missed: 记录未接电话
    • failed: 当状态码>=300,记录失败信息
  • table: 数据表名

drop_accounting([type], [flags])

重置flag和types, 参数和do_accounting函数一样。

  • 不带参数时,所有的记录都会停止。
  • 带一个参数时,只会停止指定的类型。
  • 带两个参数时,只会停止指定的类型和标志位。

acc_log_request(comment)

上报请求到日志,comment 必须是带有错误码的字符串,例如:480 NoBody Home

acc_db_request(comment, table)

上报请求到数据库,commentacc_log_request一样

acc_aaa_request(comment)

上报请求到AAA,commentacc_log_request一样

acc_evi_request(comment)

上报请求到EVENTS,commentacc_log_request一样

acc_new_leg()

创建一个新腿,所有的参数为null.

acc_load_ctx_from_dlg()

加载和导出当前在用的dialog的accouting context. 必须和load_dialog_ctx()一起使用

acc_unload_ctx_from_dlg()

卸载accouting context

EVENTS事件

E_ACC_CDR

cdr事件,参数:

  • method
  • from_tag
  • to_tag
  • callid
  • sip_code
  • sip_reason
  • time
  • evi_extra
  • evi_extra_bye
  • multi_leg_info
  • multi_leg_bye_info
  • duration
  • ms_duration
  • setuptime
  • created

E_ACC_EVENT

  • method
  • from_tag
  • to_tag
  • callid
  • sip_code
  • sip_reason
  • time
  • evi_extra
  • multi_leg_info

E_ACC_MISSED_EVENT

  • method
  • from_tag
  • to_tag
  • callid
  • sip_code
  • sip_reason
  • time
  • evi_extra
  • multi_leg_info
  • created
  • setuptime

实战

输出到syslog

使用官方配置:

配置文件

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#
# OpenSIPS residential configuration script
#     by OpenSIPS Solutions <team@opensips-solutions.com>
#
# This script was generated via "make menuconfig", from
#   the "Residential" 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=4

/* 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:172.16.4.111:5261   # CUSTOMIZE ME



####### Modules Section ########

#set module path
mpath="/usr/local/lib/opensips/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", "/run/opensips/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)

#### USeR LOCation module
loadmodule "usrloc.so"
modparam("usrloc", "nat_bflag", "NAT")
modparam("usrloc", "working_mode_preset", "single-instance-no-db")

#### REGISTRAR module
loadmodule "registrar.so"
modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT")
/* uncomment the next line not to allow more than 10 contacts per AOR */
#modparam("registrar", "max_contacts", 10)

#### ACCounting module
loadmodule "acc.so"
/* what special events should be accounted ? */
modparam("acc", "early_media", 1)
modparam("acc", "report_cancels", 1)
/* 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", "log: a->$ci; b")
loadmodule "proto_udp.so"

####### Routing Logic ########

# main request routing logic

route{

	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 within 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;
		}

		if (is_method("BYE")) {
			# do accounting even if the transaction fails
			do_accounting("log","failed");
		}

		# route it out to whatever destination was set by loose_route()
		# in $du (destination URI).
		route(relay);
		exit;
	}

	# CANCEL processing
	if (is_method("CANCEL")) {
		if (t_check_trans())
			t_relay();
		exit;
	}

	# absorb retransmissions, but do not create transaction
	t_check_trans();

	if ( !(is_method("REGISTER")  ) ) {
		
		if (is_myself("$fd")) {
					
		} else {
			# if caller is not local, then called number must be local
			
			if (!is_myself("$rd")) {
				send_reply(403,"Relay Forbidden");
				exit;
			}
		}

	}

	# preloaded route checking
	if (loose_route()) {
		xlog("L_ERR",
			"Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]");
		if (!is_method("ACK"))
			send_reply(403,"Preload Route denied");
		exit;
	}

	# record routing
	if (!is_method("REGISTER|MESSAGE"))
		record_route();

	# account only INVITEs
	if (is_method("INVITE")) {
		
		do_accounting("log");
        $acc_extra(a)=$ci;
	}

	
	if (!is_myself("$rd")) {
		append_hf("P-hint: outbound\r\n"); 
		
		route(relay);
	}

	# requests for my domain
	
	if (is_method("PUBLISH|SUBSCRIBE")) {
		send_reply(503, "Service Unavailable");
		exit;
	}

	if (is_method("REGISTER")) {
		# store the registration and generate a SIP reply
		if (!save("location"))
			xlog("failed to register AoR $tu\n");

		exit;
	}

	if ($rU==NULL) {
		# request with no Username in RURI
		send_reply(484,"Address Incomplete");
		exit;
	}

	# do lookup with method filtering
	if (!lookup("location","m")) {
		t_reply(404, "Not Found");
		exit;
	}

	# when routing via usrloc, log the missed calls also
	do_accounting("log","missed");
	route(relay);
}


route[relay] {
	# for INVITEs enable some additional helper routes
	if (is_method("INVITE")) {
		t_on_branch("per_branch_ops");
		t_on_reply("handle_nat");
		t_on_failure("missed_call");
	}

	if (!t_relay()) {
		send_reply(500,"Internal Error");
	}
	exit;
}




branch_route[per_branch_ops] {
	xlog("new branch at $ru\n");
}


onreply_route[handle_nat] {
	xlog("incoming reply\n");
}


failure_route[missed_call] {
	if (t_was_cancelled()) {
		exit;
	}

	# uncomment the following lines if you want to block client 
	# redirect based on 3xx replies.
	##if (t_check_status("3[0-9][0-9]")) {
	##t_reply(404,"Not found");
	##	exit;
	##}

	
}

配置文件解析:

modparam("acc", "extra_fields", "log: a->$ci; b"), 这里只是定义了akey$ci, 要使用$acc_extra(a)来设置value。通过这种方式,我们可以设置一些额外的参数输出到日志中。

输出的结果

  1. 正常接通挂断

sip信令图: sip

syslog输出:

1
2
3
4
5
6
7
May 13 10:07:20 [349] [130][23d4df0d6efe4cd481a6f4e29ca82f9b]---main--:INVITE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:07:22 [352] ACC: transaction answered: timestamp=1747102042;created=0;setuptime=1747102042;method=INVITE;from_tag=e2ff73efbd8242208c88592bda1d8d02;to_tag=06127b55;call_id=23d4df0d6efe4cd481a6f4e29ca82f9b;code=200;reason=OK;$ci=23d4df0d6efe4cd481a6f4e29ca82f9b;b=
May 13 10:07:22 [352] [130][23d4df0d6efe4cd481a6f4e29ca82f9b]---main--:ACK|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:07:22 [351] [130][23d4df0d6efe4cd481a6f4e29ca82f9b]---main--:INVITE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:07:22 [352] [130][23d4df0d6efe4cd481a6f4e29ca82f9b]---main--:ACK|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:07:24 [353] [130][23d4df0d6efe4cd481a6f4e29ca82f9b]---main--:BYE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:07:24 [351] ACC: transaction answered: timestamp=1747102044;created=0;setuptime=1747102044;method=BYE;from_tag=e2ff73efbd8242208c88592bda1d8d02;to_tag=06127b55;call_id=23d4df0d6efe4cd481a6f4e29ca82f9b;code=200;reason=OK;$ci=;b=

使用官方的配置,可以看到只有两个记录了INVITEBYE,没有响铃。另外,在BYE时,$acc_extra(a)的值为空。

现在修改INVITE处的do_accounting("log");do_accounting("log", "cdr|missed|failed");,再次测试,syslog输出如下:

1
2
3
4
5
6
7
May 13 10:36:06 [535] NOTICE:signaling:mod_init: initializing module ...
May 13 10:36:14 [550] [132][ec40d522330f4171866f26f9bd1a1499]---main--:INVITE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:36:15 [550] [132][ec40d522330f4171866f26f9bd1a1499]---main--:ACK|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:36:15 [550] [132][ec40d522330f4171866f26f9bd1a1499]---main--:INVITE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:36:15 [550] [132][ec40d522330f4171866f26f9bd1a1499]---main--:ACK|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:36:17 [550] [132][ec40d522330f4171866f26f9bd1a1499]---main--:BYE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:36:17 [553] ACC: call ended: created=1747103774;call_start_time=1747103775;duration=3;ms_duration=2455;setuptime=1;method=INVITE;from_tag=82c34d97660b4e6fb6c1d8ccf04c194d;to_tag=7f0a2548;call_id=ec40d522330f4171866f26f9bd1a1499;code=200;reason=OK;$ci=ec40d522330f4171866f26f9bd1a1499;b=

只有一个记录,但是带了其他信息:call_start_time:电话接通的时间戳、duration:通话时长s、ms_duration:通话时长ms,setuptime:电话建立的时间,可以认为是响铃时长s,created:此记录开始的时间.

  1. 未接电话

sip信令图: sip

syslog输出:

1
2
3
4
May 13 10:50:51 [622] [132][67abdb49d25f4d579670b78b56d4f0a3]---main--:INVITE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:50:52 [622] ACC: call missed: timestamp=1747104652;created=1747104651;setuptime=1;method=INVITE;from_tag=2cf172b645e04628a1ace902e877512b;to_tag=7f10ee66;call_id=67abdb49d25f4d579670b78b56d4f0a3;code=480;reason=Temporarily Unavailable;$ci=67abdb49d25f4d579670b78b56d4f0a3;b=
May 13 10:50:52 [622] [312][67abdb49d25f4d579670b78b56d4f0a3]---missed_call----:INVITE|<null>|sip:1009@172.16.4.111|5261
May 13 10:50:52 [622] [132][67abdb49d25f4d579670b78b56d4f0a3]---main--:ACK|<null>|sip:1009@172.16.4.111|5261|<null>

可以看到记录了missed_call

  1. 主叫CANCEL

sip信令图: sip

syslog输出:

1
2
3
4
May 13 10:57:39 [685] [132][7b53a5cf8c9741db9eccc429e719a7b1]---main--:CANCEL|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 10:57:39 [686] ACC: call missed: timestamp=1747105059;created=1747105057;setuptime=2;method=INVITE;from_tag=52d3da242e4f47e0ab21cbb95afc715c;to_tag=8f3e627c;call_id=7b53a5cf8c9741db9eccc429e719a7b1;code=487;reason=Request Terminated;$ci=7b53a5cf8c9741db9eccc429e719a7b1;b=
May 13 10:57:39 [686] [312][7b53a5cf8c9741db9eccc429e719a7b1]---missed_call----:INVITE|<null>|sip:1009@172.16.4.111|5261
May 13 10:57:39 [685] [132][7b53a5cf8c9741db9eccc429e719a7b1]---main--:ACK|<null>|sip:1009@172.16.4.111|5261|<null>

可以看到记录了missed_call, 但是应该是487信令的,而不是CANCEL.

输出到数据库

配置文件

在syslog输出的基础上,修改配置文件:

1
2
modparam("acc", "extra_fields", "log: a->$ci; b")
modparam("acc", "db_url", "DBURL")

把所有的do_accounting("log","xxx")改成do_accounting("log|db","xxx"),再次测试。

输出的结果

  1. 正常接通挂断

数据表记录: db

相对于kamailio,opensips的数据库记录更加详细,把CDR的信息一起记录到了acc表。

  1. 未接电话

数据表记录: db

数据记录在missed_call

  1. 主叫CANCEL

数据表记录: db

数据记录在missed_call

输出到EVENTS

配置文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
loadmodule "event_route.so"

...
event_route[E_ACC_CDR]{
        xlog("L_DBG","[$cfg_line]---event_route[E_ACC_CDR]----:$param(method)|$param(from_tag)|$param(to_tag)|$param(callid)|$param(sip_code)|$param(sip_reason)|$param(time)|$param(duration)|$param(ms_duration)|$param(created)|$param(setuptime)\n");

}

event_route[E_ACC_EVENT]{
        xlog("L_DBG","[$cfg_line]---event_route[E_ACC_EVENT]----:$param(method)|$param(from_tag)|$param(to_tag)|$param(callid)|$param(sip_code)|$param(sip_reason)|$param(time)\n");
}


event_route[E_ACC_MISSED_EVENT]{
        xlog("L_DBG","[$cfg_line]---event_route[E_ACC_MISSED_EVENT]----:$param(method)|$param(from_tag)|$param(to_tag)|$param(callid)|$param(sip_code)|$param(sip_reason)|$param(time)|$param(created)|$param(setuptime)\n");
}

do_accounting("log|db","xxxx"); 全部替换为do_accounting("log|db|evi","xxxx");

输出结果

  1. 正常接通挂断

event_route输出:

1
2
3
4
5
6
7
May 13 11:42:32 [959] [137][8b8ae3d6728a4b04bf6875f005730039]---main--:INVITE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 11:42:33 [959] [137][8b8ae3d6728a4b04bf6875f005730039]---main--:ACK|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 11:42:33 [961] [137][8b8ae3d6728a4b04bf6875f005730039]---main--:INVITE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 11:42:34 [957] [137][8b8ae3d6728a4b04bf6875f005730039]---main--:ACK|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 11:42:36 [959] [137][8b8ae3d6728a4b04bf6875f005730039]---main--:BYE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 11:42:36 [959] ACC: call ended: created=1747107752;call_start_time=1747107753;duration=3;ms_duration=2446;setuptime=1;method=INVITE;from_tag=5af280175d2f4bb8b32d883e3286cc4a;to_tag=897c787b;call_id=8b8ae3d6728a4b04bf6875f005730039;code=200;reason=OK;$ci=8b8ae3d6728a4b04bf6875f005730039;b=
May 13 11:42:36 [957] [333]---event_route[E_ACC_CDR]----:INVITE|5af280175d2f4bb8b32d883e3286cc4a|897c787b|8b8ae3d6728a4b04bf6875f005730039|200|OK|1747107753|3|2446|1747107752|1

可以看到在E_ACC_CDR的信息和syslog的一致.

  1. 未接电话

event_route输出:

1
2
3
4
5
May 13 11:45:40 [959] [137][cfb5b5aa7a4f4ed081ced6764ae58867]---main--:INVITE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 11:45:43 [959] [343]---event_route[E_ACC_MISSED_EVENT]----:INVITE|67c43acbbb68485e8437d660ab210df3|ba1cbf25|cfb5b5aa7a4f4ed081ced6764ae58867|480|Temporarily Unavailable|1747107943|1747107940|3
May 13 11:45:43 [958] ACC: call missed: timestamp=1747107943;created=1747107940;setuptime=3;method=INVITE;from_tag=67c43acbbb68485e8437d660ab210df3;to_tag=ba1cbf25;call_id=cfb5b5aa7a4f4ed081ced6764ae58867;code=480;reason=Temporarily Unavailable;$ci=cfb5b5aa7a4f4ed081ced6764ae58867;b=
May 13 11:45:43 [958] [317][cfb5b5aa7a4f4ed081ced6764ae58867]---missed_call----:INVITE|<null>|sip:1009@172.16.4.111|5261
May 13 11:45:43 [957] [137][cfb5b5aa7a4f4ed081ced6764ae58867]---main--:ACK|<null>|sip:1009@172.16.4.111|5261|<null>

可以看到数据输出到E_ACC_MISSED_EVENT, 在E_ACC_MISSED_EVENT的信息和syslog的一致.

  1. 主叫CANCEL

event_route输出:

1
2
3
4
5
6
May 13 11:46:47 [958] [137][df003e31dace43b298e30ef175d99343]---main--:INVITE|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 11:46:48 [957] [137][df003e31dace43b298e30ef175d99343]---main--:CANCEL|<null>|sip:1009@172.16.4.111|5261|<null>
May 13 11:46:49 [957] [343]---event_route[E_ACC_MISSED_EVENT]----:INVITE|bd65219bbfb74f5a859fca3126483d6e|e11fff0b|df003e31dace43b298e30ef175d99343|487|Request Terminated|1747108009|1747108007|2
May 13 11:46:49 [960] ACC: call missed: timestamp=1747108009;created=1747108007;setuptime=2;method=INVITE;from_tag=bd65219bbfb74f5a859fca3126483d6e;to_tag=e11fff0b;call_id=df003e31dace43b298e30ef175d99343;code=487;reason=Request Terminated;$ci=df003e31dace43b298e30ef175d99343;b=
May 13 11:46:49 [960] [317][df003e31dace43b298e30ef175d99343]---missed_call----:INVITE|<null>|sip:1009@172.16.4.111|5261
May 13 11:46:49 [957] [137][df003e31dace43b298e30ef175d99343]---main--:ACK|<null>|sip:1009@172.16.4.111|5261|<null>

可以看到数据输出到E_ACC_MISSED_EVENT, 在E_ACC_MISSED_EVENT的信息和syslog的一致.

总结

  1. opensipsextra_fields设置没有kamailio的方便。
  2. 180响铃,opensipskamailio一样,都未上报,183可能会上报。
  3. 使用数据库时,opensips只用到两个表,kamailio用到了三个表。
  4. opensips的上报方式更丰富些.
最后更新于 2025-05-13
本博客已稳定运行
发表了37篇文章 · 总计67.06k字
本站总访问量 次 · 您是本站第 位访问者
粤ICP备2025368587号-1| 使用 Hugo 构建
主题 StackJimmy 设计