mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-03 19:16:46 +00:00
Merge "res_pjproject: Add ability to map pjproject log levels to Asterisk log levels" into 13
This commit is contained in:
8
CHANGES
8
CHANGES
@@ -31,6 +31,14 @@ res_pjproject
|
|||||||
This displays the compiled-in options of the pjproject installation
|
This displays the compiled-in options of the pjproject installation
|
||||||
Asterisk is currently running against.
|
Asterisk is currently running against.
|
||||||
|
|
||||||
|
* Another feature of this module is the ability to map pjproject log levels
|
||||||
|
to Asterisk log levels, or to suppress the pjproject log messages
|
||||||
|
altogether. Many of the messages emitted by pjproject itself are the result
|
||||||
|
of errors which Asterisk will ultimately handle so the messages can be
|
||||||
|
misleading or just noise. A new config file (pjproject.conf) has been added
|
||||||
|
to configure the mapping and a new CLI command (pjproject show log mappings)
|
||||||
|
has been added to display the mappings currently in use.
|
||||||
|
|
||||||
res_pjsip
|
res_pjsip
|
||||||
------------------
|
------------------
|
||||||
* Added new global option (regcontext) to pjsip. When set, Asterisk will
|
* Added new global option (regcontext) to pjsip. When set, Asterisk will
|
||||||
|
28
configs/samples/pjproject.conf.sample
Normal file
28
configs/samples/pjproject.conf.sample
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
; Common pjproject options
|
||||||
|
;
|
||||||
|
|
||||||
|
;========================LOG_MAPPINGS SECTION OPTIONS===============================
|
||||||
|
;[log_mappings]
|
||||||
|
; SYNOPSIS: Provides pjproject to Asterisk log level mappings.
|
||||||
|
; NOTES: The name of this section in the pjproject.conf configuration file must
|
||||||
|
; remain log_mappings or the configuration will not be applied.
|
||||||
|
; The defaults mentioned below only apply if this file or the 'log_mappings'
|
||||||
|
; object can'tbe found. If the object is found, there are no defaults. If
|
||||||
|
; you don't specify an entry, nothing will be logged for that level.
|
||||||
|
;
|
||||||
|
;asterisk_error = ; A comma separated list of pjproject log levels to map to
|
||||||
|
; Asterisk errors.
|
||||||
|
; (default: "0,1")
|
||||||
|
;asterisk_warning = ; A comma separated list of pjproject log levels to map to
|
||||||
|
; Asterisk warnings.
|
||||||
|
; (default: "2")
|
||||||
|
;asterisk_notice = ; A comma separated list of pjproject log levels to map to
|
||||||
|
; Asterisk notices.
|
||||||
|
; (default: "")
|
||||||
|
;asterisk_verbose = ; A comma separated list of pjproject log levels to map to
|
||||||
|
; Asterisk verbose.
|
||||||
|
; (default: "")
|
||||||
|
;asterisk_debug = ; A comma separated list of pjproject log levels to map to
|
||||||
|
; Asterisk debug
|
||||||
|
; (default: "3,4,5")
|
||||||
|
;type= ; Must be of type log_mappings (default: "")
|
@@ -37,6 +37,44 @@
|
|||||||
<support_level>core</support_level>
|
<support_level>core</support_level>
|
||||||
***/
|
***/
|
||||||
|
|
||||||
|
/*** DOCUMENTATION
|
||||||
|
<configInfo name="res_pjproject" language="en_US">
|
||||||
|
<synopsis>pjproject common configuration</synopsis>
|
||||||
|
<configFile name="pjproject.conf">
|
||||||
|
<configObject name="log_mappings">
|
||||||
|
<synopsis>PJPROJECT to Asterisk Log Level Mapping</synopsis>
|
||||||
|
<description><para>Warnings and errors in the pjproject libraries are generally handled
|
||||||
|
by Asterisk. In many cases, Asterisk wouldn't even consider them to
|
||||||
|
be warnings or errors so the messages emitted by pjproject directly
|
||||||
|
are either superfluous or misleading. The 'log_mappings'
|
||||||
|
object allows mapping the pjproject levels to Asterisk levels, or nothing.
|
||||||
|
</para>
|
||||||
|
<note><para>The id of this object, as well as its type, must be
|
||||||
|
'log_mappings' or it won't be found.</para></note>
|
||||||
|
</description>
|
||||||
|
<configOption name="type">
|
||||||
|
<synopsis>Must be of type 'log_mappings'.</synopsis>
|
||||||
|
</configOption>
|
||||||
|
<configOption name="asterisk_error" default="0,1">
|
||||||
|
<synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_ERROR.</synopsis>
|
||||||
|
</configOption>
|
||||||
|
<configOption name="asterisk_warning" default="2">
|
||||||
|
<synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_WARNING.</synopsis>
|
||||||
|
</configOption>
|
||||||
|
<configOption name="asterisk_notice" default="">
|
||||||
|
<synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_NOTICE.</synopsis>
|
||||||
|
</configOption>
|
||||||
|
<configOption name="asterisk_debug" default="3,4,5">
|
||||||
|
<synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_DEBUG.</synopsis>
|
||||||
|
</configOption>
|
||||||
|
<configOption name="asterisk_verbose" default="">
|
||||||
|
<synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_VERBOSE.</synopsis>
|
||||||
|
</configOption>
|
||||||
|
</configObject>
|
||||||
|
</configFile>
|
||||||
|
</configInfo>
|
||||||
|
***/
|
||||||
|
|
||||||
#include "asterisk.h"
|
#include "asterisk.h"
|
||||||
|
|
||||||
ASTERISK_REGISTER_FILE()
|
ASTERISK_REGISTER_FILE()
|
||||||
@@ -51,7 +89,9 @@ ASTERISK_REGISTER_FILE()
|
|||||||
#include "asterisk/cli.h"
|
#include "asterisk/cli.h"
|
||||||
#include "asterisk/res_pjproject.h"
|
#include "asterisk/res_pjproject.h"
|
||||||
#include "asterisk/vector.h"
|
#include "asterisk/vector.h"
|
||||||
|
#include "asterisk/sorcery.h"
|
||||||
|
|
||||||
|
static struct ast_sorcery *pjproject_sorcery;
|
||||||
static pj_log_func *log_cb_orig;
|
static pj_log_func *log_cb_orig;
|
||||||
static unsigned decor_orig;
|
static unsigned decor_orig;
|
||||||
|
|
||||||
@@ -70,6 +110,66 @@ static struct pjproject_log_intercept_data pjproject_log_intercept = {
|
|||||||
.fd = -1,
|
.fd = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct log_mappings {
|
||||||
|
/*! Sorcery object details */
|
||||||
|
SORCERY_OBJECT(details);
|
||||||
|
/*! These are all comma-separated lists of pjproject log levels */
|
||||||
|
AST_DECLARE_STRING_FIELDS(
|
||||||
|
/*! pjproject log levels mapped to Asterisk ERROR */
|
||||||
|
AST_STRING_FIELD(asterisk_error);
|
||||||
|
/*! pjproject log levels mapped to Asterisk WARNING */
|
||||||
|
AST_STRING_FIELD(asterisk_warning);
|
||||||
|
/*! pjproject log levels mapped to Asterisk NOTICE */
|
||||||
|
AST_STRING_FIELD(asterisk_notice);
|
||||||
|
/*! pjproject log levels mapped to Asterisk VERBOSE */
|
||||||
|
AST_STRING_FIELD(asterisk_verbose);
|
||||||
|
/*! pjproject log levels mapped to Asterisk DEBUG */
|
||||||
|
AST_STRING_FIELD(asterisk_debug);
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct log_mappings *default_log_mappings;
|
||||||
|
|
||||||
|
static struct log_mappings *get_log_mappings(void)
|
||||||
|
{
|
||||||
|
struct log_mappings *mappings;
|
||||||
|
|
||||||
|
mappings = ast_sorcery_retrieve_by_id(pjproject_sorcery, "log_mappings", "log_mappings");
|
||||||
|
if (!mappings) {
|
||||||
|
return ao2_bump(default_log_mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __LOG_SUPPRESS -1
|
||||||
|
|
||||||
|
static int get_log_level(int pj_level)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct log_mappings *, mappings, get_log_mappings(), ao2_cleanup);
|
||||||
|
unsigned char l;
|
||||||
|
|
||||||
|
if (!mappings) {
|
||||||
|
return __LOG_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = '0' + fmin(pj_level, 9);
|
||||||
|
|
||||||
|
if (strchr(mappings->asterisk_error, l)) {
|
||||||
|
return __LOG_ERROR;
|
||||||
|
} else if (strchr(mappings->asterisk_warning, l)) {
|
||||||
|
return __LOG_WARNING;
|
||||||
|
} else if (strchr(mappings->asterisk_notice, l)) {
|
||||||
|
return __LOG_NOTICE;
|
||||||
|
} else if (strchr(mappings->asterisk_verbose, l)) {
|
||||||
|
return __LOG_VERBOSE;
|
||||||
|
} else if (strchr(mappings->asterisk_debug, l)) {
|
||||||
|
return __LOG_DEBUG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __LOG_SUPPRESS;
|
||||||
|
}
|
||||||
|
|
||||||
static void log_forwarder(int level, const char *data, int len)
|
static void log_forwarder(int level, const char *data, int len)
|
||||||
{
|
{
|
||||||
int ast_level;
|
int ast_level;
|
||||||
@@ -89,25 +189,19 @@ static void log_forwarder(int level, const char *data, int len)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lower number indicates higher importance */
|
ast_level = get_log_level(level);
|
||||||
switch (level) {
|
|
||||||
case 0: /* level zero indicates fatal error, according to docs */
|
|
||||||
case 1: /* 1 seems to be used for errors */
|
|
||||||
ast_level = __LOG_ERROR;
|
|
||||||
break;
|
|
||||||
case 2: /* 2 seems to be used for warnings and errors */
|
|
||||||
ast_level = __LOG_WARNING;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ast_level = __LOG_DEBUG;
|
|
||||||
|
|
||||||
|
if (ast_level == __LOG_SUPPRESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ast_level == __LOG_DEBUG) {
|
||||||
/* For levels 3 and up, obey the debug level for res_pjproject */
|
/* For levels 3 and up, obey the debug level for res_pjproject */
|
||||||
mod_level = ast_opt_dbg_module ?
|
mod_level = ast_opt_dbg_module ?
|
||||||
ast_debug_get_by_module("res_pjproject") : 0;
|
ast_debug_get_by_module("res_pjproject") : 0;
|
||||||
if (option_debug < level && mod_level < level) {
|
if (option_debug < level && mod_level < level) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PJPROJECT uses indention to indicate function call depth. We'll prepend
|
/* PJPROJECT uses indention to indicate function call depth. We'll prepend
|
||||||
@@ -201,14 +295,105 @@ static char *handle_pjproject_show_buildopts(struct ast_cli_entry *e, int cmd, s
|
|||||||
return CLI_SUCCESS;
|
return CLI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mapping_destroy(void *object)
|
||||||
|
{
|
||||||
|
struct log_mappings *mappings = object;
|
||||||
|
|
||||||
|
ast_string_field_free_memory(mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *mapping_alloc(const char *name)
|
||||||
|
{
|
||||||
|
struct log_mappings *mappings = ast_sorcery_generic_alloc(sizeof(*mappings), mapping_destroy);
|
||||||
|
if (!mappings) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ast_string_field_init(mappings, 128);
|
||||||
|
|
||||||
|
return mappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *handle_pjproject_show_log_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||||
|
{
|
||||||
|
struct ast_variable *objset;
|
||||||
|
struct ast_variable *i;
|
||||||
|
struct log_mappings *mappings;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case CLI_INIT:
|
||||||
|
e->command = "pjproject show log mappings";
|
||||||
|
e->usage =
|
||||||
|
"Usage: pjproject show log mappings\n"
|
||||||
|
" Show pjproject to Asterisk log mappings\n";
|
||||||
|
return NULL;
|
||||||
|
case CLI_GENERATE:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_cli(a->fd, "PJPROJECT to Asterisk log mappings:\n");
|
||||||
|
ast_cli(a->fd, "Asterisk Level : PJPROJECT log levels\n");
|
||||||
|
|
||||||
|
mappings = get_log_mappings();
|
||||||
|
if (!mappings) {
|
||||||
|
ast_log(LOG_ERROR, "Unable to retrieve pjproject log_mappings\n");
|
||||||
|
return CLI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
objset = ast_sorcery_objectset_create(pjproject_sorcery, mappings);
|
||||||
|
if (!objset) {
|
||||||
|
ao2_ref(mappings, -1);
|
||||||
|
return CLI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = objset; i; i = i->next) {
|
||||||
|
ast_cli(a->fd, "%-16s : %s\n", i->name, i->value);
|
||||||
|
}
|
||||||
|
ast_variables_destroy(objset);
|
||||||
|
|
||||||
|
ao2_ref(mappings, -1);
|
||||||
|
return CLI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static struct ast_cli_entry pjproject_cli[] = {
|
static struct ast_cli_entry pjproject_cli[] = {
|
||||||
AST_CLI_DEFINE(handle_pjproject_show_buildopts, "Show the compiled config of the pjproject in use"),
|
AST_CLI_DEFINE(handle_pjproject_show_buildopts, "Show the compiled config of the pjproject in use"),
|
||||||
|
AST_CLI_DEFINE(handle_pjproject_show_log_mappings, "Show pjproject to Asterisk log mappings"),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int load_module(void)
|
static int load_module(void)
|
||||||
{
|
{
|
||||||
ast_debug(3, "Starting PJPROJECT logging to Asterisk logger\n");
|
ast_debug(3, "Starting PJPROJECT logging to Asterisk logger\n");
|
||||||
|
|
||||||
|
if (!(pjproject_sorcery = ast_sorcery_open())) {
|
||||||
|
ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n");
|
||||||
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_sorcery_apply_default(pjproject_sorcery, "log_mappings", "config", "pjproject.conf,criteria=type=log_mappings");
|
||||||
|
if (ast_sorcery_object_register(pjproject_sorcery, "log_mappings", mapping_alloc, NULL, NULL)) {
|
||||||
|
ast_log(LOG_WARNING, "Failed to register pjproject log_mappings object with sorcery\n");
|
||||||
|
ast_sorcery_unref(pjproject_sorcery);
|
||||||
|
pjproject_sorcery = NULL;
|
||||||
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "type", "", OPT_NOOP_T, 0, 0);
|
||||||
|
ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_debug", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_debug));
|
||||||
|
ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_error", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_error));
|
||||||
|
ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_warning", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_warning));
|
||||||
|
ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_notice", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_notice));
|
||||||
|
ast_sorcery_object_field_register(pjproject_sorcery, "log_mappings", "asterisk_verbose", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct log_mappings, asterisk_verbose));
|
||||||
|
|
||||||
|
default_log_mappings = ast_sorcery_alloc(pjproject_sorcery, "log_mappings", "log_mappings");
|
||||||
|
if (!default_log_mappings) {
|
||||||
|
ast_log(LOG_ERROR, "Unable to allocate memory for pjproject log_mappings\n");
|
||||||
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
|
}
|
||||||
|
ast_string_field_set(default_log_mappings, asterisk_error, "0,1");
|
||||||
|
ast_string_field_set(default_log_mappings, asterisk_warning, "2");
|
||||||
|
ast_string_field_set(default_log_mappings, asterisk_debug, "3,4,5");
|
||||||
|
|
||||||
|
ast_sorcery_load(pjproject_sorcery);
|
||||||
|
|
||||||
pj_init();
|
pj_init();
|
||||||
|
|
||||||
decor_orig = pj_log_get_decor();
|
decor_orig = pj_log_get_decor();
|
||||||
@@ -247,12 +432,27 @@ static int unload_module(void)
|
|||||||
|
|
||||||
pj_shutdown();
|
pj_shutdown();
|
||||||
|
|
||||||
|
ao2_cleanup(default_log_mappings);
|
||||||
|
default_log_mappings = NULL;
|
||||||
|
|
||||||
|
ast_sorcery_unref(pjproject_sorcery);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int reload_module(void)
|
||||||
|
{
|
||||||
|
if (pjproject_sorcery) {
|
||||||
|
ast_sorcery_reload(pjproject_sorcery);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AST_MODULE_LOAD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJPROJECT Log and Utility Support",
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJPROJECT Log and Utility Support",
|
||||||
.support_level = AST_MODULE_SUPPORT_CORE,
|
.support_level = AST_MODULE_SUPPORT_CORE,
|
||||||
.load = load_module,
|
.load = load_module,
|
||||||
.unload = unload_module,
|
.unload = unload_module,
|
||||||
|
.reload = reload_module,
|
||||||
.load_pri = AST_MODPRI_CHANNEL_DEPEND - 6,
|
.load_pri = AST_MODPRI_CHANNEL_DEPEND - 6,
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user