Subject: [POST-1.0.2][RFC][V2 PATCH  1/2] Session log level #1: core support

---
 src/include/private/switch_core_pvt.h            |    1 +
 src/include/switch_core.h                        |   15 +++++++++
 src/include/switch_types.h                       |    5 ++-
 src/mod/applications/mod_commands/mod_commands.c |   37 ++++++++++++++++++++++
 src/mod/applications/mod_dptools/mod_dptools.c   |   19 +++++++++++
 src/switch_core_session.c                        |   15 +++++++++
 src/switch_log.c                                 |   24 ++++++++++++--
 7 files changed, 112 insertions(+), 4 deletions(-)

diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h
index 040a6ec..c3b9fc2 100644
--- a/src/include/private/switch_core_pvt.h
+++ b/src/include/private/switch_core_pvt.h
@@ -98,6 +98,7 @@ struct switch_core_session {
 	switch_size_t id;
 	switch_session_flag_t flags;
 	int thread_running;
+	switch_log_level_t log_level;
 	switch_channel_t *channel;
 
 	switch_io_event_hooks_t event_hooks;
diff --git a/src/include/switch_core.h b/src/include/switch_core.h
index 7670435..89ffbf3 100644
--- a/src/include/switch_core.h
+++ b/src/include/switch_core.h
@@ -729,6 +729,21 @@ SWITCH_DECLARE(void *) switch_core_session_get_private(_In_ switch_core_session_
 SWITCH_DECLARE(switch_status_t) switch_core_session_set_private(_In_ switch_core_session_t *session, _In_ void *private_info);
 
 /*!
+  \brief Set session loglevel
+  \param session the session
+  \param loglevel the desired loglevel
+  \return SWITCH_STATUS_SUCCESS on success
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_session_set_loglevel(_In_ switch_core_session_t *session, _In_ switch_log_level_t loglevel);
+
+/*!
+  \brief Get session loglevel
+  \param session the session
+  \return the loglevel
+*/
+SWITCH_DECLARE(switch_log_level_t) switch_core_session_get_loglevel(_In_ switch_core_session_t *session);
+
+/*!
   \brief Add a logical stream to a session
   \param session the session to add the stream to
   \param private_info an optional pointer to private data for the new stream
diff --git a/src/include/switch_types.h b/src/include/switch_types.h
index 4eca73a..415d8cc 100644
--- a/src/include/switch_types.h
+++ b/src/include/switch_types.h
@@ -678,7 +678,8 @@ SWITCH_CHANNEL_ID_EVENT			- Write to the event engine as a LOG event
 typedef enum {
 	SWITCH_CHANNEL_ID_LOG,
 	SWITCH_CHANNEL_ID_LOG_CLEAN,
-	SWITCH_CHANNEL_ID_EVENT
+	SWITCH_CHANNEL_ID_EVENT,
+	SWITCH_SESSION_ID_LOG,
 } switch_text_channel_t;
 
 typedef enum {
@@ -692,6 +693,8 @@ typedef uint32_t switch_core_session_message_flag_t;
 #define SWITCH_CHANNEL_LOG_CLEAN SWITCH_CHANNEL_ID_LOG_CLEAN, __FILE__, __SWITCH_FUNC__, __LINE__, NULL
 #define SWITCH_CHANNEL_EVENT SWITCH_CHANNEL_ID_EVENT, __FILE__, __SWITCH_FUNC__, __LINE__, NULL
 
+#define SWITCH_SESSION_LOG(session) SWITCH_SESSION_ID_LOG, __FILE__, __SWITCH_FUNC__, __LINE__, (char *)session
+
 /*!
   \enum switch_channel_state_t
   \brief Channel States (these are the defaults, CS_SOFT_EXECUTE, CS_EXCHANGE_MEDIA, and CS_CONSUME_MEDIA are often overridden by specific apps)
diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c
index 677c5fa..52fd2e2 100644
--- a/src/mod/applications/mod_commands/mod_commands.c
+++ b/src/mod/applications/mod_commands/mod_commands.c
@@ -1296,6 +1296,41 @@ SWITCH_STANDARD_API(uuid_deflect)
 	return SWITCH_STATUS_SUCCESS;
 }
 
+#define UUID_LOGLEVEL_SYNTAX "<uuid> <level>"
+SWITCH_STANDARD_API(uuid_loglevel)
+{
+	switch_core_session_t *tsession = NULL;
+	char *uuid = NULL, *text = NULL;
+
+	if (!switch_strlen_zero(cmd) && (uuid = strdup(cmd))) {
+		if ((text = strchr(uuid, ' '))) {
+			*text++ = '\0';
+		}
+	}
+
+	if (switch_strlen_zero(uuid) || switch_strlen_zero(text)) {
+		stream->write_function(stream, "-USAGE: %s\n", UUID_LOGLEVEL_SYNTAX);
+	} else {
+		switch_log_level_t level = switch_log_str2level(text);
+
+		if (level == SWITCH_LOG_INVALID) {
+			stream->write_function(stream, "-ERR Invalid log level!\n");
+		}
+		else if ((tsession = switch_core_session_locate(uuid))) {
+
+			switch_core_session_set_loglevel(tsession, level);
+			stream->write_function(stream, "+OK\n");
+			switch_core_session_rwunlock(tsession);
+		}
+		else {
+			stream->write_function(stream, "-ERR No Such Channel %s!\n", uuid);
+		}
+	}
+
+	switch_safe_free(uuid);
+	return SWITCH_STATUS_SUCCESS;
+}
+
 #define SCHED_TRANSFER_SYNTAX "[+]<time> <uuid> <extension> [<dialplan>] [<context>]"
 SWITCH_STANDARD_API(sched_transfer_function)
 {
@@ -3148,6 +3183,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
 	SWITCH_ADD_API(commands_api_interface, "system", "Execute a system command", system_function, SYSTEM_SYNTAX);
 	SWITCH_ADD_API(commands_api_interface, "time_test", "time_test", time_test_function, "<mss>");
 
+	SWITCH_ADD_API(commands_api_interface, "uuid_loglevel", "set loglevel on session", uuid_loglevel, UUID_LOGLEVEL_SYNTAX);
+
 	/* indicate that the module should continue to be loaded */
 	return SWITCH_STATUS_NOUNLOAD;
 }
diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c
index 52fc3e9..70d3ebd 100644
--- a/src/mod/applications/mod_dptools/mod_dptools.c
+++ b/src/mod/applications/mod_dptools/mod_dptools.c
@@ -1648,6 +1648,23 @@ SWITCH_STANDARD_APP(phrase_function)
 	}
 }
 
