linphone-iphone/coreapi/logging.c
2018-05-16 17:04:42 +02:00

268 lines
8.8 KiB
C

/*
log.c
Copyright (C) 2017 Belledonne Communications SARL
This program 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.
This program 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 <algorithm>
#include <map>
#include <bctoolbox/logging.h>
#include <belle-sip/object.h>
#include <mediastreamer2/mscommon.h>
#include "linphone/logging.h"
#include "c-wrapper/c-wrapper.h"
#include "logging-private.h"
struct _LinphoneLoggingService {
belle_sip_object_t base;
LinphoneLoggingServiceCbs *cbs;
bctbx_log_handler_t *log_handler;
};
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLoggingService);
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneLoggingService);
struct _LinphoneLoggingServiceCbs {
belle_sip_object_t base;
void *user_data;
LinphoneLoggingServiceCbsLogMessageWrittenCb message_event_cb;
};
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLoggingServiceCbs);
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneLoggingServiceCbs);
static LinphoneLoggingServiceCbs *_linphone_logging_service_cbs_new(void);
static LinphoneLoggingService *_linphone_logging_service_instance = NULL;
static std::map<LinphoneLogLevel, BctbxLogLevel> _linphone_log_level_to_bctbx_log_level_map = {
{ LinphoneLogLevelDebug , BCTBX_LOG_DEBUG },
{ LinphoneLogLevelTrace , BCTBX_LOG_TRACE },
{ LinphoneLogLevelMessage , BCTBX_LOG_MESSAGE },
{ LinphoneLogLevelWarning , BCTBX_LOG_WARNING },
{ LinphoneLogLevelError , BCTBX_LOG_ERROR },
{ LinphoneLogLevelFatal , BCTBX_LOG_FATAL }
};
LinphoneLogLevel _bctbx_log_level_to_linphone_log_level(BctbxLogLevel level) {
auto &tmap = _linphone_log_level_to_bctbx_log_level_map;
auto predicate = [level](const std::pair<LinphoneLogLevel, BctbxLogLevel> &tuple)->bool{return tuple.second==level;};
auto response = std::find_if(tmap.cbegin(), tmap.cend(), predicate);
if (response != tmap.cend()) {
return response->first;
} else {
ms_warning("%s(): invalid argurement [%d]", __FUNCTION__, level);
return LinphoneLogLevelDebug;
}
}
unsigned int _bctbx_log_mask_to_linphone_log_mask(unsigned int mask) {
unsigned int res = 0;
auto &tmap = _linphone_log_level_to_bctbx_log_level_map;
for (auto it=tmap.cbegin(); it!=tmap.cend(); it++) {
if (mask & it->second) {
mask&=~it->second;
res|=it->first;
}
}
if (mask != 0) {
ms_fatal("%s(): invalid flag set in mask [%x]", __FUNCTION__, mask);
}
return res;
}
BctbxLogLevel _linphone_log_level_to_bctbx_log_level(LinphoneLogLevel level) {
try {
return _linphone_log_level_to_bctbx_log_level_map.at(level);
} catch (const std::out_of_range &) {
ms_fatal("%s(): invalid argument [%d]", __FUNCTION__, level);
return BCTBX_LOG_LOGLEV_END;
}
}
unsigned int _linphone_log_mask_to_bctbx_log_mask(unsigned int mask) {
unsigned int res = 0;
auto &tmap = _linphone_log_level_to_bctbx_log_level_map;
for (auto it=tmap.cbegin(); it!=tmap.cend(); it++) {
if (mask & it->first) {
mask&=~it->first;
res|=it->second;
}
}
if (mask != 0) {
ms_fatal("%s(): invalid flag set in mask [%x]", __FUNCTION__, mask);
}
return res;
}
static void _log_handler_on_message_written_cb(void *info,const char *domain, BctbxLogLevel lev, const char *fmt, va_list args) {
LinphoneLoggingService *service = (LinphoneLoggingService *)info;
if (service->cbs->message_event_cb) {
char *message = bctbx_strdup_vprintf(fmt, args);
service->cbs->message_event_cb(service, domain, _bctbx_log_level_to_linphone_log_level(lev), message);
bctbx_free(message);
}
}
static void _log_handler_destroy_cb(bctbx_log_handler_t *handler) {
LinphoneLoggingService *service = (LinphoneLoggingService *)bctbx_log_handler_get_user_data(handler);
bctbx_free(service->log_handler);
service->log_handler = NULL;
}
static LinphoneLoggingService *_linphone_logging_service_new(void) {
LinphoneLoggingService *service = belle_sip_object_new(LinphoneLoggingService);
service->log_handler = bctbx_create_log_handler(_log_handler_on_message_written_cb, _log_handler_destroy_cb, service);
service->cbs = _linphone_logging_service_cbs_new();
bctbx_add_log_handler(service->log_handler);
return service;
}
LinphoneLoggingService *linphone_logging_service_get(void) {
if (_linphone_logging_service_instance == NULL) {
_linphone_logging_service_instance = _linphone_logging_service_new();
atexit(_linphone_logging_service_clean);
}
return _linphone_logging_service_instance;
}
void _linphone_logging_service_clean(void) {
if (_linphone_logging_service_instance) {
linphone_logging_service_unref(_linphone_logging_service_instance);
_linphone_logging_service_instance = NULL;
}
}
LinphoneLoggingService *linphone_logging_service_ref(LinphoneLoggingService *service) {
return (LinphoneLoggingService *)belle_sip_object_ref(service);
}
void linphone_logging_service_unref(LinphoneLoggingService *service) {
belle_sip_object_unref(service);
}
static void _linphone_logging_service_uninit(LinphoneLoggingService *log_service) {
if (log_service->log_handler)
bctbx_remove_log_handler(log_service->log_handler);
linphone_logging_service_cbs_unref(log_service->cbs);
}
void linphone_logging_service_release_instance(void) {
if (_linphone_logging_service_instance) {
belle_sip_object_unref(BELLE_SIP_OBJECT(_linphone_logging_service_instance));
}
_linphone_logging_service_instance = NULL;
}
LinphoneLoggingServiceCbs *linphone_logging_service_get_callbacks(const LinphoneLoggingService *log_service) {
return log_service->cbs;
}
static const char *_linphone_logging_service_log_domains[] = {
"bctbx",
"belle-sip",
"ortp",
"mediastreamer",
"bzrtp",
BCTBX_LOG_DOMAIN, /* which is "liblinphone", set from CMakeList.txt*/
NULL
};
void linphone_logging_service_set_log_level(LinphoneLoggingService *log_service, LinphoneLogLevel loglevel) {
const char **domain;
for (domain=_linphone_logging_service_log_domains; *domain; domain++) {
bctbx_set_log_level(*domain, _linphone_log_level_to_bctbx_log_level(loglevel));
}
}
void linphone_logging_service_set_log_level_mask(LinphoneLoggingService *log_service, unsigned int mask) {
const char **domain;
for (domain=_linphone_logging_service_log_domains; *domain; domain++) {
bctbx_set_log_level_mask(*domain, (int)_linphone_log_mask_to_bctbx_log_mask(mask));
}
}
unsigned int linphone_logging_service_get_log_level_mask(const LinphoneLoggingService *log_service) {
return _bctbx_log_mask_to_linphone_log_mask(bctbx_get_log_level_mask(BCTBX_LOG_DOMAIN));
}
void linphone_logging_service_set_log_file(const LinphoneLoggingService *service, const char *dir, const char *filename, size_t max_size) {
bctbx_log_handler_t *log_handler = bctbx_create_file_log_handler((uint64_t)max_size, dir, filename, NULL);
bctbx_add_log_handler(log_handler);
}
BELLE_SIP_INSTANCIATE_VPTR(LinphoneLoggingService, belle_sip_object_t,
_linphone_logging_service_uninit, // uninit
NULL, // clone
NULL, // marshal
FALSE // unown
);
static LinphoneLoggingServiceCbs *_linphone_logging_service_cbs_new(void) {
return belle_sip_object_new(LinphoneLoggingServiceCbs);
}
LinphoneLoggingServiceCbs *linphone_logging_service_cbs_ref(LinphoneLoggingServiceCbs *cbs) {
return (LinphoneLoggingServiceCbs *)belle_sip_object_ref(cbs);
}
void linphone_logging_service_cbs_unref(LinphoneLoggingServiceCbs *cbs) {
belle_sip_object_unref(cbs);
}
void linphone_logging_service_cbs_set_log_message_written(LinphoneLoggingServiceCbs *cbs, LinphoneLoggingServiceCbsLogMessageWrittenCb cb) {
/* We need to set the legacy log handler to NULL here
because LinphoneCore have a default log handler that dump
all messages into the standard output. */
/*this function is moved here to make sure default log handler is only removed when user defined logging cbs is set*/
_linphone_core_set_log_handler(NULL);
cbs->message_event_cb = cb;
}
LinphoneLoggingServiceCbsLogMessageWrittenCb linphone_logging_service_cbs_get_log_message_written(const LinphoneLoggingServiceCbs *cbs) {
return cbs->message_event_cb;
}
void linphone_logging_service_cbs_set_user_data(LinphoneLoggingServiceCbs *cbs, void *user_data) {
cbs->user_data = user_data;
}
void *linphone_logging_service_cbs_get_user_data(const LinphoneLoggingServiceCbs *cbs) {
return cbs->user_data;
}
BELLE_SIP_INSTANCIATE_VPTR(LinphoneLoggingServiceCbs, belle_sip_object_t,
NULL, // uninit
NULL, // clone
NULL, // marshal
FALSE // unown
);