浏览代码

acc_json: adding module

acc in JSON with ouput to syslog and mqueue
Julien Chavanton 7 年之前
父节点
当前提交
a23dedad87

+ 1 - 1
src/Makefile.groups

@@ -21,7 +21,7 @@ mod_list_basic=async auth benchmark blst cfg_rpc cfgutils corex counters \
 mod_list_extra=avp auth_diameter call_control call_obj dmq domainpolicy msrp \
 			     pdb qos sca seas sms sst timer tmrec uac_redirect xhttp \
 				 xhttp_rpc xprint jsonrpcs nosip dmq_usrloc statsd rtjson \
-				 log_custom keepalive ss7ops app_sqlang acc_diameter evrexec
+			  log_custom keepalive ss7ops app_sqlang acc_diameter acc_json evrexec
 
 # - common modules depending on database
 mod_list_db=acc alias_db auth_db avpops cfg_db db_text db_flatstore \

+ 29 - 0
src/modules/acc_json/Makefile

@@ -0,0 +1,29 @@
+# acc module makefile
+#
+#
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=acc_json.so
+LIBS=
+
+ifeq ($(CROSS_COMPILE),)
+JSON_SUPPORTED=$(shell \
+	if pkg-config --exists jansson; then \
+		echo 'libjansson found'; \
+	fi)
+endif
+ifneq ($(JSON_SUPPORTED),)
+	DEFS+= $(shell pkg-config --cflags jansson)
+	LIBS+= $(shell pkg-config --libs jansson)
+else
+	DEFS+=-I$(LOCALBASE)/include
+	LIBS+=-L$(SYSBASE)/include/lib -L$(LOCALBASE)/lib -ljansson
+endif
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
+include ../../Makefile.modules

+ 279 - 0
src/modules/acc_json/acc_json_mod.c