+#define SESSION_LOGLEVEL_SYNTAX "<level>"
+SWITCH_STANDARD_APP(session_loglevel_function)
+{
+	if (!switch_strlen_zero(data)) {
+		switch_log_level_t level = switch_log_str2level(data);
+
+		if (level == SWITCH_LOG_INVALID) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid log level: %s\n", data);
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting log level \"%s\" on session\n", switch_log_level2str(level));
+			switch_core_session_set_loglevel(session, level);
+		}
+	} else {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No log level specified\n");
+	}
+}
+
 
 SWITCH_STANDARD_APP(playback_function)
 {
@@ -2428,6 +2445,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
 
 	SWITCH_ADD_APP(app_interface, "wait_for_silence", "wait_for_silence", "wait_for_silence", wait_for_silence_function, WAIT_FOR_SILENCE_SYNTAX, SAF_NONE);
 
+	SWITCH_ADD_APP(app_interface, "session_loglevel", "session_loglevel", "session_loglevel", session_loglevel_function, SESSION_LOGLEVEL_SYNTAX, SAF_NONE);
+
 	SWITCH_ADD_DIALPLAN(dp_interface, "inline", inline_dialplan_hunt);
 
 	/* indicate that the module should continue to be loaded */
diff --git a/src/switch_core_session.c b/src/switch_core_session.c
index 58f3853..63e80cf 100644
--- a/src/switch_core_session.c
+++ b/src/switch_core_session.c
@@ -221,6 +221,19 @@ SWITCH_DECLARE(int) switch_core_session_get_stream_count(switch_core_session_t *
 	return session->stream_count;
 }
 
+SWITCH_DECLARE(switch_status_t) switch_core_session_set_loglevel(switch_core_session_t *session, switch_log_level_t log_level)
+{
+	switch_assert(session != NULL);
+	session->log_level = log_level;
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_DECLARE(switch_log_level_t) switch_core_session_get_loglevel(switch_core_session_t *session)
+{
+	switch_assert(session != NULL);
+	return session->log_level;
+}
+
 SWITCH_DECLARE(switch_call_cause_t) switch_core_session_resurrect_channel(const char *endpoint_name,
 																		  switch_core_session_t **new_session, switch_memory_pool_t **pool, void *data)
 {
@@ -1090,6 +1103,8 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_uuid(switch_
 		switch_uuid_format(session->uuid_str, &uuid);
 	}
 
+	session->log_level = runtime.hard_log_level;
+
 	session->endpoint_interface = endpoint_interface;
 	session->raw_write_frame.data = session->raw_write_buf;
 	session->raw_write_frame.buflen = sizeof(session->raw_write_buf);
diff --git a/src/switch_log.c b/src/switch_log.c
index 4804f6d..1cea7c4 100644
--- a/src/switch_log.c
+++ b/src/switch_log.c
@@ -248,12 +248,30 @@ SWITCH_DECLARE(void) switch_log_printf(switch_text_channel_t channel, const char
 	switch_time_t now = switch_timestamp_now();
 	uint32_t len;
 	const char *extra_fmt = "%s [%s] %s:%d %s()%c%s";
+	switch_log_level_t level_limit = runtime.hard_log_level;
 
-	if (level > runtime.hard_log_level) {
-		return;
+	switch_assert(level < SWITCH_LOG_INVALID);
+
+	/*
+	 * Special-case (no pun intended) handling for extensions
+	 */
+	switch (channel) {
+	case SWITCH_SESSION_ID_LOG:
+		{
+			switch_core_session_t *session = (switch_core_session_t *)userdata;
+			switch_assert(session != NULL);
+
+			level_limit = session->log_level;
+		}
+		break;
+
+	default:
+		break;
 	}
 
-	switch_assert(level < SWITCH_LOG_INVALID);
+	if (level > level_limit) {
+		return;
+	}
 
 	va_start(ap, fmt);
 
-- 
1.5.6.4

