diff options
author | Joshua Colp <jcolp@digium.com> | 2016-02-22 10:54:53 -0600 |
---|---|---|
committer | Gerrit Code Review <gerrit2@gerrit.digium.api> | 2016-02-22 10:54:53 -0600 |
commit | 56561c386a94b0c0f3ffce345cb43d478019294f (patch) | |
tree | 2b68f9e5f9242029ba9121da31f4c888ba6579ed | |
parent | b4fdf93d06753c580b4ef7e34fe07670a8e4aff4 (diff) | |
parent | 6b921f706d493f926c3bceb44775aa71bdc5e225 (diff) |
Merge "res_pjproject: Add ability to map pjproject log levels to Asterisk log levels" into 13
-rw-r--r-- | CHANGES | 8 | ||||
-rw-r--r-- | configs/samples/pjproject.conf.sample | 28 | ||||
-rw-r--r-- | res/res_pjproject.c | 224 |
3 files changed, 248 insertions, 12 deletions
@@ -31,6 +31,14 @@ res_pjproject This displays the compiled-in options of the pjproject installation 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 ------------------ * Added new global option (regcontext) to pjsip. When set, Asterisk will diff --git a/configs/samples/pjproject.conf.sample b/configs/samples/pjproject.conf.sample new file mode 100644 index 000000000..97af7345f --- /dev/null +++ b/configs/samples/pjproject.conf.sample @@ -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: "") diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 7bf9003f9..f54c3713e 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -37,6 +37,44 @@ <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" ASTERISK_REGISTER_FILE() @@ -51,7 +89,9 @@ ASTERISK_REGISTER_FILE() #include "asterisk/cli.h" #include "asterisk/res_pjproject.h" #include "asterisk/vector.h" +#include "asterisk/sorcery.h" +static struct ast_sorcery *pjproject_sorcery; static pj_log_func *log_cb_orig; static unsigned decor_orig; @@ -70,6 +110,66 @@ static struct pjproject_log_intercept_data pjproject_log_intercept = { .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) { int ast_level; @@ -89,25 +189,19 @@ static void log_forwarder(int level, const char *data, int len) return; } - /* Lower number indicates higher importance */ - 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; + ast_level = get_log_level(level); + + if (ast_level == __LOG_SUPPRESS) { + return; + } + if (ast_level == __LOG_DEBUG) { /* For levels 3 and up, obey the debug level for res_pjproject */ mod_level = ast_opt_dbg_module ? ast_debug_get_by_module("res_pjproject") : 0; if (option_debug < level && mod_level < level) { return; } - break; } /* 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; } +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[] = { 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) { 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(); decor_orig = pj_log_get_decor(); @@ -247,12 +432,27 @@ static int unload_module(void) pj_shutdown(); + ao2_cleanup(default_log_mappings); + default_log_mappings = NULL; + + ast_sorcery_unref(pjproject_sorcery); + 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", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, + .reload = reload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 6, ); |