@@ -0,0 +1,279 @@
+/*
+ * JSON Accounting module
+ *
+ * Copyright (C) 2018 Julien Chavanton (Flowroute.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <jansson.h>
+
+#include "../../core/sr_module.h"
+#include "../../core/dprint.h"
+#include "../../core/mem/mem.h"
+#include "../../core/parser/parse_to.h"
+#include "../../core/kemi.h"
+#include "../../modules/acc/acc_api.h"
+#include "acc_json_mod.h"
+#include "../../modules/acc/acc_extra.h"
+#include "../../modules/mqueue/api.h"
+
+MODULE_VERSION
+
+static int mod_init(void);
+static void destroy(void);
+static int child_init(int rank);
+
+int acc_json_init(acc_init_info_t *inf);
+int acc_json_send_request(struct sip_msg *req, acc_info_t *inf);
+
+// acc API
+acc_api_t accb;
+acc_engine_t _acc_json_engine;
+// mqueue API
+mq_api_t mq_api;
+
+int acc_flag = -1;
+int acc_missed_flag = -1;
+int acc_time_mode = 0;
+static char *acc_extra_str = 0;
+acc_extra_t *acc_extra = 0;
+int output_syslog = -1;
+char *output_mqueue_str = 0; /* see mqueue module queue name */
+str q_name = {0, 0};
+static char *log_facility_str = 0;
+
+static cmd_export_t cmds[] = {{0, 0, 0, 0, 0, 0}};
+
+
+static param_export_t params[] = {{"acc_flag", INT_PARAM, &acc_flag},
+		{"acc_missed_flag", INT_PARAM, &acc_missed_flag},
+		{"acc_extra", PARAM_STRING, &acc_extra_str},
+		{"acc_time_mode", INT_PARAM, &acc_time_mode},
+		{"acc_time_format", PARAM_STRING, &acc_time_format},
+		{"log_level", INT_PARAM, &log_level},
+		{"log_facility", PARAM_STRING, &log_facility_str},
+		{"output_mqueue", PARAM_STRING, &output_mqueue_str},
+		{"output_syslog", INT_PARAM, &output_syslog}, {0, 0, 0}};
+
+
+struct module_exports exports = {
+		"acc_json", DEFAULT_DLFLAGS, /* dlopen flags */
+		cmds,						 /* exported functions */
+		params,						 /* exported params */
+		0,							 /* exported statistics */
+		0,							 /* exported MI functions */
+		0,							 /* exported pseudo-variables */
+		0,							 /* extra processes */
+		mod_init,					 /* initialization module */
+		0,							 /* response function */
+		destroy,					 /* destroy function */
+		child_init					 /* per-child init function */
+};
+
+
+static int mod_init(void)
+{
+	/* bind the ACC API */
+	if(acc_load_api(&accb) < 0) {
+		LM_ERR("cannot bind to ACC API\n");
+		return -1;
+	}
+
+	LM_INFO("janson version : %s\n", JANSSON_VERSION);
+#if JANSSON_VERSION_HEX >= 0x010300
+/* Code specific to version 1.3 and above */
+#endif
+
+	if(log_facility_str) {
+		int tmp = str2facility(log_facility_str);
+		if(tmp != -1)
+			log_facility = tmp;
+		else {
+			LM_ERR("invalid log facility configured");
+			return -1;
+		}
+	}
+
+	/* load the MQUEUE API */
+	if(output_mqueue_str && (load_mq_api(&mq_api) != 0)) {
+		LM_ERR("can't load mqueue module API, disabling json acc to mqueue\n");
+		output_mqueue_str = NULL;
+	} else {
+		q_name.s = output_mqueue_str;
+		q_name.len = strlen(output_mqueue_str);
+	}
+
+	/* parse the extra string, if any */
+	if(acc_extra_str && (acc_extra = accb.parse_extra(acc_extra_str)) == 0) {
+		LM_ERR("failed to parse acc_extra param\n");
+		return -1;
+	}
+
+	memset(&_acc_json_engine, 0, sizeof(acc_engine_t));
+
+	if(acc_flag != -1)
+		_acc_json_engine.acc_flag = 1 << acc_flag;
+	if(acc_missed_flag != -1)
+		_acc_json_engine.missed_flag = 1 << acc_missed_flag;
+	_acc_json_engine.acc_req = acc_json_send_request;
+	_acc_json_engine.acc_init = acc_json_init;
+	memcpy(_acc_json_engine.name, "json", 4);
+	if(accb.register_engine(&_acc_json_engine) < 0) {
+		LM_ERR("cannot register ACC JSON engine\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int child_init(int rank)
+{
+	if(rank == PROC_INIT || rank == PROC_MAIN || rank == PROC_TCP_MAIN)
+		return 0; /* do nothing for the main process */
+
+	return 0;
+}
+
+
+static void destroy(void)
+{
+}
+
+
+int acc_json_init(acc_init_info_t *inf)
+{
+	return 0;
+}
+
+
+void syslog_write(const char *acc)
+{
+	//setlogmask(LOG_UPTO (LOG_NOTICE));
+	openlog("json_acc", LOG_CONS | LOG_PID | LOG_NDELAY, log_facility);
+	syslog(log_level, "%s", acc);
+	closelog();
+}
+
+
+int acc_json_send_request(struct sip_msg *req, acc_info_t *inf)
+{
+	int attr_cnt;
+	int i;
+	int m = 0;
+	int o = 0;
+	/* core fields */
+	attr_cnt = accb.get_core_attrs(req, inf->varr, inf->iarr, inf->tarr);
+
+	json_t *object = json_object();
+	if(acc_time_mode == 2) {
+		double dtime = (double)inf->env->tv.tv_usec;
+		dtime = (dtime / 1000000) + (double)inf->env->tv.tv_sec;
+		json_object_set_new(object, "time", json_real(dtime));
+	} else if(acc_time_mode == 3 || acc_time_mode == 4) {
+		struct tm *t;
+		if(acc_time_mode == 3) {
+			t = localtime(&inf->env->ts);
+		} else {
+			t = gmtime(&inf->env->ts);
+		}
+		if(strftime(acc_time_format_buf, ACC_TIME_FORMAT_SIZE, acc_time_format,
+				   t)
+				<= 0) {
+			acc_time_format_buf[0] = '\0';
+		}
+		json_object_set_new(object, "time", json_string(acc_time_format_buf));
+	} else { // default acc_time_mode==1
+		json_object_set_new(object, "time", json_integer(inf->env->ts));
+	}
+
+	LM_DBG("text[%.*s]\n", inf->env->text.len, inf->env->text.s);
+	for(i = 0; i < attr_cnt; i++) {
+		LM_DBG("[%d][%.*s]\n", i, inf->varr[i].len, inf->varr[i].s);
+		char *tmp = strndup(inf->varr[i].s, inf->varr[i].len);
+		json_t *value = json_string(tmp);
+		if(!value)
+			value = json_string("NON-UTF8");
+		if(i == 0) {
+			json_object_set_new(object, acc_method_key.s, value);
+		} else if(i == 1) {
+			json_object_set_new(object, acc_fromtag_key.s, value);
+		} else if(i == 2) {
+			json_object_set_new(object, acc_totag_key.s, value);
+		} else if(i == 3) {
+			json_object_set_new(object, acc_callid_key.s, value);
+		} else if(i == 4) {
+			json_object_set_new(object, acc_sipcode_key.s, value);
+		} else if(i == 5) {
+			json_object_set_new(object, acc_sipreason_key.s, value);
+		}
+		free(tmp);
+	}
+
+	/* add extra fields */
+	o = accb.get_extra_attrs(acc_extra, req, inf->varr + attr_cnt,
+			inf->iarr + attr_cnt, inf->tarr + attr_cnt);
+	attr_cnt += o;
+	m = attr_cnt;
+
+	struct acc_extra *extra = acc_extra;
+	for(; i < m; i++) {
+		LM_DBG("[%d][%s][%.*s]\n", i, extra->name.s, inf->varr[i].len,
+				inf->varr[i].s);
+		char *tmp = strndup(inf->varr[i].s, inf->varr[i].len);
+		json_t *value = json_string(tmp);
+		if(!value)
+			value = json_string("NON-UTF8");
+		json_object_set_new(object, extra->name.s, value);
+		free(tmp);
+		extra = extra->next;
+	}
+
+	if(object) {
+		if(json_object_size(object) == 0) {
+			LM_ERR("json object empty\n");
+			json_decref(object);
+			return 0;
+		}
+		char *json_string = json_dumps(object, JSON_ENSURE_ASCII);
+		str acc_str = {json_string, strlen(json_string)};
+
+		// json acc output to mqueue
+		if(output_mqueue_str) {
+			str key = str_init("acc");
+			if(mq_api.add(&q_name, &key, &acc_str)) {
+				LM_DBG("ACC queued [%d][%s]\n", acc_str.len, acc_str.s);
+			} else {
+				LM_DBG("ACC mqueue add error [%d][%s]\n", acc_str.len,
+						acc_str.s);
+			}
+		}
+		// json acc output to syslog
+		if(output_syslog)
+			syslog_write(json_string);
+		free(json_string);
+		json_object_clear(object);
+		json_decref(object);
+	}
+	/* free memory allocated by extra2strar */
+	free_strar_mem(&(inf->tarr[m - o]), &(inf->varr[m - o]), o, m);
+	return 1;
+}

+ 42 - 0
src/modules/acc_json/acc_json_mod.h

@@ -0,0 +1,42 @@
+/*
+ * JSON Accounting module
+ *
+ * Copyright (C) 2018 Julien Chavanton (Flowroute.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _ACC_JSON_MOD_H_
+#define _ACC_JSON_MOD_H_
+
+str acc_method_key = str_init("method");
+str acc_fromtag_key = str_init("from_tag");
+str acc_totag_key = str_init("to_tag");
+str acc_callid_key = str_init("callid");
+str acc_sipcode_key = str_init("sip_code");
+str acc_sipreason_key = str_init("sip_reason");
+str acc_time_key = str_init("time");
+
+#define ACC_TIME_FORMAT_SIZE 128
+static char acc_time_format_buf[ACC_TIME_FORMAT_SIZE];
+char *acc_time_format = "%Y-%m-%d %H:%M:%S";
+
+int log_level = L_NOTICE;
+int log_facility = LOG_DAEMON;
+
+#endif

+ 4 - 0
src/modules/acc_json/doc/Makefile

@@ -0,0 +1,4 @@
+docs = acc_json.xml
+
+docbook_dir = ../../../../doc/docbook
+include $(docbook_dir)/Makefile.module

+ 42 - 0
src/modules/acc_json/doc/acc_json.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../../doc/docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+	<bookinfo>
+	<title>ACC_JSON Module</title>
+	<productname class="trade">&kamailio;</productname>
+	<authorgroup>
+        <author>
+        <firstname>Julien</firstname>
+        <surname>Chavanton</surname>
+        <email>[email protected]</email>
+        </author>
+		<author>
+		<firstname>Julien</firstname>
+		<surname>Chavanton</surname>
+		<affiliation><orgname>flowroute.com</orgname></affiliation>
+		<email>[email protected]</email>
+		</author>
+		<editor>
+		<firstname>Julien</firstname>
+		<surname>Chavanton</surname>
+		<affiliation><orgname>flowroute.com</orgname></affiliation>
+		<email>[email protected]</email>
+		</editor>
+	</authorgroup>
+	<copyright>
+		<year>2018</year>
+		<holder>Flowroute.com</holder>
+	</copyright>
+	</bookinfo>
+	<toc></toc>
+
+	<xi:include href="acc_json_admin.xml"/>
+</book>

+ 299 - 0
src/modules/acc_json/doc/acc_json_admin.xml

@@ -0,0 +1,299 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../../doc/docbook/entities.xml">
+%docentities;
+
+]>
+
+<!-- Acc Module User's Guide -->
+
+<chapter>
+
+	<title>&adminguide;</title>
+
+	<section>
+	<title>Overview</title>
+	<para>
+		ACC_JSON module is used to account transaction information in a JSON dictionary.
+		It binds to ACC module API and uses the same accounting mechanisms as for other
+		backends.
+	</para>
+	<para>
+		It can output the JSON dictionary to MQUEUE or
+		SYSLOG (even if Kamailio is not using syslog)
+	</para>
+	</section>
+
+	<section>
+		<title>Dependencies</title>
+		<section>
+			<title>&kamailio; Modules</title>
+			<para>
+			The module depends on the following modules (in the other words
+			the listed modules must be loaded before this module):
+			<itemizedlist>
+				<listitem>
+				<para><emphasis>acc</emphasis> - accounting module</para>
+				</listitem>
+				<listitem>
+				<para><emphasis>mqueue</emphasis> - mqueue module (optional)</para>
+				</listitem>
+			</itemizedlist>
+			</para>
+		</section>
+		<section>
+			<title>External Libraries or Applications</title>
+			<para>
+			The following libraries or applications must be installed
+			before running &kamailio; with this module loaded:
+			</para>
+			<itemizedlist>
+				<listitem>
+				<para>
+				<emphasis>jansson</emphasis> http://www.digip.org/jansson/
+				</para><para>
+				Jansson is a C library for encoding, decoding and manipulating JSON data.
+				</para>
+				</listitem>
+			</itemizedlist>
+		</section>
+	</section>
+
+	<section id="ACC-param-id">
+	<title>Parameters</title>
+
+	<section id="acc_json.p.acc_flag">
+	<title><varname>acc_flag</varname> (integer)</title>
+		<para>
+		Request flag which needs to be set to account a transaction in acc_json.
+		See output_mqueue and output_syslog
+		</para>
+		<para>
+		Default value is not-set (no flag).
+		</para>
+		<example>
+		<title>acc_flag example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc_json", "acc_flag", 2)
+...
+		</programlisting>
+		</example>
+	</section>
+
+	<section id="acc_json.p.acc_missed_flag">
+		<title><varname>acc_missed_flag</varname> (integer)</title>
+		<para>
+		Request flag which needs to be set to account missed calls in acc_json.
+		See output_mqueue and output_syslog
+		</para>
+		<para>
+		Default value is not-set (no flag).
+		</para>
+		<example>
+		<title>acc_missed_flag example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc_json", "acc_missed_flag", 3)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="acc_json.p.acc_extra">
+		<title><varname>acc_extra</varname> (integer)</title>
+		<para>
+		Extra values to be added to the json dictionnary.
+		</para>
+		<para>
+		Default value is NULL.
+		</para>
+		<example>
+		<title>acc_extra example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc_json", "acc_extra", "via=$hdr(Via[*]); email=$avp(s:email)")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="acc_json.p.acc_time_mode">
+	<title><varname>acc_time_mode</varname> (integer)</title>
+		<para>
+		Store additional value related to the time of event.
+		</para>
+		<para>
+		Values can be:
+		</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>0</emphasis> -  (default), save only unix
+				timestamp for syslog and datetime for database.</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>1</emphasis> - save seconds in time_attr and
+				microseconds in time_exten.</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>2</emphasis> - save seconds.milliseconds
+				in time_attr.</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>3</emphasis> - save formatted time according
+				to time_format parameter, using the output of localtime(). Used for cdr entries too.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>4</emphasis> - save formatted time according
+				to time_format parameter, using the output of gmtime(). Used for cdr entries too.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<example>
+		<title>acc_time_mode example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc_json", "acc_time_mode", 1)
+...
+		</programlisting>
+		</example>
+	</section>
+
+	<section id="acc.p.acc_time_format">
+		<title><varname>acc_time_format</varname> (str)</title>
+		<para>
+		Specify the format to print the time for time_mode 3 or 4.
+		</para>
+		<para>
+		Default value is %Y-%m-%d %H:%M:%S".
+		</para>
+		<example>
+		<title>acc_time_format example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc_json", "acc_time_format", "%Y/%m/%d %H:%M:%S")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="acc_json.p.output_mqueue">
+		<title><varname>output_mqueue</varname> (integer)</title>
+		<para>
+                Requires the mqueue module.
+                The acc module will queue json acc events in the specified mqueue.
+                Using a rtimer module exec you can access the queue and process them.
+		</para>
+		<para>
+		Default value is not-set mqueue will not be required
+		</para>
+		<example>
+		<title>output_mqueue usage example</title>
+		<programlisting format="linespecific">
+...
+# example using json_mqueue/http_client to publish to NSQD
+max_while_loops=100000
+modparam("mqueue", "mqueue", "name=acc_events;size=100000")
+modparam("acc_json", "output_mqueue", "acc_events")
+modparam("acc_json", "acc_flag", 2)
+modparam("acc_json", "acc_extra", "caller_ip_port=$avp(caller_ip_port);")
+modparam("rtimer", "timer", "name=nsqt;interval=1;mode=1;")
+modparam("rtimer", "exec", "timer=nsqt;route=RUN_CDR_PUBLISH")
+modparam("http_client", "keep_connections", 1)
+modparam("http_client", "httpcon", "nsqd=>http://localhost:4151/pub?topic=acc")
+
+route[RUN_CDR_PUBLISH] {
+   $var(count) = 0;
+   while (mq_fetch("acc_events")) {
+      $var(q_size) = mq_size("acc_events");
+      $var(count) = $var(count) + 1;
+      xinfo("[RUN_CDR_PUBLISH][$var(q_size)][$var(count)][$mqk(acc_events)][$mqv(acc_events)]\n");
+      $var(res) = http_connect("nsqd", "", "application/json", $mqv(acc_events), "$var(nsq_res)");
+      if ($var(res) != "200") {
+         mq_add("acc_events", "acc_key", "$mqv(acc_events)");
+         return;
+      }
+   }
+   if ($var(count) > 0 ) {
+      xinfo("[RUN_CDR_PUBLISH]done count[$var(count)]\n");
+   }
+}
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="acc_json.p.output_syslog">
+		<title><varname>output_syslog</varname> (integer)</title>
+		<para>
+		Control if the output of acc json should be sent to syslog.
+                This is not dependent on Kamailio global logging settigns,
+                we can use syslog even if Kamailio is not daemonized and/or
+                logging is done to sdtout stderr.
+		</para>
+		<para>
+		Default value is not-set (no flag).
+		</para>
+		<example>
+		<title>output_syslog example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc_json", "output_syslog", 1)
+modparam("acc_json", "log_level", 2)
+modparam("acc_json", "log_facility", "LOG_DAEMON")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="acc_json.p.log_facility">
+		<title><varname>log_facility</varname> (integer)</title>
+		<para>
+		Log facility to which accounting messages are issued to syslog.
+                This allows to easily seperate the accounting specific logging
+                from the other log messages.
+		</para>
+		<para>
+		Default value is LOG_DAEMON.
+		</para>
+		<example>
+		<title>log_facility example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc_json", "log_facility", "LOG_LOCAL0")
+
+# modify you syslog/rsyslog config
+# /etc/rsyslog.d/default.conf
+# remove local0 from default log file
+# *.*;local0,auth,authpriv.none /var/log/syslog
+# add local0 to another log file
+# local0.*                      /var/log/json_acc.log
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="acc_json.p.log_level">
+		<title><varname>log_level</varname> (integer)</title>
+		<para>
+		Log level at which accounting messages are issued to syslog.
+		</para>
+		<para>
+		Default value is 1 (L_NOTICE).
+		</para>
+		<example>
+			<title>log_level example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc_json", "log_level", 2) # Set log_level to 2 (L_INFO)
+...
+</programlisting>
+		</example>
+	</section>
+
+	</section>
+
+</chapter>