diff --git a/apps/logsupport.cpp b/ATTIC/logsupport.cpp similarity index 87% rename from apps/logsupport.cpp rename to ATTIC/logsupport.cpp index 0637845cb..705de10ac 100644 --- a/apps/logsupport.cpp +++ b/ATTIC/logsupport.cpp @@ -17,17 +17,20 @@ #include "logsupport.hpp" #include "../srtcore/srt.h" #include "../srtcore/utilities.h" -#include "../srtcore/ofmt.h" +#include "ofmt.h" using namespace std; using namespace srt; +namespace hvu +{ + // This is based on codes taken from // This is POSIX standard, so it's not going to change. // Haivision standard only adds one more severity below // DEBUG named DEBUG_TRACE to satisfy all possible needs. -map srt_level_names +map level_names { { "alert", LOG_ALERT }, { "crit", LOG_CRIT }, @@ -48,9 +51,9 @@ map srt_level_names -srt_logging::LogLevel::type SrtParseLogLevel(string level) +hvu::logging::LogLevel::type ParseLogLevel(string level) { - using namespace srt_logging; + using namespace hvu::logging; if ( level.empty() ) return LogLevel::fatal; @@ -58,7 +61,7 @@ srt_logging::LogLevel::type SrtParseLogLevel(string level) if ( isdigit(level[0]) ) { long lev = strtol(level.c_str(), 0, 10); - if ( lev >= SRT_LOG_LEVEL_MIN && lev <= SRT_LOG_LEVEL_MAX ) + if ( lev >= HVU_LOG_LEVEL_MIN && lev <= HVU_LOG_LEVEL_MAX ) return LogLevel::type(lev); cerr << "ERROR: Invalid loglevel number: " << level << " - fallback to FATAL\n"; @@ -93,24 +96,13 @@ struct ToLowerFormat } }; -void LogFANames::Install(string upname, int value) -{ - string id; - transform(upname.begin(), upname.end(), back_inserter(id), ToLowerFormat()); - namemap[id] = value; -} // See logsupport_appdefs.cpp for log FA definitions LogFANames srt_transmit_logfa_names; -const map SrtLogFAList() +set ParseLogFA(string fa, set* punknown) { - return srt_transmit_logfa_names.namemap; -} - -set SrtParseLogFA(string fa, set* punknown) -{ - using namespace srt_logging; + using namespace hvu::logging; set fas; @@ -175,7 +167,7 @@ set SrtParseLogFA(string fa, set* punknown) void ParseLogFASpec(const vector& speclist, string& w_on, string& w_off) { - srt::ofmtbufstream son, soff; + hvu::ofmtbufstream son, soff; for (auto& s: speclist) { @@ -204,4 +196,5 @@ void ParseLogFASpec(const vector& speclist, string& w_on, string& w_off) w_off = soffs.empty() ? string() : soffs.substr(1); } +} diff --git a/apps/logsupport.hpp b/ATTIC/logsupport.hpp similarity index 53% rename from apps/logsupport.hpp rename to ATTIC/logsupport.hpp index 79115d726..d6c6a4d72 100644 --- a/apps/logsupport.hpp +++ b/ATTIC/logsupport.hpp @@ -14,21 +14,16 @@ #include #include #include -#include "../srtcore/srt.h" -#include "../srtcore/logging_api.h" +#include "logging_api.h" -srt_logging::LogLevel::type SrtParseLogLevel(std::string level); -std::set SrtParseLogFA(std::string fa, std::set* punknown = nullptr); +namespace hvu +{ + +hvu::logging::LogLevel::type ParseLogLevel(std::string level); +std::set ParseLogFA(std::string fa, std::set* punknown = nullptr); void ParseLogFASpec(const std::vector& speclist, std::string& w_on, std::string& w_off); -const std::map SrtLogFAList(); -SRT_API extern std::map srt_level_names; -struct LogFANames -{ - std::map namemap; - void Install(std::string upname, int value); - LogFANames(); -}; +} #endif diff --git a/apps/logsupport_appdefs.cpp b/ATTIC/logsupport_appdefs.cpp similarity index 100% rename from apps/logsupport_appdefs.cpp rename to ATTIC/logsupport_appdefs.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 96888f8f1..28b6f742d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -795,6 +795,7 @@ set (SRT_SRC_SRTCORE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/srtcore) set (SRT_SRC_COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/common) set (SRT_SRC_TOOLS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tools) set (SRT_SRC_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test) +set (SRT_SRC_LOG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/logging) if(WIN32) message(STATUS "DETECTED SYSTEM: WINDOWS; WIN32=1; PTW32_STATIC_LIB=1") @@ -840,7 +841,7 @@ endif() # This is obligatory include directory for all targets. This is only # for private headers. Installable headers should be exclusively used DIRECTLY. -include_directories(${SRT_SRC_COMMON_DIR} ${SRT_SRC_SRTCORE_DIR} ${SRT_SRC_HAICRYPT_DIR}) +include_directories(${SRT_SRC_COMMON_DIR} ${SRT_SRC_SRTCORE_DIR} ${SRT_SRC_HAICRYPT_DIR} ${SRT_SRC_LOG_DIR}) if (ENABLE_LOGGING) list(APPEND SRT_EXTRA_CFLAGS "-DENABLE_LOGGING=1") @@ -1239,6 +1240,27 @@ if (ENABLE_ENCRYPTION AND "${USE_ENCLIB}" STREQUAL "botan") add_dependencies(srt_virtual botan) endif() +# If empty, set to the default value because this value needs +# to be checked +if (USE_CXX_STD_LIB STREQUAL "") + set (USE_CXX_STD_LIB ${CMAKE_CXX_STANDARD_DEFAULT}) +endif() + +if ("${USE_CXX_STD_LIB}" EQUAL 98) + + message(STATUS "USING STANDARD: ${USE_CXX_STD_LIB} - ADDING LOGGER sync lib") + + # Use SRT sync definitions for logging - for everything, regardless which standard apps use. + # We use options that can be only handled by gcc and clang, + # but on Windows we don't support non-C++11 compiling anymore. + add_definitions(-DHVU_EXT_INCLUDE_SYNC="../srtcore/srt_sync_cxx98.h") +else() + + message(STATUS "USING STANDARD: ${USE_CXX_STD_LIB} - KEEPING LOGGER sync lib as std C++") + +endif() + + if (srt_libspec_shared) if (MICROSOFT) target_link_libraries(${TARGET_srt}_shared PUBLIC Ws2_32.lib) diff --git a/apps/apputil.cpp b/apps/apputil.cpp index 479dff5ed..0d2623af4 100644 --- a/apps/apputil.cpp +++ b/apps/apputil.cpp @@ -19,7 +19,7 @@ #include "common.h" #include "apputil.hpp" #include "netinet_any.h" -#include "srt_compat.h" +#include "hvu_compat.h" #include "ofmt.h" using namespace std; @@ -148,7 +148,7 @@ string Join(const vector& in, string sep) if (in.empty()) return ""; - srt::ofmtbufstream os; + hvu::ofmtbufstream os; os << in[0]; for (auto i = in.begin()+1; i != in.end(); ++i) diff --git a/apps/srt-file-transmit.cpp b/apps/srt-file-transmit.cpp index a850374a4..a2b34532c 100644 --- a/apps/srt-file-transmit.cpp +++ b/apps/srt-file-transmit.cpp @@ -29,10 +29,10 @@ written by #include #include #include +#include #include "apputil.hpp" #include "uriparser.hpp" -#include "logsupport.hpp" #include "socketoptions.hpp" #include "transmitmedia.hpp" #include "verbose.hpp" @@ -58,8 +58,8 @@ struct FileTransmitConfig unsigned long chunk_size; bool skip_flushing; bool quiet = false; - srt_logging::LogLevel::type loglevel = srt_logging::LogLevel::error; - set logfas; + hvu::logging::LogLevel::type loglevel = hvu::logging::LogLevel::error; + set logfas; string logfile; int bw_report = 0; int stats_report = 0; @@ -207,8 +207,8 @@ int parse_args(FileTransmitConfig &cfg, int argc, char** argv) } cfg.full_stats = Option(params, false, o_statsfull); - cfg.loglevel = SrtParseLogLevel(Option(params, "error", o_loglevel)); - cfg.logfas = SrtParseLogFA(Option(params, "", o_logfa)); + cfg.loglevel = hvu::logging::parse_level(Option(params, "error", o_loglevel)); + cfg.logfas = hvu::logging::parse_fa(srt::logging::logger_config(), Option(params, "", o_logfa)); cfg.logfile = Option(params, "", o_logfile); cfg.quiet = Option(params, false, o_quiet); @@ -698,7 +698,7 @@ int main(int argc, char** argv) // Set SRT log levels and functional areas // srt_setloglevel(cfg.loglevel); - for (set::iterator i = cfg.logfas.begin(); i != cfg.logfas.end(); ++i) + for (set::iterator i = cfg.logfas.begin(); i != cfg.logfas.end(); ++i) srt_addlogfa(*i); // diff --git a/apps/srt-live-transmit.cpp b/apps/srt-live-transmit.cpp index 8bd45b9c1..d5888b47f 100644 --- a/apps/srt-live-transmit.cpp +++ b/apps/srt-live-transmit.cpp @@ -65,11 +65,11 @@ #include #include -#include "srt_compat.h" +#include + #include "apputil.hpp" // CreateAddr #include "uriparser.hpp" // UriParser #include "socketoptions.hpp" -#include "logsupport.hpp" #include "transmitmedia.hpp" #include "verbose.hpp" @@ -77,7 +77,7 @@ // to the library. Application using the "installed" library should // use #include -#include +#include // because contains the declaration of logger_config using namespace std; @@ -130,8 +130,8 @@ struct LiveTransmitConfig int timeout_mode = 0; int chunk_size = -1; bool quiet = false; - srt_logging::LogLevel::type loglevel = srt_logging::LogLevel::error; - set logfas; + hvu::logging::LogLevel::type loglevel = hvu::logging::LogLevel::error; + set logfas; bool log_internal; string logfile; int bw_report = 0; @@ -247,18 +247,18 @@ int parse_args(LiveTransmitConfig &cfg, int argc, char** argv) cerr << "List of functional areas:\n"; map revmap; - for (auto entry: SrtLogFAList()) - revmap[entry.second] = entry.first; + for (size_t i = 0; i < srt::logging::logger_config().size(); ++i) + revmap[i] = srt::logging::logger_config().name(i); // Each group on a new line - int en10 = 0; + int en6 = 0; for (auto entry: revmap) { cerr << " " << entry.second; - if (entry.first/10 != en10) + if (entry.first/6 != en6) { cerr << endl; - en10 = entry.first/10; + en6 = entry.first/6; } } cerr << endl; @@ -338,8 +338,8 @@ int parse_args(LiveTransmitConfig &cfg, int argc, char** argv) } cfg.full_stats = OptionPresent(params, o_statsfull); - cfg.loglevel = SrtParseLogLevel(Option(params, "warn", o_loglevel)); - cfg.logfas = SrtParseLogFA(Option(params, "", o_logfa)); + cfg.loglevel = hvu::logging::parse_level(Option(params, "warn", o_loglevel)); + cfg.logfas = hvu::logging::parse_fa(srt::logging::logger_config(), Option(params, "", o_logfa)); cfg.log_internal = OptionPresent(params, o_log_internal); cfg.logfile = Option(params, o_logfile); cfg.quiet = OptionPresent(params, o_quiet); @@ -398,9 +398,7 @@ int main(int argc, char** argv) srt_setloglevel(cfg.loglevel); if (!cfg.logfas.empty()) { - srt_resetlogfa(nullptr, 0); - for (set::iterator i = cfg.logfas.begin(); i != cfg.logfas.end(); ++i) - srt_addlogfa(*i); + srt::resetlogfa(cfg.logfas); } // @@ -411,10 +409,10 @@ int main(int argc, char** argv) if (cfg.log_internal) { srt_setlogflags(0 - | SRT_LOGF_DISABLE_TIME - | SRT_LOGF_DISABLE_SEVERITY - | SRT_LOGF_DISABLE_THREADNAME - | SRT_LOGF_DISABLE_EOL + | HVU_LOGF_DISABLE_TIME + | HVU_LOGF_DISABLE_SEVERITY + | HVU_LOGF_DISABLE_THREADNAME + | HVU_LOGF_DISABLE_EOL ); srt_setloghandler(NAME, TestLogHandler); } @@ -881,29 +879,21 @@ int main(int argc, char** argv) void TestLogHandler(void* opaque, int level, const char* file, int line, const char* area, const char* message) { - char prefix[100] = ""; - if ( opaque ) { -#ifdef _MSC_VER - strncpy_s(prefix, sizeof(prefix), (char*)opaque, _TRUNCATE); -#else - strncpy(prefix, (char*)opaque, sizeof(prefix) - 1); - prefix[sizeof(prefix) - 1] = '\0'; -#endif + std::string prefix; + if (opaque) + { + const char* instr = (const char*)opaque; + size_t len = strlen(instr); + if (len > 10) + len = 10; + prefix = ":" + string(instr, len); } + time_t now; time(&now); - char buf[1024]; - struct tm local = SysLocalTime(now); - size_t pos = strftime(buf, 1024, "[%c ", &local); - -#ifdef _MSC_VER - // That's something weird that happens on Microsoft Visual Studio 2013 - // Trying to keep portability, while every version of MSVS is a different plaform. - // On MSVS 2015 there's already a standard-compliant snprintf, whereas _snprintf - // is available on backward compatibility and it doesn't work exactly the same way. -#define snprintf _snprintf -#endif - snprintf(buf+pos, 1024-pos, "%s:%d(%s)]{%d} %s", file, line, area, level, message); + struct tm local = hvu::SysLocalTime(now); - cerr << buf << endl; + cerr << "[" << std::put_time(&local, "%c") << " " << file << ":" << line + << "(" << area << ")]{" << level << "} " << prefix << message + << endl; } diff --git a/apps/srt-tunnel.cpp b/apps/srt-tunnel.cpp index abb27fefd..68ea65037 100644 --- a/apps/srt-tunnel.cpp +++ b/apps/srt-tunnel.cpp @@ -27,11 +27,11 @@ #include #include -#include "srt_compat.h" +#include "hvu_compat.h" +#include "hvu_threadname.h" #include "apputil.hpp" // CreateAddr #include "uriparser.hpp" // UriParser #include "socketoptions.hpp" -#include "logsupport.hpp" #include "transmitbase.hpp" // bytevector typedef to avoid collisions #include "verbose.hpp" @@ -61,13 +61,8 @@ testmedia.cpp using namespace std; using namespace srt; -const srt_logging::LogFA SRT_LOGFA_APP = 10; -namespace srt_logging -{ -Logger applog(SRT_LOGFA_APP, srt_logger_config, "TUNNELAPP"); -} +hvu::logging::Logger applog("app", srt::logging::logger_config(), true, "TUNNELAPP"); -using srt_logging::applog; class Medium { @@ -241,7 +236,7 @@ class Engine { Verb() << "START: " << media[DIR_IN]->uri() << " --> " << media[DIR_OUT]->uri(); const std::string thrn = media[DIR_IN]->id() + ">" + media[DIR_OUT]->id(); - srt::ThreadName tn(thrn); + hvu::ThreadName tn(thrn); thr = thread([this]() { Worker(); }); } @@ -470,6 +465,7 @@ class SrtMedium: public Medium static void Error(int srterror, int errnov, const string& text) { + using namespace hvu; string message = srt_strerror(srterror, errnov); string hm = fmtcat("ERROR #", srterror, ": ", text, ": ", message); @@ -477,8 +473,7 @@ class SrtMedium: public Medium throw TransmissionError(hm); else { - char buf[180]; - throw TransmissionError(fmtcat(hm, ": #", errnov, ": ", SysStrError(errnov, buf, 179))); + throw TransmissionError(fmtcat(hm, ": #", errnov, ": ", SysStrError(errnov))); } } @@ -572,8 +567,7 @@ class TcpMedium: public Medium static void Error(int verrno, const string& text) { - char rbuf[1024]; - throw TransmissionError("ERROR: " + text + ": " + SysStrError(verrno, rbuf, 1024)); + throw TransmissionError("ERROR: " + text + ": " + hvu::SysStrError(verrno)); } virtual ~TcpMedium() @@ -1135,22 +1129,22 @@ int main( int argc, char** argv ) string loglevel = Option(params, "error", o_loglevel); string logfa = Option(params, "", o_logfa); - srt_logging::LogLevel::type lev = SrtParseLogLevel(loglevel); + auto lev = hvu::logging::parse_level(loglevel); srt::setloglevel(lev); if (logfa == "") { - srt::addlogfa(SRT_LOGFA_APP); + srt::addlogfa(applog.id()); } else { // Add only selected FAs set unknown_fas; - set fas = SrtParseLogFA(logfa, &unknown_fas); + set fas = hvu::logging::parse_fa(srt::logging::logger_config(), logfa, &unknown_fas); srt::resetlogfa(fas); // The general parser doesn't recognize the "app" FA, we check it here. if (unknown_fas.count("app")) - srt::addlogfa(SRT_LOGFA_APP); + srt::addlogfa(applog.id()); } string verbo = Option(params, "no", o_verbose); diff --git a/apps/statswriter.cpp b/apps/statswriter.cpp index 7fdf54bcb..7eab5dc9b 100644 --- a/apps/statswriter.cpp +++ b/apps/statswriter.cpp @@ -16,10 +16,11 @@ #include #include -#include "statswriter.hpp" -#include "netinet_any.h" -#include "srt_compat.h" +#include +#include +#include "ofmt_iostream.h" +#include "statswriter.hpp" using namespace std; @@ -102,19 +103,24 @@ std::string SrtStatsWriter::print_timestamp() { using namespace std; using namespace std::chrono; + using namespace hvu; const auto systime_now = system_clock::now(); const time_t time_now = system_clock::to_time_t(systime_now); - std::ostringstream output; + ofmtbufstream output; // SysLocalTime returns zeroed tm_now on failure, which is ok for put_time. const tm tm_now = SysLocalTime(time_now); - output << std::put_time(&tm_now, "%FT%T.") << std::setfill('0') << std::setw(6); - const auto since_epoch = systime_now.time_since_epoch(); - const seconds s = duration_cast(since_epoch); - output << duration_cast(since_epoch - s).count(); - output << std::put_time(&tm_now, "%z"); + output << fmt(tm_now, "%FT%T."); + + // Fraction of a second part + const auto us_now = duration_cast(systime_now.time_since_epoch()); + const auto us_rem = us_now - duration_cast(us_now); + output << fmt(us_rem.count(), fmtc().fillzero().width(6)); + + // Timezone + output << fmt(tm_now, "%z"); return output.str(); } #else diff --git a/apps/support.maf b/apps/support.maf index e5aa77b8e..e19588317 100644 --- a/apps/support.maf +++ b/apps/support.maf @@ -10,8 +10,6 @@ SOURCES apputil.cpp statswriter.cpp -logsupport.cpp -logsupport_appdefs.cpp socketoptions.cpp transmitmedia.cpp uriparser.cpp @@ -19,7 +17,6 @@ verbose.cpp PRIVATE HEADERS apputil.hpp -logsupport.hpp socketoptions.hpp transmitbase.hpp transmitmedia.hpp diff --git a/apps/transmitmedia.cpp b/apps/transmitmedia.cpp index 34f1d0bb1..fa5a91bd3 100644 --- a/apps/transmitmedia.cpp +++ b/apps/transmitmedia.cpp @@ -38,11 +38,12 @@ #include "socketoptions.hpp" #include "uriparser.hpp" #include "transmitmedia.hpp" -#include "srt_compat.h" +#include "hvu_compat.h" #include "verbose.hpp" using namespace std; using namespace srt; +using namespace hvu; bool g_stats_are_printed_to_stdout = false; bool transmit_total_stats = false; @@ -1014,8 +1015,7 @@ class UdpCommon void Error(int err, string src) { - char buf[512]; - string message = SysStrError(err, buf, 512u); + string message = SysStrError(err); cerr << "\nERROR #" << err << ": " << message << endl; diff --git a/apps/uriparser.cpp b/apps/uriparser.cpp index 45cb4753a..c143cb9af 100644 --- a/apps/uriparser.cpp +++ b/apps/uriparser.cpp @@ -24,6 +24,7 @@ #endif using namespace std; +using namespace hvu; map g_types; @@ -57,8 +58,6 @@ UriParser::~UriParser(void) string UriParser::makeUri() { - using namespace srt; - // Reassemble parts into the URI string prefix = ""; if (m_proto != "") diff --git a/examples/recvfile.cpp b/examples/recvfile.cpp index 7f75cd856..1ee4b8409 100644 --- a/examples/recvfile.cpp +++ b/examples/recvfile.cpp @@ -24,7 +24,7 @@ int main(int argc, char* argv[]) // Use this function to initialize the UDT library srt_startup(); - srt_setloglevel(srt_logging::LogLevel::debug); + srt_setloglevel(hvu::logging::LogLevel::debug); struct addrinfo hints, *peer; diff --git a/examples/recvlive.cpp b/examples/recvlive.cpp index e14420a66..82cb94c8f 100644 --- a/examples/recvlive.cpp +++ b/examples/recvlive.cpp @@ -26,7 +26,7 @@ int main(int argc, char* argv[]) // use this function to initialize the UDT library srt_startup(); - srt_setloglevel(srt_logging::LogLevel::debug); + srt_setloglevel(hvu::logging::LogLevel::debug); addrinfo hints; addrinfo* res; diff --git a/examples/recvmsg.cpp b/examples/recvmsg.cpp index 008eb3928..b04ff5b81 100644 --- a/examples/recvmsg.cpp +++ b/examples/recvmsg.cpp @@ -76,7 +76,7 @@ int main(int argc, char* argv[]) // use this function to initialize the UDT library srt_startup(); - srt_setloglevel(srt_logging::LogLevel::debug); + srt_setloglevel(hvu::logging::LogLevel::debug); SRTSOCKET sfd = srt_create_socket(); if (SRT_INVALID_SOCK == sfd) diff --git a/examples/sendmsg.cpp b/examples/sendmsg.cpp index ce80564d9..9ef34703a 100644 --- a/examples/sendmsg.cpp +++ b/examples/sendmsg.cpp @@ -38,7 +38,7 @@ int main(int argc, char* argv[]) // Use this function to initialize the UDT library srt_startup(); - srt_setloglevel(srt_logging::LogLevel::debug); + srt_setloglevel(hvu::logging::LogLevel::debug); struct addrinfo hints, *peer; diff --git a/haicrypt/haicrypt_log.cpp b/haicrypt/haicrypt_log.cpp index 773507196..336c4952a 100644 --- a/haicrypt/haicrypt_log.cpp +++ b/haicrypt/haicrypt_log.cpp @@ -15,12 +15,13 @@ #include "hcrypt.h" #include "haicrypt.h" #include "../srtcore/srt.h" -#include "../srtcore/logging.h" +#include "../srtcore/logger_fas.h" // Attach yourself to the SRT logging configuration -extern srt_logging::LogConfig srt_logger_config; - -// LOGFA symbol defined in srt.h -srt_logging::Logger hclog(SRT_LOGFA_HAICRYPT, srt_logger_config, "SRT.hc"); +// This symbol doesn't need to be external actually because it's exclusively +// used in haicrypt through this interface (or it is used only inside this file). +// The "logger_fas.h" header provides only the configuration object in which +// this one is registerred. +hvu::logging::Logger hclog("haicrypt", srt::logging::logger_config(), false, "SRT.hc"); extern "C" { @@ -44,11 +45,11 @@ int HaiCrypt_SetLogLevel(int level, int logfa) #define HAICRYPT_DEFINE_LOG_DISPATCHER(LOGLEVEL, dispatcher) \ int HaiCrypt_LogF_##LOGLEVEL ( const char* file, int line, const char* function, const char* format, ...) \ { \ - srt_logging::LogDispatcher& lg = hclog.dispatcher; \ - if (!lg.CheckEnabled()) return -1; \ + hvu::logging::LogDispatcher& lg = hclog.dispatcher; \ + if (!lg.IsEnabled()) return -1; \ va_list ap; \ va_start(ap, format); \ - lg().setloc(file, line, function).vform(format, ap); \ + lg.setloc(file, line, function).vform(format, ap); \ va_end(ap); \ return 0; \ } diff --git a/logging/README.md b/logging/README.md new file mode 100644 index 000000000..b1bf981e1 --- /dev/null +++ b/logging/README.md @@ -0,0 +1,382 @@ +Contents +======== + +This module contains the logging system, plus dependent utilities. + + +Compat utilities +================ + +Header: `hvu_compat.h` +Source: `hvu_compat.c` + +Implements the following functions: + +1. `SysStrError`: replicates the functionality of the `strerror` function +portable way. This function returns a message assigned to the given system +error code. + +The "portable" `strerror` function is not reentrant, and the reentrant +functions are not portable, there are 2 different versions on POSIX systems +and there's a whole new procedure on Windows. This function should cover +this functionality on all supported systems. + +The version for C language requires an output buffer. An extra C++ version +returns it as a string. + +The version with C interface is named `hvu_SysStrError`, everything else is +in the `hvu` namespace. + +2. `SysLocalTime`: returns the `tm` structure for the local time basing on +given value that should be the number of seconds sinc epoch. This should +replicate the reentrant versions of the `localtime` function. + + +Thread name +=========== + +This is a facility that can be used to name a thread so that the name is +visible in the debugger. This name can be also extracted by the logging +system so that this name is present in the log. + +The `ThreadName::set` can be used to set the current thread's name. This +can be only used in the thread handler function so that the thread can +set the name for itself. + +The `ThreadName::get` can be used to read the current thread name. +The name is read into the buffer of size 64, designated as BUFSIZE static +constant. + +This class can be used to make a temporary current process name change +using the RAII-RRID object: You set the name in the constructor, which +will extract the previous name, then the destructor restores the old name. +This can be used as a trick to name the thread at the time when it starts +so that the name is inherited in the newly spawned thread. + +Note that the use of this class can be not always reliable because it +would have to be stated that during the life time of this object the +thread should not be switched, otherwise the name read by other facilities +could be misleading. A more reliable way is to set the thread name +in the beginning of the thread handler using `ThreadName::set`. + + +OFMT +==== + +This is a header-only library facilitating the on-demand tagged formatting. + +It can be used for internal formatting only (using the wrapper over +`std::stringstream`) and with iostream as well. It provides the `fmt` +function that facilitates the "on-demand tagged API" for formatting. +Example: + +``` +printf("%x : %d", a, b); +``` + +In the bare iostream should be written as: + +``` +cout << hex << a << dec << " : " << b; +``` + +With the on-demand tagged API it has to be written as: + +cout << fmt(a, fmtc().hex()) << " : " << b; + +Additionally, it provides optimizations based on the fact that in +the buffer class you can bypass any formatting for strings, if you +don't use `fmt`, that is, rely on the default formatting. + +``` +hvu::ofmtbufstream out; + +out << fmt(a, fmtc().hex()) << " : " << b; +``` + +Here the `" : "` part will be written to the embedded std::stringstream +using the write() method, not using operator<<, which will bypass the +formatting. + +This facility is used in the logging system and can be also used with +any iostream, both with C++03-only and C++11 API. + +Follow the [OFMT documentation](ofmt.md) for details. + + +Logging system +============== + +This is a logging system, which provides the following features: + +1. Displays the time, thread name, configuration set prefix, functional area +prefix, severity prefix and the log contents in one log line. + +2. Displaying of particular log instructions can be filtered by: + * Setting the minimum severity + * Selecting functional areas + +The use of functional areas is not obligatory - there is always availble +a general log, which is always enabled as functional area (it can be +still disabled per severity selection or the whole logging can be turned +off at compile time). + +The logging system consists of two main parts: + +1. Functional part +2. Generated part + +The functional part is the whole logging facility and it provides one +default "general" functional area designated object that you can use +for logging. Additional (selectable) functional areas you can use through +the generated code. + + +Generated files +--------------- + +The generated part is created using the script `generate-fa-files.tcl`. +As argument it requires the configuration file. You should save this +configuration file in your project. The model for this configuration is +provided in `config-model.tcl` file. + +Note that you are obliged to perform the generation in order to be able +to use this library at all, but your configuration may contain the empty +list of the FA (functional areas), if you only plan to use one general FA, and +all configuration items can be reused from the model configuration. + +In this file you can define your all FA entries. For every FA, beside +the description you have the identification name (to find this FA by +string name) and the name prefix. For every FA there will be created +a global variable, which's name consists of ``, where +`` is in this table and `` is common for the whole +configuration defined in `loggers_varsuffix` variable. + + +Basic Usage +----------- + +All these variables can be used then to perform logging at the given +location in the code. So, for example, when you have a FA with prefix +"fa" and the variable suffix is "log", this is to issue a log message +for level "error". + +``` +falog.Error("Wrong value of ", x); +``` + +Note that the printing call form uses the "subsequent arguments" method, +similar to the `print` function in Python or Perl (NOTE: not C++20 one). +In order to use any non-default formatting for numeric values, use the +`fmt` function from the `ofmt.h` header; see above for details. + + +Macros +------ + +This above shown call method is not recommended if you want to be able to +control the logging at compile time to be generally enabled or disabled; +additionally this method doesn't provide the file and line information, +should you need it in your logging line format. Additionally, the variadic +argument version is only available since C++11. Therefore there are two macros +added: + +* `LOGP`: Sequential logging arguments specification (like `print` in Perl or Python) +* `LOGC`: Use the iostream-style `operator <<` to specify arguments + +They resolve to call of the above instruction, if the `ENABLE_DEBUG` +macro is defined as 1, otherwise they resolve to nothing. Additionally +for logging that is considered "heavy" (very detailed and often occurring, +usually for debug only), there are corresponding `HLOGP` and `HLOGC` +macros enabled by `ENABLE_HEAVY_LOGGING`. The usage is: + +``` +LOGP(falog.Error, "Wrong value of ", x); +``` +or with iostream-style (`log` is a local variable inside this instruction only): +``` +LOGC(falog.Error, log << "Wrong value of " << x); +``` + +The second one is the only possibility for C++03/C++98. The LOGP is still +available if compiling in this mode, but it accepts only one message argument. + +For convenience these enabler macros enable also the use of the following +convenience macros: + +* `IF_LOGGING( STATEMENT )` +* `IF_HEAVY_LOGGING( STATEMENT )` + +You can use them in order to prepare appropriate parameters that you would like +to use in the logging instruction, but they are not used outside the logging - +such as declaring a helper variable. Only a single instruction can be placed +inside the arguments (commas inside are still handled). + + +Configuration +------------- + +In order to manage your logging configuration during runtime there is provided +the configuration object. Currently it's implemented as a singleton, for which +you define the access function. Note that the singleton is using the C++ system +supported singleton (meaning, guaranteed to be thread-safely initialized). +Theoretically this is not a requirement in C++98 to be supported, but all +compilers have been supporting it since even before C++11 has been defined, +regardless of the standard requirement. You might want to check on your +compiler if the thread-safe global initialization is in force, but this thing +is only known to be unsupported on archaic gcc compilers only. + +In this configuration object you can: + +* set up the log selection +* find the FA id by name +* configure the C++ stream used for log printing +* configure the log handler function (instead of printing on the `cerr` stream) +* configure special format flags + +The name of the type of the configuration object is `hvu::logging::LogConfig`. +The accessor function's name is defined in the logger configuration file +under the `loggers_configname` key. + + +Management +---------- + +All FA objects get their ids (unique and generated) and they can be also +accessed by these IDs as being collected in a configuration object, to which +they should be added during the creation time. The ID can be obtained by + +``` +falog.id() +``` + +IDs can be searched also by name in the configuration object and through +this object they can be also turned on or off. + +Particular logs can be enabled or disabled using two categories: + +1. Level. You can set the highest possible log level. All logs that +are below this level will not be printed. The levels are in this order: + +* Fatal +* Error +* Warn +* Note +* Debug + +These above are the method names that issue printing a log at particular +level. The corresponding level values for configuration as enum labels +of type `hvu::logging::LogLevel::type`: + +* fatal +* error +* warning +* note +* debug + +You can translate a string into this value using `hvu::logging::parse_level`. + +Using the configuration object you can set the maximum level by + +* `set_maxlevel(level)` + +Note that the argument should be the value of `hvu::logging::LogLevel::type` +type, but you can use as well the `LOG_*` values from `` header and +explicitly convert them into this type. See the `logging_api.h` header for +values. Values do not have 1-based resolution, but this isn't a problem if +you set the log level value to a value not present in this list; the comparison +for enabled log bases on the integer value of the `LOG_*` symbol. + +For Windows there's a specific header provided with `LOG_*` symbols, +`windows_syslog.h`. + + +2. Functional Area. + +You can obtain the IDs from the names given by a string with names +separated by comma. All IDs are then collected in a set returned +by `hvu::logging::parse_fa`. This requires the configuraiton object +because all the names are collected there. These IDs can be then +used to turn on or off the particular functional areas. + +The following functions can be used to configure the enabled FAs: + +* `enable_fa(name, enabled)`: find FA by name and set it enabled or disabled +* `enable_fa(array, arraysize, enabled)`: enable or disable FAs by IDs in the array +* `setup_fa(faset)`: reset enabled FA to only those present in `faset` +* `setup_fa(faset, enabled)`: set only selected FAs enabled or disabled + + +Additional configuration facilities +----------------------------------- + +The following methods are available in `LogConfig` object: + +* `size()` + +Returns the number of functional areas registered in this configuration. + +* `name(id)` + +Returns the name for this FA ID. Empty string is returned if ID is invalid. + +* `find_id(name)` + +Find the FA ID by name. The value should be the positive integer or 0. +If this name is not found, -1 is returned. Note that there is always available +a FA named "general" with ID 0. + +* `set_handler(opaque, handler)` + +Sets the handler function that will be called instead of the default one that +prints into the stream, where `opaque` is a `void*` pointer value to be always +passed to the handler and `handler` is the function to be called with the +following signature: + +``` +typedef void HVU_LOG_HANDLER_FN(void* opaque, int level, const char* file, int line, const char* area, const char* message); +``` + +where: + + * `opaque` is the object as passed to the `set_handler` call + * `level` is the level value as above described + * `file` and `line` are values passed from the `LOGC` or `LOGP` macros + * `area` is the FA prefix, as configured + * `message` is the log message with header + +Note that the header is always present before the message text, and what +this header contains, can be configured in the flags. + +* `set_flags(f)` + +Sets the flags that control the contents of the header; using these you can +turn off particular elements of the log text. This is useful if you want to +format the log message and provide particular parts of the message yourself. + +Flags: + + * `HVU_LOGF_DISABLE_TIME`: Do not add the time when the log instruction was executed + * `HVU_LOGF_DISABLE_THREADNAME`: Do not add the thread name to the log header + * `HVU_LOGF_DISABLE_SEVERITY`: Do not add level marker to the log header + * `HVU_LOGF_DISABLE_EOL`: Do not add the EOL character at the end of `message` + + +Development dependent parts +=========================== + +The logging system uses thread-related facilities for its own purpose. +It doesn't use threads, but it does use thread names, as well as mutexes +and atomics. + +The header file `hvu_sync.h` provides appropriate definitions based on +the C++11 standard library. + +If you want to use it with C++03, you have to provide these facilities +yourself. The SRT library contains a nice wrapper library over the POSIX +threads that provide the appropriate classes that use the same API as +the C++11 standard library - you can use it as an example. In order to +use a header with your definitions, provide its name in `HVU_EXT_INCLUDE_SYNC` +macro in the compilation command line. + + diff --git a/logging/config-model.tcl b/logging/config-model.tcl new file mode 100644 index 000000000..64856c7b5 --- /dev/null +++ b/logging/config-model.tcl @@ -0,0 +1,94 @@ +# +# SRT - Secure, Reliable, Transport +# Copyright (c) 2020 Haivision Systems Inc. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +#***************************************************************************** +#written by +# Haivision Systems Inc. +#***************************************************************************** + +# This is an example configuration file. + +# To explain how they map to the logging system, here is an example +# of the instruction: + +# LOGP(myfalog.Error, "ERROR: The value ", x, " is wrong!"); +# where: +# - "myfalog" is the logger variable assigned to a functional area, +# - "myfa" is the "display-id" (see below) +# - "log" is the $loggers_varsuffix (see below) +# - "Error" is the severity" +# - remaining arguments are data to be printed in the log +# +# The resulting log will then look like this: +# 10:44:56.123456:WRK3!E:LF.myfa: ERROR: The value -1 is wrong! +# where: +# - initial numbers present the timestamp +# - "WRK3" is the thread name (see hvu_threadname.h) +# - !E - is the severity marker (Error in this case) +# - "LF." is $loggers_prefix (see below) +# - "myfa" is the "display-id" + +# All variable names have loggers_ prefix. All those variables can be then used +# inside the generated file pattern. + +# Logger definitions. +# ------------------- +# This defines the functional areas, each one with symbolic +# name and description. Comments are allowed here, just only for the whole +# line. + +# The content is line-oriented! + +# Structure: { name-id display-id help comment follows } where: +# * name-id: Identifier that can be used to obtain the FA identifier (internal) +# * display-id: This FA will be displayed in the log header with the prefix (see below) +# * remaining text up to the end of line: a description to be placed in a comment +set loggers_table { + external ex External functionality + internal in Internal functionality +} + +# This will be used to construct the variable name. The +# display-id field will be used, followed by this one. +# For example, with this suffix, the "external" FA the logger will be "exlog" +set loggers_varsuffix log + +# OPTIONAL, you may want to create also a link to the general +# logger, for convenience. This time it's a full name of a variable +set loggers_generallink gglog + +# This is the prefix when displaying the FA in the log header. +# For example, for 'external', the prefix will be "LF.ex" +set loggers_prefix "LF." + +# The namespace where the global logger variables and the logger config will +# be defined. Use dot separation rather than ::. +# For example, this one below will be my::ns namespace. +set loggers_namespace my.ns + +# Name of the config object where the loggers will be subscribed. +# This will be the function name that returns the logger config +# object as a singleton. This, together with loggers_namespace, +# will form the logger config accessor as "my::ns::logconfig()". +set loggers_configname logconfig + +# Whether all loggers should be enabled or disabled by default +# Note that this doesn't touch upon the general logger. +set loggers_enabled true + +# Name of the generated header and source file (.cpp and .h suffixes +# will be added to this name). May enclose the directory name. +set loggers_modulename example_logfa_file + +# This contents will be pasted into the generated header and source +# file in the beginning. +set loggers_globalheader { + +// This is an example HVU Logger's generated file. + +} diff --git a/logging/generate-fa-files.tcl b/logging/generate-fa-files.tcl new file mode 100755 index 000000000..dde362522 --- /dev/null +++ b/logging/generate-fa-files.tcl @@ -0,0 +1,421 @@ +#!/usr/bin/tclsh +#* +#* SRT - Secure, Reliable, Transport +#* Copyright (c) 2020 Haivision Systems Inc. +#* +#* This Source Code Form is subject to the terms of the Mozilla Public +#* License, v. 2.0. If a copy of the MPL was not distributed with this +#* file, You can obtain one at http://mozilla.org/MPL/2.0/. +#* +#*/ +# +#***************************************************************************** +#written by +# Haivision Systems Inc. +#***************************************************************************** + +lassign $argv configfile + +if {$configfile == ""} { + puts stderr "Usage: [file tail $argv0] " + puts stderr "MIND that the script is run in accordance to relative directories defined there" + exit 1 +} + +source $configfile + +# COMMENTS NOT ALLOWED HERE! Only as C++ comments inside C++ model code. +# (NOTE: Tcl syntax highlighter will likely falsely highlight # as comment here) +# +# Model: TARGET-NAME { format-model logger-pattern hidden-logger-pattern } +# where: +# +# format-model: Text for the whole file. +# - Use $loggers_globalheader in the beginning +# - Use $entries to place loggers_table' entries. +# - Use {%PROCEDURE_NAME} to call a procedure to generate the pattern +# logger-pattern: Pattern for a single logger entry, expanded for all loggers_table +# - $shortname: two-letter name used to compose the logger symbol name (with -log added) +# - $longname: symbolic name suffix +# - $description: to be placed in comments +# +# Special syntax: +# +# % : a high-level command execution. This declares a command that +# must be executed to GENERATE the model. Then, [subst] is executed +# on the results. +# +# = : when placed as the hidden-logger-pattern, it's equal to logger-pattern. +# +# NOTE: NO TABS ALLOWED. INDENT WITH SPACES ONLY. +set generation { + + cpp { + + { + $loggers_globalheader + #include "logging.h" + #include "${loggers_modulename_header}" + + $loggers_namespace_begin + ${loggers_config_defn} + ${loggers_generallink_defn} + + $entries + $loggers_namespace_end + } + + { + // $description + hvu::logging::Logger ${shortname}${loggers_varsuffix}("${longname}", ${loggers_config_use}, ${loggers_enabled}, "${loggers_prefix}${shortname}"); + } + } + + h { + { + $loggers_globalheader + #ifndef $loggers_modulename_macroguard + #define $loggers_modulename_macroguard + + #include "logging.h" + + $loggers_namespace_begin + ${loggers_config_decl} + ${loggers_generallink_decl} + + $entries + $loggers_namespace_end + + #endif + } + + { + extern hvu::logging::Logger ${shortname}${loggers_varsuffix}; + } + } +} + +# Post-processing of the configuration + +if {![info exists loggers_modulename_header]} { + set loggers_modulename_header "[file tail $loggers_modulename].h" +} + +set upref [string map {. _} $loggers_namespace] +set ufile [file tail $loggers_modulename] +set loggers_modulename_macroguard [string toupper ${upref}_${ufile}_H] + +proc DefineNamespaceBounds {nsspec r_begin r_end} { + upvar $r_begin begin + upvar $r_end end + + set parts [split $nsspec .] + set ndepth [llength $parts] + + for {set i 0} {$i < $ndepth} {incr i} { + append begin "namespace [lindex $parts $i] \{ " + append end "\} " + } +} + +set loggers_namespace_begin "" +set loggers_namespace_end "" + +DefineNamespaceBounds $loggers_namespace loggers_namespace_begin loggers_namespace_end + +set loggers_config_decl "extern hvu::logging::LogConfig& ${loggers_configname}();" +set loggers_config_defn "hvu::logging::LogConfigSingleton ${loggers_configname}_si; + hvu::logging::LogConfig& ${loggers_configname}() { return ${loggers_configname}_si.instance();}" +set loggers_config_use "${loggers_configname}()" + +set loggers_generallink_decl "" +set loggers_generallink_defn "" + +if {[info exists loggers_generallink]} { + set loggers_generallink_decl "extern hvu::logging::Logger& $loggers_generallink;" + set loggers_generallink_defn "hvu::logging::Logger& ${loggers_generallink} = ${loggers_config_use}.general;" +} + +set pattern_vars [info vars loggers_*] + +# Processing utilities for 'generation' + +proc get_trim_prefix_length {model} { + # The model consists of lines; we state that the + # definition in the configuration should be appropriately + # indented, but this indentation should be removed or at least + # refaxed for the needs of generation. + + # So we take the indentation from the first line and that + # should be the removable indentation. Any deeper indentation + # in any next line should be only the extra indentation. + + set lines [split $model \n] + foreach l $lines { + set tl [string trim $l] + if {$tl == ""} { + continue + } + set tl [string trimleft $l] + + # The size of the indent prefix is the length + # difference between the original and trimmed line + return [expr { [string length $l] - [string length $tl] } ] + } + + return 0 +} + +proc get_indent {l} { + set tl [string trimleft $l] + return [expr {[string length $l] - [string length $tl]} ] +} + +# lprefix: indent size found in the line +# prefixlen: general prefix in the source format +proc indent_size {lprefix prefixlen} { + if {$lprefix < $prefixlen} { + return -1 + } + + return [expr {$lprefix - $prefixlen}] +} + +proc reindent {line prefixlen} { + set lprefix [get_indent $line] + set indent [indent_size $lprefix $prefixlen] + if {$indent == -1} { + # Line is shorter than the original prefix, so return original + return $line + } + + return [string repeat " " $indent][string trimleft $line] +} + + +# EXECUTION + +set here [file dirname [file normalize $argv0]] + +# if {[lindex [file split $here] end] != "scripts"} { +# puts stderr "The script is in weird location." +# exit 1 +# } + +set outdir [file dirname $loggers_modulename] +if {![file exists $outdir] || ![file isdirectory $outdir]} { + puts stderr "ERROR: The directory for the output files '$outdir' doesn't exist" + exit 1 +} + +set path [file join {*}[lrange [file split $here] 0 end-1]] + +# Utility. Allows to put line-oriented comments and have empty lines +proc no_comments {input} { + set output "" + foreach line [split $input \n] { + set nn [string trim $line] + if { $nn == "" || [string index $nn 0] == "#" } { + continue + } + append output $line\n + } + + return $output +} + +proc generate_entries_from_table {ptabprefix pattern} { + + #puts "PTABPREFIX: '$ptabprefix'" + + foreach v $::pattern_vars { + global $v + } + + # For the [subst] call, use variables + # longname + # shortname + # description + + foreach line [split $::loggers_table \n] { + set line [string trim $line] + + # Skip empty lines and comment lines + if {$line == "" || [string index $line 0] == "#"} { + continue + } + + set description [lassign $line longname shortname] + + # Strip one embedding level + if {[llength $description] == 1} { + set description [lindex $description 0] + } + append entries "${ptabprefix}[string trimleft [subst -nobackslashes $pattern]]\n" + } + + return $entries +} + +proc reindent_all {text indentsize} { + set lines [split $text \n] + + # Find the first non-empty line + for {set ix 0} {$ix < [llength $lines]} {incr ix} { + if {[string trim [lindex $lines $ix]] != ""} { + break + } + } + if {$ix != 0} { + set lines [lrange $lines $ix end] + } + + set remindent [get_indent [lindex $lines 0]] + + set out "" + + foreach l $lines { + set tl [string trimleft $l] + if {$tl == ""} { + append out \n + } else { + append out [string repeat " " $remindent]$tl\n + } + } + return $out +} + +proc generate_file {od target} { + + foreach v $::pattern_vars { + global $v + } + + # Here we have: + # format_model: format for the whole file, should contain $entries + # pattern: pattern for every entry, to be replaced by $entries + lassign [dict get $::generation $target] format_model pattern hpattern + + set ptabprefix "" + + if {[string index $format_model 0] == "%"} { + set command [string range $format_model 1 end] + set format_model [eval $command] + } + + if {$format_model != ""} { + + set indentlen [get_trim_prefix_length $format_model] + + set newformat "" + set trimmed 0 + foreach line [split $format_model \n] { + + + if {[string trim $line] == ""} { + if {$trimmed} { + append newformat "\n" + } + continue + } + set trimmed 1 + + set line [reindent $line $indentlen] + append newformat $line\n + + set ie [string first {$} $line] + if {$ie != -1} { + if {[string range $line $ie end] == {$entries}} { + set ptabprefix [string repeat " " [get_indent $line]] + #puts "CAUGHT ENTRIES: '$line' indent size:[get_indent $line] PTAB '$ptabprefix'" + } + } + } + + set format_model $newformat + unset newformat + } + + set entries "" + + if {[string trim $pattern] != "" } { + + set prevval 0 + set pattern [reindent_all $pattern [string length $ptabprefix]] + + #puts "ENTRIES PATTERN: '$pattern' PTABPREFIX: '$ptabprefix'" + + append entries [generate_entries_from_table $ptabprefix $pattern] + } + + if {$hpattern != ""} { + if {$hpattern == "="} { + set hpattern $pattern + } else { + set hpattern [string trim $hpattern] + } + + # Extra line to separate from the normal entries + append entries "\n" + append entries [generate_entries_from_table $ptabprefix $hpattern] + } + + # --- if { [dict exists $::special $target] } { + # --- set code [subst [dict get $::special $target]] + # --- + # --- # The code should contain "append entries" ! + # --- eval $code + # --- } + + #set entries [string trim $entries] + set entries [string trimleft [reindent_all $entries [string length $ptabprefix]]] + + if {$format_model == ""} { + set format_model $entries + } + + #puts "ENTRY SUBST: '$format_model'" + + # For any case, cut external spaces + puts $od [string trim [subst -nocommands -nobackslashes $format_model]] +} + +proc debug_vars {list} { + set output "" + foreach name $list { + upvar $name _${name} + lappend output "${name}=[set _${name}]" + } + + return $output +} + +# MAIN + +set entryfiles [dict keys $generation] + +foreach suf $entryfiles { + + set f ${loggers_modulename}.$suf + + # Set simple relative path, if the file isn't defined as path. + if { [llength [file split $f]] == 1 } { + set filepath $f + } else { + set filepath [file join $path $f] + } + + puts stderr "Generating '$filepath'" + set od [open $filepath.tmp w] + generate_file $od $suf + close $od + if { [file exists $filepath] } { + puts stderr "WARNING: will overwrite exiting '$f'. Hit ENTER to confirm, or Control-C to stop" + gets stdin + } + + file rename -force $filepath.tmp $filepath +} + +puts stderr Done. + diff --git a/srtcore/srt_compat.c b/logging/hvu_compat.c similarity index 97% rename from srtcore/srt_compat.c rename to logging/hvu_compat.c index bbdf7f795..d064231ef 100644 --- a/srtcore/srt_compat.c +++ b/logging/hvu_compat.c @@ -16,8 +16,7 @@ written by // Prevents from misconfiguration through preprocessor. -#include "platform_sys.h" -#include +#include "hvu_compat.h" #include #include @@ -51,7 +50,7 @@ static const char* SysStrError_Fallback(int errnum, char* buf, size_t buflen) // a fallback message will be returned, either as returned by the underlying // function, or crafted by this function as a response to error in an // underlying function. -extern const char * SysStrError(int errnum, char * buf, size_t buflen) +extern const char * hvu_SysStrError(int errnum, char * buf, size_t buflen) { if (buf == NULL || buflen < 4) // Required to put ??? into it as a fallback { diff --git a/srtcore/srt_compat.h b/logging/hvu_compat.h similarity index 82% rename from srtcore/srt_compat.h rename to logging/hvu_compat.h index d4fd2361e..0c677daf3 100644 --- a/srtcore/srt_compat.h +++ b/logging/hvu_compat.h @@ -14,18 +14,17 @@ written by Haivision Systems Inc. *****************************************************************************/ -#ifndef INC_SRT_COMPAT_H -#define INC_SRT_COMPAT_H +#ifndef INC_HVU_COMPAT_H +#define INC_HVU_COMPAT_H #include -#include #ifdef __cplusplus extern "C" { #endif /* Ensures that we store the error in the buffer and return the bufer. */ -const char * SysStrError(int errnum, char * buf, size_t buflen); +const char * hvu_SysStrError(int errnum, char * buf, size_t buflen); #ifdef __cplusplus } // extern C @@ -36,14 +35,21 @@ const char * SysStrError(int errnum, char * buf, size_t buflen); #include #include +#include + +namespace hvu +{ + inline std::string SysStrError(int errnum) { char buf[1024]; - return SysStrError(errnum, buf, 1024); + return ::hvu_SysStrError(errnum, buf, 1024); } inline struct tm SysLocalTime(time_t tt) { + using namespace std; + struct tm tms; memset(&tms, 0, sizeof tms); #ifdef _WIN32 @@ -60,7 +66,8 @@ inline struct tm SysLocalTime(time_t tt) return tms; } +} #endif // defined C++ -#endif // INC_SRT_COMPAT_H +#endif // macroguard diff --git a/logging/hvu_sync.h b/logging/hvu_sync.h new file mode 100644 index 000000000..5cc6976db --- /dev/null +++ b/logging/hvu_sync.h @@ -0,0 +1,31 @@ +/* + * SRT - Secure, Reliable, Transport + * Copyright (c) 2018 Haivision Systems Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +/***************************************************************************** +written by + Haivision Systems Inc. + *****************************************************************************/ + +// This file should provide the standard way of sync facilities (mutex, scoped lock, atomic, threads) +// This requires, however, at least C++11. For C++98 and C++03 you need to provide some external +// facility. + +#ifndef INC_HVU_SYNC_H +#define INC_HVU_SYNC_H + +#include +#include +#include +#define HVU_EXT_MUTEX std::mutex +#define HVU_EXT_LOCKGUARD std::lock_guard +#define HVU_EXT_ATOMIC std::atomic +#define HVU_EXT_THIS_THREAD std::this_thread + +#endif diff --git a/srtcore/threadname.h b/logging/hvu_threadname.h similarity index 93% rename from srtcore/threadname.h rename to logging/hvu_threadname.h index 6233e36fc..6d6ba8453 100644 --- a/srtcore/threadname.h +++ b/logging/hvu_threadname.h @@ -13,8 +13,8 @@ written by Haivision Systems Inc. *****************************************************************************/ -#ifndef INC_SRT_THREADNAME_H -#define INC_SRT_THREADNAME_H +#ifndef INC_HVU_THREADNAME_H +#define INC_HVU_THREADNAME_H // NOTE: // HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H @@ -31,6 +31,11 @@ written by // Linux-MUSL(MUSL-1.1.20 Partial Implementation. See below). // MINGW-W64(4.0.6) +// If not available, this facility will try to get the thread ID +// using C++11 facilities. For C++03 you have to provide: +// - HVU_EXT_INCLUDE_THREAD (For C++11: ) +// - HVU_EXT_THIS_THREAD (For C++11: std::this_thread) + #if defined(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) \ || defined(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) #include @@ -56,16 +61,23 @@ written by #include #endif #include +#else + +#ifdef HVU_EXT_INCLUDE_SYNC +#include HVU_EXT_INCLUDE_SYNC +#else +#include "hvu_sync.h" +#endif + +#include + #endif #include #include #include -#include "common.h" -#include "sync.h" - -namespace srt { +namespace hvu { class ThreadName { @@ -94,7 +106,6 @@ class ThreadName static bool set(const char* name) { - SRT_ASSERT(name != NULL); #if defined(__linux__) // The name can be up to 16 bytes long, including the terminating // null byte. (If the length of the string, including the terminating @@ -165,7 +176,7 @@ class ThreadName { // The default implementation will simply try to get the thread ID std::ostringstream bs; - bs << "T" << sync::this_thread::get_id(); + bs << "T" << HVU_EXT_THIS_THREAD::get_id(); size_t s = bs.str().copy(output, BUFSIZE - 1); output[s] = '\0'; return true; diff --git a/logging/logging.cpp b/logging/logging.cpp new file mode 100644 index 000000000..9a1004159 --- /dev/null +++ b/logging/logging.cpp @@ -0,0 +1,458 @@ +/* + * SRT - Secure, Reliable, Transport + * Copyright (c) 2018 Haivision Systems Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +/***************************************************************************** +written by + Haivision Systems Inc. + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "logging_api.h" +#include "logging.h" +#include "hvu_threadname.h" +#include "hvu_compat.h" + + +#if __cplusplus > 201100L +#define HVU_LOG_STATIC_ASSERT(cond, msg) static_assert(cond, msg) +#else +#define HVU_LOG_STATIC_ASSERT(cond, msg) +#endif + +// MSVC likes to pollute things +#undef min +#undef max + +using namespace std; + +namespace hvu +{ +namespace logging +{ + +// NOTE: names are used to be assigned to names, +// but hvu::logging uses only some significant ones +// (here with -> assigned dispatcher symbols): +// +// - fatal/crit -> Fatal; +// - error/err -> Error; +// - warning/warn -> Warn; +// - note/notice -> Note; +// - debug -> Debug; +// +// Special trick to initialize it also in C++03 mode. +struct LevelNamesWrapper +{ + map names; + LevelNamesWrapper(); +}; + +LevelNamesWrapper::LevelNamesWrapper() +{ + // This is based on codes taken from + // This is POSIX standard, so it's not going to change. + // Haivision standard only adds one more severity below + // DEBUG named DEBUG_TRACE to satisfy all possible needs. + + // Using only values replicated in LogLevel::type + names.insert(make_pair("crit", LOG_CRIT )); + names.insert(make_pair("debug", LOG_DEBUG )); + names.insert(make_pair("err", LOG_ERR )); + names.insert(make_pair("error", LOG_ERR )); + names.insert(make_pair("fatal", LOG_CRIT )); + names.insert(make_pair("notice", LOG_NOTICE )); + names.insert(make_pair("note", LOG_NOTICE )); + names.insert(make_pair("warn", LOG_WARNING )); + names.insert(make_pair("warning", LOG_WARNING )); +} + +LogLevel::type parse_level(const std::string& name) +{ + // Values can be of more resolution than hvu::logging uses, + // but it only puts the highest level value. Log messages are + // enabled only if they are on that level or below. + static LevelNamesWrapper level; + + map::iterator i = level.names.find(name); + if (i == level.names.end()) + return LogLevel::invalid; + return LogLevel::type(i->second); +} + +std::set parse_fa(const hvu::logging::LogConfig& config, std::string fa, std::set* punknown) +{ + set fas; + + // The split algo won't work on empty string. + if ( fa == "" ) + return fas; + + // To enable all FAs, you can call enable_fa() with zero array size. + // But for the APIs that require particular FA IDs for various operations + // they need to get the actual numbers. + if ( fa == "all" ) + { + // Start from 1 as general is always on. + for (size_t i = 1; i < config.size(); ++i) + fas.insert(i); + + return fas; + } + + int (*ToLower)(int) = &std::tolower; + transform(fa.begin(), fa.end(), fa.begin(), ToLower); + + vector xfas; + size_t pos = 0, ppos = 0; + for (;;) + { + if ( fa[pos] != ',' ) + { + ++pos; + if ( pos < fa.size() ) + continue; + } + size_t n = pos - ppos; + if ( n != 0 ) + xfas.push_back(fa.substr(ppos, n)); + ++pos; + if ( pos >= fa.size() ) + break; + ppos = pos; + } + + for (size_t i = 0; i < xfas.size(); ++i) + { + fa = xfas[i]; + int faid = config.find_id(fa); + if (faid == -1) + { + if (punknown) + punknown->insert(fa); // If requested, add it back silently + else + cerr << "ERROR: Invalid log functional area spec: '" << fa << "' - skipping\n"; + continue; + } + + fas.insert(faid); + } + + return fas; +} + + +// Note: subscribe() and unsubscribe() functions are being called +// in the global constructor and destructor only, as the +// Logger objects (and inside them also their LogDispatcher) +// are being created. It's not predicted that LogDispatcher +// object are going to be created any other way than as +// global objects. Therefore the construction and destruction +// of them happens always in the main thread. + +void LogConfig::subscribe(LogDispatcher* lg) +{ + vector::iterator p = std::find(loggers.begin(), loggers.end(), lg); + if (p != loggers.end()) + return; // Do not register twice + + loggers.push_back(lg); +} + +void LogConfig::unsubscribe(LogDispatcher* lg) +{ + vector::iterator p = std::find(loggers.begin(), loggers.end(), lg); + if (p != loggers.end()) + { + loggers.erase(p); + } +} + +// This function doesn't have any protection on itself, +// however the API functions from which it is called, call +// it already under a mutex protection. +void LogConfig::updateLoggersState() +{ + for (vector::iterator p = loggers.begin(); + p != loggers.end(); ++p) + { + (*p)->Update(); + } +} + +LogDispatcher::LogDispatcher(int functional_area, bool initially_enabled, + LogConfig& config, LogLevel::type log_level, + const char* level_pfx, const char* logger_pfx /*[[nullable]]*/): + fa(functional_area), + level(log_level), + level_prefix(level_pfx), + enabled(initially_enabled), + src_config(&config) +{ + // The Logger object and the config must be defined in the same + // file because otherwise otherwise the order of initialization cannot + // be ensured. + + // We need to keep the user prefix and level prefix in one table. + // So let's copy initially the level prefix. This one is not + // allowed to be NULL. + + prefix_len = strlen(level_pfx); + memcpy(prefix, level_pfx, prefix_len+1); + + set_prefix(logger_pfx); + + config.subscribe(this); + Update(); +} + +void LogDispatcher::set_prefix(const char* logger_pfx) +{ + size_t level_pfx_len = level_prefix ? strlen(level_prefix) : 0; + const size_t logger_pfx_len = logger_pfx ? strlen(logger_pfx) : 0; + + if (logger_pfx && level_pfx_len + logger_pfx_len + 1 < MAX_PREFIX_SIZE) + { + memcpy(prefix, level_prefix, level_pfx_len); + prefix[level_pfx_len] = ':'; + memcpy(prefix + level_pfx_len + 1, logger_pfx, logger_pfx_len); + prefix_len = level_pfx_len + logger_pfx_len + 1; + prefix[prefix_len] = '\0'; + } + else if (level_prefix) + { + // Prefix too long, so copy only level_pfx and only + // as much as it fits + size_t copylen = std::min(+MAX_PREFIX_SIZE, level_pfx_len); + memcpy(prefix, level_prefix, copylen); + prefix[copylen] = '\0'; + prefix_len = copylen; + } + else + { + prefix[0] = '\0'; + prefix_len = 0; + } +} + +LogDispatcher::~LogDispatcher() +{ + src_config->unsubscribe(this); +} + +void LogDispatcher::Update() +{ + bool enabled_in_fa = src_config->enabled_fa[fa]; + enabled = enabled_in_fa && level <= src_config->max_level; +} + + +// SendLogLine can be compiled normally. It's intermediately used by: +// - Proxy object, which is replaced by DummyProxy when !ENABLE_LOGGING +// - PrintLogLine, which has empty body when !ENABLE_LOGGING +void LogDispatcher::SendLogLine(const char* file, int line, const std::string& area, const std::string& msg) +{ + src_config->lock(); + if ( src_config->loghandler_fn ) + { + (*src_config->loghandler_fn)(src_config->loghandler_opaque, int(level), file, line, area.c_str(), msg.c_str()); + } + else if ( src_config->log_stream ) + { + src_config->log_stream->write(msg.data(), msg.size()); + src_config->log_stream->flush(); + } + src_config->unlock(); +} + + +#if ENABLE_LOGGING + +LogDispatcher::Proxy LogDispatcher::setloc(const char* f, int l, const std::string& a) +{ + return Proxy(*this, f, l, a); +} + +LogDispatcher::Proxy::Proxy(LogDispatcher& guy) + : that(guy) + , i_file("") + , i_line(0) + , flags(that.src_config->flags) +{ + if (that.IsEnabled()) + { + // Create logger prefix + that.CreateLogLinePrefix(os); + } +} + +LogDispatcher::Proxy::Proxy(LogDispatcher& guy, const char* f, int l, std::string a) + : that(guy) + , i_file(f) + , i_line(l) + , flags(that.src_config->flags) +{ + if (that.IsEnabled()) + { + area = a; + // Create logger prefix + that.CreateLogLinePrefix(os); + } +} + +LogDispatcher::Proxy LogDispatcher::operator()() +{ + return Proxy(*this); +} + +LogDispatcher::Proxy& LogDispatcher::Proxy::vform(const char* fmts, va_list ap) +{ + static const int BUFLEN = 512; + char buf[BUFLEN]; + +#if defined(_MSC_VER) && _MSC_VER < 1900 + int wlen = _vsnprintf(buf, BUFLEN - 1, fmts, ap); +#else + int wlen = vsnprintf(buf, BUFLEN, fmts, ap); +#endif + + if (wlen < 1) // catch both 0 and -1 + { + // ERROR when formatting + const char msg[] = ""; + os.write(msg, sizeof (msg)); + return *this; + } + + // vsnprintf returns the number of characters printed, + // or the size of required buffer, if the buffer was too small + // and it resulted in a truncated string. Ignore truncation, + // just make sure that terminating 0 was properly specified. + size_t len = wlen >= BUFLEN ? BUFLEN - 1 : wlen; + if ( buf[len-1] == '\n' ) + { + // Remove EOL character, should it happen to be at the end. + // The EOL will be added at the end anyway. + --len; + } + + os.write(buf, len); + return *this; +} + +void LogDispatcher::CreateLogLinePrefix(hvu::ofmtbufstream& serr) +{ + using namespace std; + using namespace hvu; + + HVU_LOG_STATIC_ASSERT(hvu::ThreadName::BUFSIZE >= sizeof("hh:mm:ss.") * 2, // multiply 2 for some margin + "ThreadName::BUFSIZE is too small to be used for strftime"); + char tmp_buf[ThreadName::BUFSIZE]; + if (!isset(HVU_LOGF_DISABLE_TIME)) + { + // Not necessary if sending through the queue. + timeval tv; + gettimeofday(&tv, NULL); + struct tm tm = hvu::SysLocalTime((time_t) tv.tv_sec); + + if (strftime(tmp_buf, sizeof(tmp_buf), "%X.", &tm)) + { + serr << tmp_buf << fmt(tv.tv_usec, fmtc().fillzero().width(6)); + } + } + + // Note: ThreadName::get needs a buffer of size min. ThreadName::BUFSIZE + if (!isset(HVU_LOGF_DISABLE_THREADNAME) && ThreadName::get(tmp_buf)) + { + serr << OFMT_RAWSTR("/") << tmp_buf; + } + + if (!isset(HVU_LOGF_DISABLE_SEVERITY)) + { + serr.write(prefix, prefix_len); // include terminal 0 + } + + serr << OFMT_RAWSTR(": "); +} + +#undef HVU_LOG_STATIC_ASSERT + +std::string LogDispatcher::Proxy::ExtractName(std::string pretty_function) +{ + if ( pretty_function == "" ) + return ""; + size_t pos = pretty_function.find('('); + if ( pos == std::string::npos ) + return pretty_function; // return unchanged. + + pretty_function = pretty_function.substr(0, pos); + + // There are also template instantiations where the instantiating + // parameters are encrypted inside. Therefore, search for the first + // open < and if found, search for symmetric >. + + int depth = 1; + pos = pretty_function.find('<'); + if ( pos != std::string::npos ) + { + size_t end = pos+1; + for(;;) + { + ++pos; + if ( pos == pretty_function.size() ) + { + --pos; + break; + } + if ( pretty_function[pos] == '<' ) + { + ++depth; + continue; + } + + if ( pretty_function[pos] == '>' ) + { + --depth; + if ( depth <= 0 ) + break; + continue; + } + } + + std::string afterpart = pretty_function.substr(pos+1); + pretty_function = pretty_function.substr(0, end) + ">" + afterpart; + } + + // Now see how many :: can be found in the name. + // If this occurs more than once, take the last two. + pos = pretty_function.rfind("::"); + + if ( pos == std::string::npos || pos < 2 ) + return pretty_function; // return whatever this is. No scope name. + + // Find the next occurrence of :: - if found, copy up to it. If not, + // return whatever is found. + pos -= 2; + pos = pretty_function.rfind("::", pos); + if ( pos == std::string::npos ) + return pretty_function; // nothing to cut + + return pretty_function.substr(pos+2); +} +#endif + +}} // (end namespace hvu::logging) + diff --git a/logging/logging.h b/logging/logging.h new file mode 100644 index 000000000..29786a80c --- /dev/null +++ b/logging/logging.h @@ -0,0 +1,625 @@ +/* + * SRT - Secure, Reliable, Transport + * Copyright (c) 2018 Haivision Systems Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +/***************************************************************************** +written by + Haivision Systems Inc. + *****************************************************************************/ + +// This file contains the interface for the logging system and should be +// included in a file where you are going to use the logging instructions, +// also indirectly through the generated logger FA interface file. + +// Usage: +// +// LOGC(gglog.Note, log << "There are " << note_no << " notes."); +// LOGP(gglog.Note, "There are ", note_no, " notes."); +// +// Where: +// +// LOGC/LOGP: The logger macro. This allows to turn logging off, if not ENABLE_LOGGING. +// *C: Use the iostream-style formatting with 'log' as the stream marker. +// *P: Use multiple arguments (note: for C++03 only one argument available). +// +// Note that the logger dispatchers ("Note" here) can be also called directly, but +// this way you can't control the logging at compile time (or you have to organize +// it somehow by yourself; this macro allows also to record __FILE__ and __LINE__ +// of the log (although not used by the default format). +// +// gglog.Note("There are ", note_no, " notes."); +// or +// gglog.Note() << "There are " << note_no << " notes."; +// +// Formating with printf-style is partially supported, but you need to do your own +// wrapper for that, which will do something like: +// +// va_list ap; +// va_start(ap, args); +// gglog.Note.setloc(file, line, function).vform(format, ap); +// va_end(ap); +// +// (Note that file, line and function parameters should be extracted through +// the macro from __FILE__, __LINE__ and __function__ at the macro application). + + +#ifndef INC_HVU_LOGGING_H +#define INC_HVU_LOGGING_H + +// This is for a case when compiling in C++03/C++98 mode. +// In this case you need to provide the definitions like +// below and define HVU_EXT_NOCXX11 to 1. + +#ifndef HVU_EXT_NOCXX11 +#define HVU_EXT_NOCXX11 0 +#define HVU_EXT_INCLUDE_MUTEX +#define HVU_EXT_INCLUDE_ATOMIC +#endif + +#include +#include +#include +#include +#include + +#ifdef HVU_EXT_INCLUDE_SYNC +#include HVU_EXT_INCLUDE_SYNC +#else +#include "hvu_sync.h" +#endif + + +#include +#ifdef _WIN32 +#include "win/wintime.h" +#include +#else +#include +#endif + +#include "logging_api.h" +#include "ofmt.h" + +#if !defined(ENABLE_LOGGING) +#define ENABLE_LOGGING 0 +#endif + +#if ENABLE_LOGGING + +// GENERAL NOTE: All logger functions ADD THEIR OWN \n (EOL). Don't add any your own EOL character. +// The logging system may not add the EOL character, if appropriate flag was set in log settings. +// Anyway, treat the whole contents of eventually formatted message as exactly one line. + +// LOGC uses an iostream-like syntax, using the special 'log' symbol. +// This symbol isn't visible outside the log macro parameters. +// Usage: LOGC(gglog.Debug, log << param1 << param2 << param3); +#define LOGC(logdes, args) if (logdes.IsEnabled()) \ +{ \ + hvu::logging::LogDispatcher::Proxy log(logdes, __FILE__, __LINE__, __FUNCTION__); \ + { (void)(const hvu::logging::LogDispatcher::Proxy&)(args); } \ +} + +// LOGP is C++11 only OR with only one argument. +// Usage: LOGP(gglog.Debug, param1, param2, param3); +#define LOGP(logdes, ...) if (logdes.IsEnabled()) logdes.printloc(__FILE__, __LINE__, __FUNCTION__,##__VA_ARGS__) + +#define IF_LOGGING(instr,...) instr,##__VA_ARGS__ + +#if ENABLE_HEAVY_LOGGING + +#define HLOGC LOGC +#define HLOGP LOGP +#define IF_HEAVY_LOGGING IF_LOGGING + +#else + +#define HLOGC(...) +#define HLOGP(...) +#define IF_HEAVY_LOGGING(...) (void)0 + +#endif + +#else // IF LOGGING DISABLED + +#define LOGC(...) +#define LOGP(...) +#define HLOGC(...) +#define HLOGP(...) +#define IF_HEAVY_LOGGING(...) (void)0 +#define IF_LOGGING(...) (void)0 + +#endif + +namespace hvu +{ +namespace logging +{ + +// The LogDispatcher class represents the object that is responsible for +// printing the log line. +class LogDispatcher +{ + friend class Logger; + friend class LogConfig; + + int fa; + LogLevel::type level; + static const size_t MAX_PREFIX_SIZE = 32; + const char* level_prefix; // ONLY STATIC CONSTANTS ALLOWED + char prefix[MAX_PREFIX_SIZE+1]; + size_t prefix_len; + HVU_EXT_ATOMIC enabled; + class LogConfig* src_config; + + bool isset(int flg); + +public: + + void set_prefix(const char* prefix); + + LogDispatcher(int functional_area, bool initially_enabled, class LogConfig& config, LogLevel::type log_level, + const char* level_pfx, //NOTE: ONLY STATIC CONSTANTS ALLOWED! + const char* logger_pfx = NULL); + + ~LogDispatcher(); + + void Update(); + + bool IsEnabled() { return enabled; } + + void CreateLogLinePrefix(hvu::ofmtbufstream&); + void SendLogLine(const char* file, int line, const std::string& area, const std::string& sl); + + // log.Debug("This is the ", nth, " time"); <--- C++11 only. + // log.Debug() << "This is the " << nth << " time"; <--- C++03 available. + +#if HAVE_CXX11 + + template + void PrintLogLine(const char* file, int line, const std::string& area, Args&&... args); + + template + void operator()(Args&&... args) + { + PrintLogLine("UNKNOWN.c++", 0, "UNKNOWN", args...); + } + + template + void printloc(const char* file, int line, const std::string& area, Args&&... args) + { + PrintLogLine(file, line, area, args...); + } +#else + template + void PrintLogLine(const char* file, int line, const std::string& area, const Arg& arg); + + // For C++03 (older) standard provide only with one argument. + template + void operator()(const Arg& arg) + { + PrintLogLine("UNKNOWN.c++", 0, "UNKNOWN", arg); + } + + void printloc(const char* file, int line, const std::string& area, const std::string& arg1) + { + PrintLogLine(file, line, area, arg1); + } +#endif + +#if ENABLE_LOGGING + + struct Proxy; + friend struct Proxy; + + Proxy operator()(); + Proxy setloc(const char* f, int l, const std::string& a); +#else + + // Dummy proxy that does nothing + struct DummyProxy + { + template + DummyProxy& operator<<(const T& ) + { + return *this; + } + + DummyProxy& vform(const char*, va_list) + { + return *this; + } + + DummyProxy& setloc(const char* , int , std::string) + { + return *this; + } + }; + + DummyProxy operator()() + { + return DummyProxy(); + } + + DummyProxy setloc(const char* , int , const std::string& ) + { + return DummyProxy(); + } +#endif +}; + +// Proxy is the class provided for the sake of C++03 support +// using the << operator syntax. Ignore it if you only use +// the multi-parameter call. + +#if ENABLE_LOGGING + +struct LogDispatcher::Proxy +{ + LogDispatcher& that; + + hvu::ofmtbufstream os; + + // CACHE!!! + const char* i_file; + int i_line; + int flags; + std::string area; + + // Left for future. Not sure if it's more convenient + // to use this to translate __PRETTY_FUNCTION__ to + // something short, or just let's leave __FUNCTION__ + // or better __func__. + std::string ExtractName(std::string pretty_function); + + Proxy(LogDispatcher& guy); + Proxy(LogDispatcher& guy, const char* f, int l, std::string a); + + // Copy constructor is needed due to noncopyable ostringstream. + // This is used only in creation of the default object, so just + // use the default values, just copy the location cache. + Proxy(const Proxy& p) + : that(p.that) + , i_file(p.i_file) + , i_line(p.i_line) + , flags(p.flags) + , area(p.area) + { + } + + template + Proxy& operator<<(const T& arg) // predicted for temporary objects + { + if ( that.IsEnabled() ) + { + os << arg; + } + return *this; + } + + // Provide explicit overloads for const char* and string + // so that printing them bypasses the formatting facility + + // Special case for atomics, as passing them to the fmt facility + // requires unpacking the real underlying value. + template + Proxy& operator<<(const HVU_EXT_ATOMIC& arg) + { + if (that.IsEnabled()) + { + os << arg.load(); + } + return *this; + } + +#if HAVE_CXX11 + + void dispatch() {} + + template + void dispatch(const Arg1& a1, const Args&... others) + { + *this << a1; + dispatch(others...); + } + + // Special dispatching for atomics must be provided here. + // By some reason, "*this << a1" expression gets dispatched + // to the general version of operator<<, not the overload for + // atomic. Even though the compiler shows Arg1 type as atomic. + template + void dispatch(const HVU_EXT_ATOMIC& a1, const Args&... others) + { + *this << a1.load(); + dispatch(others...); + } + +#endif + + ~Proxy() + { + if (that.IsEnabled()) + { + if ((flags & HVU_LOGF_DISABLE_EOL) == 0) + os << OFMT_RAWSTR("\n"); // XXX would be nice to use a symbol for it + + that.SendLogLine(i_file, i_line, area, os.str()); + } + // XXX Consider clearing the 'os' manually + } + + Proxy& vform(const char* fmts, va_list ap); +}; + + +#endif + +class Logger +{ + friend class LogConfig; + + int m_fa; + Logger(const std::string& idname, class LogConfig& config, bool initially_enabled, const char* logger_pfx, int forced_fa); + +public: + + LogDispatcher Debug; + LogDispatcher Note; + LogDispatcher Warn; + LogDispatcher Error; + LogDispatcher Fatal; + + Logger(const std::string& idname, class LogConfig& config, bool initially_enabled, const char* logger_pfx = NULL); + int id() const { return m_fa; } +}; + +class LogConfig +{ +public: + typedef std::vector fa_flags_t; +private: + + friend class Logger; + friend class LogDispatcher; + char initialized; // Marker to detect uninitialized object + + fa_flags_t enabled_fa; // NOTE: assumed atomic reading + LogLevel::type max_level; // NOTE: assumed atomic reading + std::ostream* log_stream; + HVU_LOG_HANDLER_FN* loghandler_fn; + void* loghandler_opaque; + mutable HVU_EXT_MUTEX config_lock; + int flags; + std::vector loggers; + + // Index of 'names' and 'enabled_fa' come together + // and they are numeric index of the logger. + std::vector names; + +public: + + Logger general; + + size_t size() const { return names.size(); } + + const std::string& name(size_t ix) const + { + static const std::string& emp = ""; + return ix >= names.size() ? emp : names[ix]; + } + + int find_id(const std::string& name) const + { + // Linear search, but we state the number of FAs will be + // relatively low and will only happen in the setup time + // of the program. + for (size_t i = 0; i < names.size(); ++i) + if (names[i] == name) + return int(i); + + return -1; + } + + // Setters + void set_handler(void* opaque, HVU_LOG_HANDLER_FN* fn) + { + HVU_EXT_LOCKGUARD gg(config_lock); + loghandler_fn = fn; + loghandler_opaque = opaque; + } + + void set_flags(int f) + { + HVU_EXT_LOCKGUARD gg(config_lock); + flags = f; + } + + void set_stream(std::ostream& str) + { + HVU_EXT_LOCKGUARD gg(config_lock); + log_stream = &str; + } + + void set_maxlevel(LogLevel::type l) + { + HVU_EXT_LOCKGUARD gg(config_lock); + max_level = l; + updateLoggersState(); + } + + void enable_fa(const std::string& name, bool enabled) + { + HVU_EXT_LOCKGUARD gg(config_lock); + + for (size_t i = 0; i < names.size(); ++i) + if (names[i] == name) + { + enabled_fa[i] = enabled; + break; + } + } + + // XXX You can add the use of std::array in C++11 mode. + void enable_fa(const int* farray, size_t fs, bool enabled) + { + HVU_EXT_LOCKGUARD gg(config_lock); + if (fs == 0) + { + if (enabled) + enabled_fa = fa_flags_t(enabled_fa.size(), enabled); + else + { + enabled_fa = fa_flags_t(enabled_fa.size(), enabled); + + // General can never be disabled. + enabled_fa[0] = true; + } + } + else + { + for (size_t i = 0; i < fs; ++i) + { + size_t fa = farray[i]; + if (fa < enabled_fa.size()) + enabled_fa[fa] = true; + } + } + updateLoggersState(); + } + + void setup_fa(const std::set& selected) + { + HVU_EXT_LOCKGUARD gg(config_lock); + for (size_t i = 0; i < enabled_fa.size(); ++i) + enabled_fa[i] = bool(selected.count(i)); + updateLoggersState(); + } + + void setup_fa(const std::set& selected, bool enabled) + { + HVU_EXT_LOCKGUARD gg(config_lock); + std::set::const_iterator i = selected.begin(), e = selected.end(); + for (; i != e; ++i) + if (size_t(*i) < enabled_fa.size()) + enabled_fa[*i] = enabled; + updateLoggersState(); + } + + int generate_fa_id(const std::string& name) + { + HVU_EXT_LOCKGUARD gg(config_lock); + + // 'names' and 'enabled_fa' grow together! + size_t firstfree = names.size(); + names.push_back(name); + enabled_fa.push_back(false); + return int(firstfree); + } + + LogConfig() + : initialized(1) // global objects are 0-initialized + , max_level(LogLevel::warning) + , log_stream(&std::cerr) + , loghandler_fn() + , loghandler_opaque() + , flags() + , general("GENERAL", *this, true, "HVU.gg") + { + // XXX May do some verification code if LogConfig is + // a global variable. + } + + ~LogConfig() + { + } + + // XXX Add TSA markers for lock/unlock + void lock() const { config_lock.lock(); } + void unlock() const { config_lock.unlock(); } + + void subscribe(LogDispatcher*); + void unsubscribe(LogDispatcher*); + void updateLoggersState(); +}; + +struct LogConfigSingleton +{ + // If you declare this as a global object, + // this variable will be filled with zeros. + LogConfig* this_instance; + char memory[sizeof (LogConfig)]; + + // NOTE: This kind of singleton isn't thread-resistant, although + // this kind of object is intended to be used in global variables + // only. So the only dillema is whether the object being initialized + // is the first one, or not. Global constructor may construct objects + // in whatever order, but all initialization happen in a single thread. + LogConfig& instance() + { + if (!this_instance) + this_instance = new(memory) LogConfig; + + return *this_instance; + } +}; + +inline Logger::Logger(const std::string& idname, class LogConfig& config, bool initially_enabled, const char* logger_pfx): + m_fa(config.generate_fa_id(idname)), + Debug (m_fa, initially_enabled, config, LogLevel::debug, " D", logger_pfx), + Note (m_fa, initially_enabled, config, LogLevel::note, ".N", logger_pfx), + Warn (m_fa, initially_enabled, config, LogLevel::warning, "!W", logger_pfx), + Error (m_fa, initially_enabled, config, LogLevel::error, "*E", logger_pfx), + Fatal (m_fa, initially_enabled, config, LogLevel::fatal, "!!FATAL!!", logger_pfx) +{ + if (!config.initialized) + { + // Global object initialization problem! + throw std::runtime_error("Config object can be used only if declared in the same file"); + } + config.enabled_fa[m_fa] = initially_enabled; +} + +inline bool LogDispatcher::isset(int flg) { return (src_config->flags & flg) != 0; } + + +#if HAVE_CXX11 + +template +inline void LogDispatcher::PrintLogLine(const char* file, int line, const std::string& area, Args&&... args) +{ + (void)file; + (void)line; + (void)area; +#if ENABLE_LOGGING + Proxy(*this).dispatch(args...); +#else + (void)sizeof...(args); +#endif +} + +#else // !HAVE_CXX11 + +template +inline void LogDispatcher::PrintLogLine(const char* file, int line, const std::string& area, const Arg& arg) +{ + (void)file; + (void)line; + (void)area; +#if ENABLE_LOGGING + Proxy(*this) << arg; +#else + (void)(arg); +#endif +} + +#endif // HAVE_CXX11 + +} +} + +#endif // INC_SRT_LOGGING_H diff --git a/srtcore/logging_api.h b/logging/logging_api.h similarity index 62% rename from srtcore/logging_api.h rename to logging/logging_api.h index 4fc3b812b..1836fddfd 100644 --- a/srtcore/logging_api.h +++ b/logging/logging_api.h @@ -13,8 +13,13 @@ written by Haivision Systems Inc. *****************************************************************************/ -#ifndef INC_SRT_LOGGING_API_H -#define INC_SRT_LOGGING_API_H +// This file contains definitions that can be provided for the application that +// would like to control the logging of a library. Part if this can be also used +// in a C application, while you only need C++ code to directly deal with the +// logging system. + +#ifndef INC_HVU_LOGGING_API_H +#define INC_HVU_LOGGING_API_H // These are required for access functions: // - adding FA (requires set) @@ -22,10 +27,11 @@ written by #ifdef __cplusplus #include #include +#include #endif #ifdef _WIN32 -#include "win/syslog_defs.h" +#include "windows_syslog.h" #else #include #endif @@ -36,41 +42,34 @@ written by #define LOG_DEBUG_TRACE 8 #endif // It's unused anyway, just for the record. -#define SRT_LOG_LEVEL_MIN LOG_CRIT -#define SRT_LOG_LEVEL_MAX LOG_DEBUG +#define HVU_LOG_LEVEL_MIN LOG_CRIT +#define HVU_LOG_LEVEL_MAX LOG_DEBUG // Flags -#define SRT_LOGF_DISABLE_TIME 1 -#define SRT_LOGF_DISABLE_THREADNAME 2 -#define SRT_LOGF_DISABLE_SEVERITY 4 -#define SRT_LOGF_DISABLE_EOL 8 +#define HVU_LOGF_DISABLE_TIME 1 +#define HVU_LOGF_DISABLE_THREADNAME 2 +#define HVU_LOGF_DISABLE_SEVERITY 4 +#define HVU_LOGF_DISABLE_EOL 8 -// Handler type. -typedef void SRT_LOG_HANDLER_FN(void* opaque, int level, const char* file, int line, const char* area, const char* message); +// Handler type - provided for C API. +typedef void HVU_LOG_HANDLER_FN(void* opaque, int level, const char* file, int line, const char* area, const char* message); #ifdef __cplusplus -namespace srt_logging +namespace hvu { - - -struct LogFA +namespace logging { -private: - int value; -public: - operator int() const { return value; } - - LogFA(int v): value(v) - { - // Generally this was what it has to be used for. - // Unfortunately it couldn't be agreed with the - //logging_fa_all.insert(v); - } -}; -const LogFA LOGFA_GENERAL = 0; +class LogConfig; +// same as HVU_LOG_HANDLER_FN +typedef void loghandler_fn_t(void* opaque, int level, const char* file, int line, const char* area, const char* message); +// Same as C-API flags +const int LOGF_DISABLE_TIME = 1, + LOGF_DISABLE_THREADNAME = 2, + LOGF_DISABLE_SEVERITY = 4, + LOGF_DISABLE_EOL = 8; namespace LogLevel { @@ -86,6 +85,8 @@ namespace LogLevel enum type { + invalid = -1, + fatal = LOG_CRIT, // Fatal vs. Error: with Error, you can still continue. error = LOG_ERR, @@ -99,9 +100,13 @@ namespace LogLevel }; } +extern LogLevel::type parse_level(const std::string&); +extern std::set parse_fa(const hvu::logging::LogConfig& config, std::string fa, std::set* punknown = NULL); + class Logger; -} +} // /logging +} // /hvu #endif #endif diff --git a/srtcore/ofmt.h b/logging/ofmt.h similarity index 99% rename from srtcore/ofmt.h rename to logging/ofmt.h index c5aaaed24..5b9c5c021 100644 --- a/srtcore/ofmt.h +++ b/logging/ofmt.h @@ -44,8 +44,8 @@ written by // definition support. This is only the basic fragment to be used with the logging system, // hence it provides only a wrapper over std::stringstream. -#ifndef INC_SRT_OFMT_H -#define INC_SRT_OFMT_H +#ifndef INC_HVU_OFMT_H +#define INC_HVU_OFMT_H #include #include @@ -61,7 +61,7 @@ written by #endif -namespace srt +namespace hvu { template @@ -656,7 +656,7 @@ std::string fmts(const Value& val, const fmtc& fmtspec) // This prevents the macro from being used with anything else // than a string literal. Version of ""_V UDL available for C++03. -#define OFMT_RAWSTR(arg) srt::internal::CreateRawString_FWD("" arg) +#define OFMT_RAWSTR(arg) ::hvu::internal::CreateRawString_FWD("" arg) diff --git a/logging/ofmt.md b/logging/ofmt.md new file mode 100644 index 000000000..be62ebab1 --- /dev/null +++ b/logging/ofmt.md @@ -0,0 +1,158 @@ +Introduction +============ + +The iostream library has many advantages over the old C's printf function, +but the design has flaws: the formatting specification exists as a state of +the stream, which can be modified on the fly through manipulators. +For example, once you send `hex` manipulator into the stream, all integers will +be printed in hex since this time, until you change it back to `dec`. +This includes the instruction of sending to a stream happening anyhow next, +including after some instructions or in another function. The rules for +iostream manipulators only state that the `width` parameter is reset to 0, +and only after printing value of a type, for which the `operator<<` is +overloaded in the C++ standard library. All other parameters just get +changed and there's even no method to reset settings to system defaults +(you can do it by doing save-and-restore configuration, but it's on your +head as well to remember the system configuration in the beginning, which +is actually impossible in case of a library). + +To fix this problem, you can use the so-called On-Demand Tagged API. That is, +instead of specifying the configuration by changing the stream's state, you can +choose to just apply a format specification for a single value using the +supplied `fmt` function: + +``` +cout << fmt(x, fmtc().hex()) << " " << y; // y printed as dec +``` + +(Note here that to compile this fragment, you need to include `ofmt_iostream.h`). + +The formatting specification is using the `fmtc` structure to achieve it, +which prevents from polluting the global namespace with too many names +as well as allows to save the configuration in a variable so that it can +be specified for multiple values: + +``` +fmtc hex04 = fmtc().hex().fillzero().width(4); +cout << fmt(a, hex04) << ":" << fmt(b, hex04); +``` + +Although for a single manipulator there is prepared also a simplified version +using the iomanip manipulators: + +``` +cout << fmt(x, hex) << " " << y; // y printed as dec +``` + +(Potentially this can be extended to handle multiple iomanip formatters, +but it's not implemented yet). + +This solution is compatible with C++98/C++03 version. Some alternative, more +comfortable API is provided for C++11. + + +Formatting flags +================ + +The following configuration items are available in `fmtc` type: + +* `width(int field_length)`: set minimum field length to `field_length` +* `precision(int prec)`: floating-point precision +* `fill(char c)`: character to fill unused space of minimum width +* `fillzero()`: use `0` prefix to fill field width extension +* `left()`, `right()`, `internal()`: alignment control inside wide field +* `dec()`, `hex()`, `oct()`: set numeric base system (lowercase) +* `uhex()`, `uoct()`: uppercase version of the above (for oct only prefix) +* `fhex()`, `ufhex()`: floating-point hex format (C++11 only) +* `general()`, `ugeneral()`: floating-point value-dependent fixed or scientific selection +* `fixed()`: floating-point fixed format +* `exp()`, `scientific()`: floating-point scientific format (exponental) +* `uexp()`, `uscientific()`: floating-point scientific format (exponental) with uppercase E +* `showbase()`: use `0` prefix for oct and `0x` for hex (`0X` if `uhex`) +* `showpos()`: prefix positive numbers with `+` +* `showpoint()`: add decimal point always, even if fraction part is 0 + +(Note: fillzero() sets the `0` character as filling, with regard to the +`char` or `wchar_t` types, and also sets `internal` adjustment field.) + +Note that all of them are implemented as methods that return "itself", so +you can bind settings in chain: + +``` + fmtc().hex().width(8).fillzero().showbase() +``` + +You can also create local variable for this type so that you can define +the format specification and use in multiple `fmt` calls: + +``` +fmtc phex8 = fmtc().hex().width(8).fillzero().showbase(); +``` + +The `width`, `precision` and `fill` methods have a parameter and this way +they can use as well a runtime value. + +Formatting stream utility +========================= + +The idea for stream manipulation with on-demand tagged API is that there are +overloads for several types known as "string form", in which case this +string is directly written into the stream, with bypassing any formatting. +Everything else is passed through the `fmt` function with no config spec, +that is, it will use default formatting. The `fmt` function returns a proxy +object, which will employ std::stringstream for formatting, and then in order +to send to the output stream it will use buffer-to-buffer copy. + +Hence the `ofmtbufstream` class is provided, which is a wrapper around +`std::stringstream` and should be used instead of it in order to utilize the +on-demand tagged API. Beside the "traditional" overloads for `operator<<`, it +provides also the "print" function, which uses multiple arguments ("puts" +additionally adds the end-of-line, just like the standard C "puts" function +does). This function is only available in C++11 version. + + +Iostream support +================ + +This support is not provided by default, but you can use this also with iostream +classes' instances. You need to include "`ofmt_iostream.h`" for this. It provides +extra overloads for the internal types `internal::fmt_proxy` and +`internal::fmt_simple_proxy` so that the result of the `fmt` function can be +handled. Note that the rules as above described for `ofmtstream` do not apply here, +unless you use `fmt_rawstr()` function for every string. + +This provides also a possibility to use `std::put_time` through a special overload +of the `fmt` function. Usage: + +``` +ofmtbufstream out; +... +typedef std::chrono::system_clock sclock; +std::time_t timenow = sclock.to_time_t(sclock.now()); + +out << "Timestamp: " << fmt(*std::localtime(&timenow), "%F %T"); +``` + +(Note that in C++20 there are some easier way to get from `sclock.now()` to +`std::put_time` and you can easily use it through `fmt` instead of `std::put_time`). + + +Additional formatting functions +=============================== + +The `fmt` function returns a proxy that should make the value written into the +stream with appropriate format. Besides there are also other formatting tools: + +* `fmtcat`: a multi-argument function where formatted versions of the arguments +are glued together and returned as `std::string` + +* `fmts`: formats the single value (like with `fmt`) and return it as `std::string`; +the call to `fmts(value, man1, man2)` is equivalent to calling +`fmtcat(fmt(value, man1, man2))` with just one argument + +* `fmt_rawstr`: Turns a string of `std::string` or pointer-length specification +into the `internal::fmt_stringview` type, which can be directly handled by the +`operator<<` overload or `print` method of `ofmtbufstream`. This is also provided +for iostream version. + + diff --git a/srtcore/ofmt_iostream.h b/logging/ofmt_iostream.h similarity index 91% rename from srtcore/ofmt_iostream.h rename to logging/ofmt_iostream.h index 40bf0b937..9da4841b2 100644 --- a/srtcore/ofmt_iostream.h +++ b/logging/ofmt_iostream.h @@ -32,7 +32,7 @@ template< > inline std::basic_ostream& operator<<( std::basic_ostream& os, - const srt::internal::fmt_proxy& valproxy + const hvu::internal::fmt_proxy& valproxy ) { valproxy.sendto(os); @@ -46,7 +46,7 @@ template< > inline std::basic_ostream& operator<<( std::basic_ostream& os, - const srt::internal::fmt_simple_proxy& valproxy + const hvu::internal::fmt_simple_proxy& valproxy ) { valproxy.sendto(os); @@ -58,13 +58,13 @@ inline std::basic_ostream& operator<<( // facilities, but you can pass the string through fmt() and // this way you make a stringview-forwarder and formating gets // bypassed. -inline std::ostream& operator<<( std::ostream& os, const srt::internal::fmt_stringview& v) +inline std::ostream& operator<<( std::ostream& os, const hvu::internal::fmt_stringview& v) { os.write(v.data(), v.size()); return os; } -namespace srt +namespace hvu { namespace internal { diff --git a/common/win/syslog_defs.h b/logging/windows_syslog.h similarity index 100% rename from common/win/syslog_defs.h rename to logging/windows_syslog.h diff --git a/scripts/generate-logging-defs.tcl b/scripts/generate-logging-defs.tcl deleted file mode 100755 index a86ab9a62..000000000 --- a/scripts/generate-logging-defs.tcl +++ /dev/null @@ -1,454 +0,0 @@ -#!/usr/bin/tclsh -#* -#* SRT - Secure, Reliable, Transport -#* Copyright (c) 2020 Haivision Systems Inc. -#* -#* This Source Code Form is subject to the terms of the Mozilla Public -#* License, v. 2.0. If a copy of the MPL was not distributed with this -#* file, You can obtain one at http://mozilla.org/MPL/2.0/. -#* -#*/ -# -#***************************************************************************** -#written by -# Haivision Systems Inc. -#***************************************************************************** - -# What fields are there in every entry -set model { - longname - shortname - id - description -} - -# Logger definitions. -# Comments here allowed, just only for the whole line. - -# Use values greater than 0. Value 0 is reserved for LOGFA_GENERAL, -# which is considered always enabled. -set loggers { - GENERAL gg 0 "General uncategorized log, for serious issues only" - SOCKMGMT sm 1 "Socket create/open/close/configure activities" - CONN cn 2 "Connection establishment and handshake" - XTIMER xt 3 "The checkTimer and around activities" - TSBPD ts 4 "The TsBPD thread" - RSRC rs 5 "System resource allocation and management" - CONGEST cc 7 "Congestion control module" - PFILTER pf 8 "Packet filter module" - API_CTRL ac 11 "API part for socket and library managmenet" - QUE_CTRL qc 13 "Queue control activities" - EPOLL_UPD ei 16 "EPoll, internal update activities" - - API_RECV ar 21 "API part for receiving" - BUF_RECV br 22 "Buffer, receiving side" - QUE_RECV qr 23 "Queue, receiving side" - CHN_RECV kr 24 "CChannel, receiving side" - GRP_RECV gr 25 "Group, receiving side" - - API_SEND as 31 "API part for sending" - BUF_SEND bs 32 "Buffer, sending side" - QUE_SEND qs 33 "Queue, sending side" - CHN_SEND ks 34 "CChannel, sending side" - GRP_SEND gs 35 "Group, sending side" - - INTERNAL in 41 "Internal activities not connected directly to a socket" - QUE_MGMT qm 43 "Queue, management part" - CHN_MGMT km 44 "CChannel, management part" - GRP_MGMT gm 45 "Group, management part" - EPOLL_API ea 46 "EPoll, API part" -} - -set hidden_loggers { - # Haicrypt logging - usually off. - HAICRYPT hc 6 "Haicrypt module area" - - # defined in apps, this is only a stub to lock the value - APPLOG ap 10 "Applications" -} - -set globalheader { - /* - WARNING: Generated from ../scripts/generate-logging-defs.tcl - - DO NOT MODIFY. - - Copyright applies as per the generator script. - */ - -} - - -# This defines, what kind of definition will be generated -# for a given file out of the log FA entry list. - -# Fields: -# - prefix/postfix model -# - logger_format -# - hidden_logger_format - -# COMMENTS NOT ALLOWED HERE! Only as C++ comments inside C++ model code. -set special { - srtcore/logger_default.cpp { - if {"$longname" == "HAICRYPT"} { - puts $od " -#if ENABLE_HAICRYPT_LOGGING - allfa.set(SRT_LOGFA_HAICRYPT, true); -#endif" - } - } -} - -proc GenerateModelForSrtH {} { - - # `path` will be set to the git top path - global path - - set fd [open [file join $path srtcore/srt.h] r] - - set contents "" - - set state read - set pass looking - - while { [gets $fd line] != -1 } { - if { $state == "read" } { - - if { $pass != "passed" } { - - set re [regexp {SRT_LOGFA BEGIN GENERATED SECTION} $line] - if {$re} { - set state skip - set pass found - } - - } - - append contents "$line\n" - continue - } - - if {$state == "skip"} { - if { [string trim $line] == "" } { - # Empty line, continue skipping - continue - } - - set re [regexp {SRT_LOGFA END GENERATED SECTION} $line] - if {!$re} { - # Still SRT_LOGFA definitions - continue - } - - # End of generated section. Switch back to pass-thru. - - # First fill the gap - append contents "\n\$entries\n\n" - - append contents "$line\n" - set state read - set pass passed - } - } - - close $fd - - # Sanity check - if {$pass != "passed"} { - error "Invalid contents of `srt.h` file, can't find '#define SRT_LOGFA_' phrase" - } - - return $contents -} - -# COMMENTS NOT ALLOWED HERE! Only as C++ comments inside C++ model code. -# (NOTE: Tcl syntax highlighter will likely falsely highlight # as comment here) -# -# Model: TARGET-NAME { format-model logger-pattern hidden-logger-pattern } -# -# Special syntax: -# -# % : a high-level command execution. This declares a command that -# must be executed to GENERATE the model. Then, [subst] is executed -# on the results. -# -# = : when placed as the hidden-logger-pattern, it's equal to logger-pattern. -# -set generation { - srtcore/srt.h { - - {%GenerateModelForSrtH} - - {#define [format "%-20s %-3d" SRT_LOGFA_${longname} $id] // ${shortname}log: $description} - - = - } - - srtcore/logger_default.cpp { - - { - $globalheader - #include "srt.h" - #include "logging.h" - #include "logger_defs.h" - - namespace srt_logging - { - AllFaOn::AllFaOn() - { - $entries - } - } // namespace srt_logging - - } - - { - allfa.set(SRT_LOGFA_${longname}, true); - } - } - - srtcore/logger_defs.cpp { - - { - $globalheader - #include "srt.h" - #include "logging.h" - #include "logger_defs.h" - - namespace srt_logging { AllFaOn logger_fa_all; } - // We need it outside the namespace to preserve the global name. - // It's a part of "hidden API" (used by applications) - SRT_API srt_logging::LogConfig srt_logger_config(srt_logging::logger_fa_all.allfa); - - namespace srt_logging - { - $entries - } // namespace srt_logging - } - - { - Logger ${shortname}log(SRT_LOGFA_${longname}, srt_logger_config, "SRT.${shortname}"); - } - } - - srtcore/logger_defs.h { - { - $globalheader - #ifndef INC_SRT_LOGGER_DEFS_H - #define INC_SRT_LOGGER_DEFS_H - - #include "srt.h" - #include "logging.h" - - namespace srt_logging - { - struct AllFaOn - { - LogConfig::fa_bitset_t allfa; - AllFaOn(); - }; - - $entries - - } // namespace srt_logging - - #endif - } - - { - extern Logger ${shortname}log; - } - } - - apps/logsupport_appdefs.cpp { - { - $globalheader - #include "logsupport.hpp" - - LogFANames::LogFANames() - { - $entries - } - } - - { - Install("$longname", SRT_LOGFA_${longname}); - } - - { - Install("$longname", SRT_LOGFA_${longname}); - } - } -} - -# EXECUTION - -set here [file dirname [file normalize $argv0]] - -if {[lindex [file split $here] end] != "scripts"} { - puts stderr "The script is in weird location." - exit 1 -} - -set path [file join {*}[lrange [file split $here] 0 end-1]] - -# Utility. Allows to put line-oriented comments and have empty lines -proc no_comments {input} { - set output "" - foreach line [split $input \n] { - set nn [string trim $line] - if { $nn == "" || [string index $nn 0] == "#" } { - continue - } - append output $line\n - } - - return $output -} - -proc generate_file {od target} { - - global globalheader - lassign [dict get $::generation $target] format_model pattern hpattern - - set ptabprefix "" - - if {[string index $format_model 0] == "%"} { - set command [string range $format_model 1 end] - set format_model [eval $command] - } - - if {$format_model != ""} { - set beginindex 0 - while { [string index $format_model $beginindex] == "\n" } { - incr beginindex - } - - set endindex $beginindex - while { [string is space [string index $format_model $endindex]] } { - incr endindex - } - - set tabprefix [string range $pattern $beginindex $endindex-1] - - set newformat "" - foreach line [split $format_model \n] { - if {[string trim $line] == ""} { - append newformat "\n" - continue - } - - if {[string first $tabprefix $line] == 0} { - set line [string range $line [string length $tabprefix] end] - } - append newformat $line\n - - set ie [string first {$} $line] - if {$ie != -1} { - if {[string range $line $ie end] == {$entries}} { - set ptabprefix "[string range $line 0 $ie-1]" - } - } - } - - set format_model $newformat - unset newformat - } - - set entries "" - - if {[string trim $pattern] != "" } { - - set prevval 0 - set pattern [string trim $pattern] - - # The first "$::model" will expand into variable names - # as defined there. - foreach [list {*}$::model] [no_comments $::loggers] { - if {$prevval + 1 != $id} { - append entries "\n" - } - - append entries "${ptabprefix}[subst -nobackslashes $pattern]\n" - set prevval $id - } - } - - if {$hpattern != ""} { - if {$hpattern == "="} { - set hpattern $pattern - } else { - set hpattern [string trim $hpattern] - } - - # Extra line to separate from the normal entries - append entries "\n" - foreach [list {*}$::model] [no_comments $::hidden_loggers] { - append entries "${ptabprefix}[subst -nobackslashes $hpattern]\n" - } - } - - if { [dict exists $::special $target] } { - set code [subst [dict get $::special $target]] - - # The code should contain "append entries" ! - eval $code - } - - set entries [string trim $entries] - - if {$format_model == ""} { - set format_model $entries - } - - # For any case, cut external spaces - puts $od [string trim [subst -nocommands -nobackslashes $format_model]] -} - -proc debug_vars {list} { - set output "" - foreach name $list { - upvar $name _${name} - lappend output "${name}=[set _${name}]" - } - - return $output -} - -# MAIN - -set entryfiles $argv - -if {$entryfiles == ""} { - set entryfiles [dict keys $generation] -} else { - foreach ef $entryfiles { - if { $ef ni [dict keys $generation] } { - error "Unknown generation target: $entryfiles" - } - } -} - -foreach f $entryfiles { - - # Set simple relative path, if the file isn't defined as path. - if { [llength [file split $f]] == 1 } { - set filepath $f - } else { - set filepath [file join $path $f] - } - - puts stderr "Generating '$filepath'" - set od [open $filepath.tmp w] - generate_file $od $f - close $od - if { [file exists $filepath] } { - puts "WARNING: will overwrite exiting '$f'. Hit ENTER to confirm, or Control-C to stop" - gets stdin - } - - file rename -force $filepath.tmp $filepath -} - -puts stderr Done. - diff --git a/scripts/logging-config.tcl b/scripts/logging-config.tcl new file mode 100644 index 000000000..2b6ef1e8c --- /dev/null +++ b/scripts/logging-config.tcl @@ -0,0 +1,91 @@ +#* +#* SRT - Secure, Reliable, Transport +#* Copyright (c) 2020 Haivision Systems Inc. +#* +#* This Source Code Form is subject to the terms of the Mozilla Public +#* License, v. 2.0. If a copy of the MPL was not distributed with this +#* file, You can obtain one at http://mozilla.org/MPL/2.0/. +#* +#*/ +# +#***************************************************************************** +#written by +# Haivision Systems Inc. +#***************************************************************************** + +# Logger definitions. +# Comments here allowed, just only for the whole line. + +# Structure: { name-id display-id help-comment } where: +# * name-id: Identifier that can be used to obtain the FA identifier (internal) +# * display-id: This FA will be displayed in the log header with the prefix (see below) +# * help-comment: Unused currently, visible only in this table for now. +set loggers_table { + sockmgmt sm "Socket create/open/close/configure activities" + conn cn "Connection establishment and handshake" + xtimer xt "The checkTimer and around activities" + tsbpd ts "The TsBPD thread" + rsrc rs "System resource allocation and management" + congest cc "Congestion control module" + pfilter pf "Packet filter module" + api_ctrl ac "API part for socket and library managmenet" + que_ctrl qc "Queue control activities" + epoll_upd ei "EPoll, internal update activities" + + api_recv ar "API part for receiving" + buf_recv br "Buffer, receiving side" + que_recv qr "Queue, receiving side" + chn_recv kr "CChannel, receiving side" + grp_recv gr "Group, receiving side" + + api_send as "API part for sending" + buf_send bs "Buffer, sending side" + que_send qs "Queue, sending side" + chn_send ks "CChannel, sending side" + grp_send gs "Group, sending side" + + internal in "Internal activities not connected directly to a socket" + que_mgmt qm "Queue, management part" + chn_mgmt km "CChannel, management part" + grp_mgmt gm "Group, management part" + epoll_api ea "EPoll, API part" +} + +# This is the prefix when displaying the FA in the log header. +# For example, if your display-id is "cc", this will be "${loggers_prefix}cc" +set loggers_prefix "SRT." + +# The namespace where the global logger variables and the logger config will +# be defined. Use dot separation rather than ::. +set loggers_namespace srt.logging + +# Name of the config object where the loggers will be subscribed. +set loggers_configname logger_config + +# Whether all loggers should be enabled or disabled by default +set loggers_enabled true + +# This will be used to construct the variable name. The +# display-id field will be used, followed by this one. +set loggers_varsuffix log + +# OPTIONAL, you may want to create also a link to the general +# logger, for convenience. +set loggers_generallink gglog + +# Name of the generated header and source file (.cpp and .h suffixes +# will be added to this name). May enclose the directory name. +set loggers_modulename srtcore/logger_fas + +# This contents will be pasted into the generated header and source +# file in the beginning. +set loggers_globalheader { + /* + WARNING: Generated from ../logging/generate-logging-defs.tcl + + DO NOT MODIFY. + + Copyright applies as per the generator script. + */ + +} diff --git a/srtcore/api.cpp b/srtcore/api.cpp index d0c39baa0..436bc7921 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -65,7 +65,7 @@ modified by #include "core.h" #include "epoll.h" #include "logging.h" -#include "threadname.h" +#include "hvu_compat.h" #include "srt.h" #ifdef _WIN32 @@ -77,7 +77,7 @@ modified by #endif using namespace std; -using namespace srt_logging; +using namespace srt::logging; using namespace srt::sync; namespace srt @@ -249,9 +249,7 @@ string CUDTUnited::CONID(SRTSOCKET sock) if (int32_t(sock) <= 0) // embraces SRT_INVALID_SOCK, SRT_SOCKID_CONNREQ and illegal negative domain return ""; - ofmtbufstream os; - os << "@" << int(sock) << ":"; - return os.str(); + return hvu::fmtcat("@", int(sock), ":"); } bool CUDTUnited::startGarbageCollector() @@ -1732,7 +1730,7 @@ SRTSOCKET CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, for (size_t i = 0; i < g.m_config.size(); ++i) { HLOGC(aclog.Debug, log << "groupConnect: OPTION @" << sid << " #" << g.m_config[i].so); - error_reason = fmtcat("group-derived option: #", g.m_config[i].so); + error_reason = hvu::fmtcat("group-derived option: #", g.m_config[i].so); ns->core().setOpt(g.m_config[i].so, &g.m_config[i].value[0], (int)g.m_config[i].value.size()); } @@ -2273,8 +2271,6 @@ SRTSTATUS CUDTUnited::close(const SRTSOCKET u, int reason) #if ENABLE_BONDING void CUDTUnited::deleteGroup(CUDTGroup* g) { - using srt_logging::gmlog; - sync::ExclusiveLock cg(m_GlobControlLock); return deleteGroup_LOCKED(g); } @@ -3721,9 +3717,8 @@ void CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& reqaddr, const UDP } catch (const CUDTException& x) { - IF_HEAVY_LOGGING(char errmsg[161]); HLOGC(smlog.Debug, log << "installMuxer: FAILED; removing multiplexer: ERROR #" << x.getErrorCode() - << ": " << x.getErrorMessage() << ": errno=" << x.getErrno() << SysStrError(x.getErrno(), errmsg, 160)); + << ": " << x.getErrorMessage() << ": errno=" << x.getErrno() << ": " << hvu::SysStrError(x.getErrno())); m_mMultiplexer.erase(muxid); throw; } @@ -4005,7 +4000,7 @@ bool CUDTUnited::updateListenerMux(CUDTSocket* s, const CUDTSocket* ls) CMultiplexer& m = i->second; #if ENABLE_HEAVY_LOGGING - ofmtbufstream that_muxer; + hvu::ofmtbufstream that_muxer; that_muxer << "id=" << m.id() << " addr=" << m.selfAddr().str(); #endif @@ -5201,61 +5196,47 @@ int CUDT::epoll_wait2(int eid, return ret; } -void setloglevel(LogLevel::type ll) +void setloglevel(hvu::logging::LogLevel::type ll) { - ScopedLock gg(srt_logger_config.mutex); - srt_logger_config.max_level = ll; - srt_logger_config.updateLoggersState(); + srt::logging::logger_config().set_maxlevel(ll); } -void addlogfa(LogFA fa) +void addlogfa(int fa) { - ScopedLock gg(srt_logger_config.mutex); - srt_logger_config.enabled_fa.set(fa, true); - srt_logger_config.updateLoggersState(); + srt_addlogfa(fa); } -void dellogfa(LogFA fa) +void dellogfa(int fa) { - ScopedLock gg(srt_logger_config.mutex); - srt_logger_config.enabled_fa.set(fa, false); - srt_logger_config.updateLoggersState(); + srt_dellogfa(fa); } -void resetlogfa(set fas) +void resetlogfa(set fas) { - ScopedLock gg(srt_logger_config.mutex); - for (int i = 0; i <= SRT_LOGFA_LASTNONE; ++i) - srt_logger_config.enabled_fa.set(i, fas.count(i)); - srt_logger_config.updateLoggersState(); + std::vector faval; + std::copy(fas.begin(), fas.end(), std::back_inserter(faval)); + + srt_resetlogfa(&faval[0], faval.size()); } void resetlogfa(const int* fara, size_t fara_size) { - ScopedLock gg(srt_logger_config.mutex); - srt_logger_config.enabled_fa.reset(); - for (const int* i = fara; i != fara + fara_size; ++i) - srt_logger_config.enabled_fa.set(*i, true); - srt_logger_config.updateLoggersState(); + srt_resetlogfa(fara, fara_size); } void setlogstream(std::ostream& stream) { - ScopedLock gg(srt_logger_config.mutex); - srt_logger_config.log_stream = &stream; + srt::logging::logger_config().set_stream(stream); } -void setloghandler(void* opaque, SRT_LOG_HANDLER_FN* handler) +void setloghandler(void* opaque, HVU_LOG_HANDLER_FN* handler) { - ScopedLock gg(srt_logger_config.mutex); - srt_logger_config.loghandler_opaque = opaque; - srt_logger_config.loghandler_fn = handler; + srt::logging::logger_config().set_handler(opaque, handler); } void setlogflags(int flags) { - ScopedLock gg(srt_logger_config.mutex); - srt_logger_config.flags = flags; + srt::logging::logger_config().set_flags(flags); } SRT_API bool setstreamid(SRTSOCKET u, const std::string& sid) diff --git a/srtcore/buffer_rcv.cpp b/srtcore/buffer_rcv.cpp index 392d26c40..401b3f61e 100644 --- a/srtcore/buffer_rcv.cpp +++ b/srtcore/buffer_rcv.cpp @@ -48,15 +48,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "buffer_rcv.h" #include "logging.h" +#include "logger_fas.h" using namespace std; using namespace srt::sync; -using namespace srt_logging; -namespace srt_logging -{ - extern Logger brlog; -} +using namespace srt::logging; +using namespace hvu; #define rbuflog brlog namespace srt { diff --git a/srtcore/buffer_snd.cpp b/srtcore/buffer_snd.cpp index e04743e1f..ab45cdb53 100644 --- a/srtcore/buffer_snd.cpp +++ b/srtcore/buffer_snd.cpp @@ -62,7 +62,7 @@ modified by namespace srt { using namespace std; -using namespace srt_logging; +using namespace srt::logging; using namespace sync; CSndBuffer::CSndBuffer(int ip_family, int size, int maxpld, int authtag) @@ -142,7 +142,8 @@ void CSndBuffer::addBuffer(const char* data, int len, SRT_MSGCTRL& w_mctrl) const int iNumBlocks = countNumPacketsRequired(len, iPktLen); HLOGC(bslog.Debug, - log << "addBuffer: needs=" << iNumBlocks << " buffers for " << len << " bytes. Taken=" << m_iCount << "/" << m_iSize); + log << "addBuffer: needs=" << iNumBlocks << " buffers for " << len << " bytes. Taken=" + << m_iCount.load() << "/" << m_iSize); // Retrieve current time before locking the mutex to be closer to packet submission event. const steady_clock::time_point tnow = steady_clock::now(); @@ -243,7 +244,7 @@ int CSndBuffer::addBufferFromFile(fstream& ifs, int len) const int iNumBlocks = countNumPacketsRequired(len, iPktLen); HLOGC(bslog.Debug, - log << "addBufferFromFile: size=" << m_iCount << " reserved=" << m_iSize << " needs=" << iPktLen + log << "addBufferFromFile: size=" << m_iCount.load() << " reserved=" << m_iSize << " needs=" << iPktLen << " buffers for " << len << " bytes"); // dynamically increase sender buffer @@ -394,7 +395,7 @@ int32_t CSndBuffer::getMsgNoAt(const int offset) { // Prevent accessing the last "marker" block LOGC(bslog.Error, - log << "CSndBuffer::getMsgNoAt: IPE: offset=" << offset << " not found, max offset=" << m_iCount); + log << "CSndBuffer::getMsgNoAt: IPE: offset=" << offset << " not found, max offset=" << m_iCount.load()); return SRT_MSGNO_CONTROL; } diff --git a/srtcore/buffer_tools.cpp b/srtcore/buffer_tools.cpp index 85ae3188d..002fc26a6 100644 --- a/srtcore/buffer_tools.cpp +++ b/srtcore/buffer_tools.cpp @@ -53,13 +53,13 @@ modified by #include "platform_sys.h" #include "buffer_tools.h" #include "packet.h" -#include "logger_defs.h" +#include "logger_fas.h" #include "utilities.h" namespace srt { using namespace std; -using namespace srt_logging; +using namespace srt::logging; using namespace sync; // You can change this value at build config by using "ENFORCE" options. diff --git a/srtcore/channel.cpp b/srtcore/channel.cpp index 380687d9d..f45a64576 100644 --- a/srtcore/channel.cpp +++ b/srtcore/channel.cpp @@ -53,11 +53,11 @@ modified by #include "platform_sys.h" #include #include // Logging -#include +#include #include #include "channel.h" -#include "core.h" // srt_logging:kmlog +#include "core.h" // srt::logging::kmlog #include "packet.h" #include "logging.h" #include "netinet_any.h" @@ -68,7 +68,8 @@ typedef int socklen_t; #endif using namespace std; -using namespace srt_logging; +using namespace srt::logging; +using namespace hvu; // ofmt namespace srt { @@ -208,7 +209,7 @@ void CChannel::createSocket(int family) char msg[160]; LOGC(kmlog.Error, log << "::setsockopt: failed to set IPPROTO_IPV6/IPV6_V6ONLY = " << m_mcfg.iIpV6Only << ": " - << SysStrError(err, msg, 159)); + << hvu_SysStrError(err, msg, 159)); } #endif // ENABLE_LOGGING } diff --git a/srtcore/common.cpp b/srtcore/common.cpp index 7b6633148..fea79c381 100644 --- a/srtcore/common.cpp +++ b/srtcore/common.cpp @@ -74,16 +74,11 @@ modified by #include "netinet_any.h" #include "logging.h" #include "packet.h" -#include "threadname.h" +#include "logger_fas.h" using namespace std; using namespace srt::sync; -using namespace srt_logging; - -namespace srt_logging -{ -extern Logger inlog; -} +using namespace srt::logging; namespace srt { @@ -196,7 +191,6 @@ bool checkMappedIPv4(const uint16_t* addr) // Consider simply returning sockaddr_any by value. void CIPAddress::pton(sockaddr_any& w_addr, const uint32_t ip[4], const sockaddr_any& peer) { - //using ::srt_logging::inlog; uint32_t* target_ipv4_addr = NULL; if (peer.family() == AF_INET) @@ -283,6 +277,8 @@ void CIPAddress::pton(sockaddr_any& w_addr, const uint32_t ip[4], const sockaddr else { #if ENABLE_LOGGING + using namespace hvu; + ofmtbufstream peeraddr_form; fmtc hex04 = fmtc().hex().fillzero().width(4); peeraddr_form << fmt(peeraddr16[0], hex04); @@ -586,10 +582,6 @@ vector GetLocalInterfaces() } -} // namespace srt - -namespace srt_logging -{ // Value display utilities // (also useful for applications) @@ -647,5 +639,5 @@ string MemberStatusStr(SRT_MEMBERSTATUS s) } -} // (end namespace srt_logging) +} // namespace srt diff --git a/srtcore/common.h b/srtcore/common.h index 9894e4761..d39b24e38 100644 --- a/srtcore/common.h +++ b/srtcore/common.h @@ -180,14 +180,12 @@ struct CNetworkInterface } -namespace srt_logging +namespace srt { + std::string SockStatusStr(SRT_SOCKSTATUS s); std::string MemberStatusStr(SRT_MEMBERSTATUS s); -} -namespace srt -{ // Class CUDTException exposed for C++ API. // This is actually useless, unless you'd use a DIRECT C++ API, diff --git a/srtcore/congctl.cpp b/srtcore/congctl.cpp index 47da5640a..4f5ad148f 100644 --- a/srtcore/congctl.cpp +++ b/srtcore/congctl.cpp @@ -35,7 +35,7 @@ using namespace std; using namespace srt::sync; -using namespace srt_logging; +using namespace srt::logging; namespace srt { diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 08bcefd98..34a360312 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -87,11 +87,12 @@ modified by #include "logging.h" #include "crypto.h" #include "logging_api.h" // Required due to containing extern srt_logger_config -#include "logger_defs.h" +#include "logger_fas.h" using namespace std; using namespace srt::sync; -using namespace srt_logging; +using namespace srt::logging; +using namespace hvu; // ofmt namespace srt { @@ -3581,7 +3582,7 @@ void CUDT::synchronizeWithGroup(CUDTGroup* gp) { HLOGC(gmlog.Debug, log << CONID() << "synchronizeWithGroup: DERIVED ISN: RCV=%" << m_iRcvLastAck << " -> %" << rcv_isn - << " (shift by " << CSeqNo::seqcmp(rcv_isn, m_iRcvLastAck) << ") SND=%" << m_iSndLastAck + << " (shift by " << CSeqNo::seqcmp(rcv_isn, m_iRcvLastAck) << ") SND=%" << m_iSndLastAck.load() << " -> %" << snd_isn << " (shift by " << CSeqNo::seqcmp(snd_isn, m_iSndLastAck) << ")"); setInitialRcvSeq(rcv_isn); setInitialSndSeq(snd_isn); @@ -3590,7 +3591,7 @@ void CUDT::synchronizeWithGroup(CUDTGroup* gp) { HLOGC(gmlog.Debug, log << CONID() << "synchronizeWithGroup: DEFINED ISN: RCV=%" << m_iRcvLastAck << " SND=%" - << m_iSndLastAck); + << m_iSndLastAck.load()); } } #endif @@ -3845,7 +3846,7 @@ void CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn) HLOGC(cnlog.Debug, log << CONID() << "startConnect: success. Parameters: sourceIP=" << m_SourceAddr.str() << " mss=" << m_config.iMSS << " max-cwnd-size=" << m_CongCtl->cgWindowMaxSize() << " cwnd-size=" << m_CongCtl->cgWindowSize() - << " rtt=" << m_iSRTT << " bw=" << m_iBandwidth); + << " rtt=" << m_iSRTT.load() << " bw=" << m_iBandwidth.load()); } // Asynchronous connection @@ -3987,7 +3988,7 @@ void CUDT::sendRendezvousRejection(const sockaddr_any& serv_addr, CPacket& r_rsp r_rsppkt.setLength(size); HLOGC(cnlog.Debug, log << CONID() << "sendRendezvousRejection: using code=" << m_ConnReq.m_iReqType - << " for reject reason code " << m_RejectReason << " (" << srt_rejectreason_str(m_RejectReason) << ")"); + << " for reject reason code " << m_RejectReason.load() << " (" << srt_rejectreason_str(m_RejectReason) << ")"); setPacketTS(r_rsppkt, steady_clock::now()); channel()->sendto(serv_addr, r_rsppkt, m_SourceAddr); @@ -5661,7 +5662,7 @@ int CUDT::rcvDropTooLateUpTo(int seqno, DropReason reason) void CUDT::setInitialRcvSeq(int32_t isn) { m_iRcvLastAck = isn; -#ifdef ENABLE_LOGGING +#if ENABLE_LOGGING m_iDebugPrevLastAck = isn; #endif m_iRcvLastAckAck = isn; @@ -6192,10 +6193,10 @@ SRT_REJECT_REASON CUDT::setupCC() m_tsLastRspAckTime = currtime; m_tsLastSndTime.store(currtime); - HLOGC(rslog.Debug, - log << CONID() << "setupCC: setting parameters: mss=" << m_config.iMSS << " maxCWNDSize/FlowWindowSize=" - << m_iFlowWindowSize << " rcvrate=" << m_iDeliveryRate << "p/s (" << m_iByteDeliveryRate << "B/S)" - << " rtt=" << m_iSRTT << " bw=" << m_iBandwidth); + HLOGC(rslog.Debug, log << CONID() << "setupCC: setting parameters: mss=" << m_config.iMSS + << " maxCWNDSize/FlowWindowSize=" << m_iFlowWindowSize.load() + << " rcvrate=" << m_iDeliveryRate.load() << "p/s (" << m_iByteDeliveryRate.load() << "B/S)" + << " rtt=" << m_iSRTT.load() << " bw=" << m_iBandwidth.load()); if (!updateCC(TEV_INIT, EventVariant(TEV_INIT_RESET))) { @@ -6645,7 +6646,7 @@ int CUDT::sndDropTooLate() } HLOGC(qslog.Debug, - log << CONID() << "SND-DROP: %(" << realack << "-" << m_iSndCurrSeqNo << ") n=" << dpkts << "pkt " << dbytes + log << CONID() << "SND-DROP: %(" << realack << "-" << m_iSndCurrSeqNo.load() << ") n=" << dpkts << "pkt " << dbytes << "B, span=" << buffdelay_ms << " ms, FIRST #" << first_msgno); #if ENABLE_BONDING @@ -7177,7 +7178,8 @@ int CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_excep // After signaling the tsbpd for ready data, report the bandwidth. #if ENABLE_HEAVY_LOGGING double bw = Bps2Mbps(int64_t(m_iBandwidth) * m_iMaxSRTPayloadSize ); - HLOGC(arlog.Debug, log << CONID() << "CURRENT BANDWIDTH: " << bw << "Mbps (" << m_iBandwidth << " buffers per second)"); + HLOGC(arlog.Debug, log << CONID() << "CURRENT BANDWIDTH: " + << bw << "Mbps (" << m_iBandwidth.load() << " buffers per second)"); #endif } return res; @@ -8120,7 +8122,8 @@ bool CUDT::getFirstNoncontSequence(int32_t& w_seq, string& w_log_reason) if (CSeqNo::seqcmp(w_seq, iNextSeqNo) > 0) { - LOGC(xtlog.Error, log << "IPE: NONCONT-SEQUENCE: RCV buffer first non-read %" << w_seq << ", RCV latest seqno %" << m_iRcvCurrSeqNo); + LOGC(xtlog.Error, log << "IPE: NONCONT-SEQUENCE: RCV buffer first non-read %" + << w_seq << ", RCV latest seqno %" << m_iRcvCurrSeqNo.load()); w_seq = iNextSeqNo; } @@ -8516,7 +8519,7 @@ void CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_point const bool isLiteAck = ctrlpkt.getLength() == (size_t)SEND_LITE_ACK; HLOGC(inlog.Debug, - log << CONID() << "ACK covers: " << m_iSndLastDataAck << " - " << ackdata_seqno << " [ACK=" << m_iSndLastAck + log << CONID() << "ACK covers: " << m_iSndLastDataAck.load() << " - " << ackdata_seqno << " [ACK=" << m_iSndLastAck << "]" << (isLiteAck ? "[LITE]" : "[FULL]")); updateSndLossListOnACK(ackdata_seqno); diff --git a/srtcore/core.h b/srtcore/core.h index a3af013d3..607e55052 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -71,7 +71,6 @@ modified by #include "packetfilter.h" #include "socketconfig.h" #include "utilities.h" -#include "logger_defs.h" #include "stats.h" @@ -1040,7 +1039,7 @@ class CUDT CPktTimeWindow<16, 64> m_RcvTimeWindow; // Packet arrival time window int32_t m_iRcvLastAck; // First unacknowledged packet seqno sent in the latest ACK. -#ifdef ENABLE_LOGGING +#if ENABLE_LOGGING int32_t m_iDebugPrevLastAck; #endif int32_t m_iRcvLastAckAck; // (RCV) Latest packet seqno in a sent ACK acknowledged by ACKACK. RcvQTh (sendCtrlAck {r}, processCtrlAckAck {r}, processCtrlAck {r}, connection {w}). diff --git a/srtcore/crypto.cpp b/srtcore/crypto.cpp index a53f2f97c..148ddfe9a 100644 --- a/srtcore/crypto.cpp +++ b/srtcore/crypto.cpp @@ -28,7 +28,7 @@ written by #include "core.h" #include "api.h" -using namespace srt_logging; +using namespace srt::logging; namespace srt { @@ -45,10 +45,6 @@ SRT_STATIC_ASSERT(SRT_CMD_KMREQ_SZ <= SRT_CMD_MAXSZ, "error: SRT_CMD_MAXSZ too s // 10* HAICRYPT_DEF_KM_PRE_ANNOUNCE const int SRT_CRYPT_KM_PRE_ANNOUNCE SRT_ATR_UNUSED = 0x10000; -} - -namespace srt_logging -{ std::string KmStateStr(SRT_KM_STATE state) { switch (state) @@ -75,12 +71,6 @@ std::string KmStateStr(SRT_KM_STATE state) } } } -} // namespace - -using srt_logging::KmStateStr; - -namespace srt -{ void CCryptoControl::globalInit() { diff --git a/srtcore/crypto.h b/srtcore/crypto.h index c5eb9da32..195a2ac9b 100644 --- a/srtcore/crypto.h +++ b/srtcore/crypto.h @@ -23,25 +23,19 @@ written by #include "packet.h" #include "utilities.h" #include "logging.h" +#if ENABLE_LOGGING +#include "logger_fas.h" +#endif #include #include - - -namespace srt_logging -{ -std::string KmStateStr(SRT_KM_STATE state); -#if ENABLE_LOGGING -extern Logger cnlog; -#endif -} - namespace srt { class CUDT; struct CSrtConfig; +std::string KmStateStr(SRT_KM_STATE state); // For KMREQ/KMRSP. Only one field is used. const size_t SRT_KMR_KMSTATE = 0; @@ -171,7 +165,7 @@ class CCryptoControl void getKmMsg_markSent(size_t ki, bool runtime) { #if ENABLE_LOGGING - using srt_logging::cnlog; + using srt::logging::cnlog; #endif m_SndKmLastTime = sync::steady_clock::now(); diff --git a/srtcore/epoll.cpp b/srtcore/epoll.cpp index e385d845d..be292703d 100644 --- a/srtcore/epoll.cpp +++ b/srtcore/epoll.cpp @@ -65,17 +65,12 @@ modified by #include "common.h" #include "epoll.h" #include "logging.h" +#include "logger_fas.h" #include "utilities.h" using namespace std; using namespace srt::sync; - -namespace srt_logging -{ - extern Logger eilog, ealog; -} - -using namespace srt_logging; +using namespace srt::logging; #if ENABLE_HEAVY_LOGGING #define IF_DIRNAME(tested, flag, name) (tested & flag ? name : "") diff --git a/srtcore/fec.cpp b/srtcore/fec.cpp index 43fbbe0e2..64c48c163 100644 --- a/srtcore/fec.cpp +++ b/srtcore/fec.cpp @@ -33,7 +33,8 @@ #define SRT_FEC_MAX_RCV_HISTORY 10 using namespace std; -using namespace srt_logging; +using namespace srt::logging; +using namespace hvu; // ofmt namespace srt { diff --git a/srtcore/filelist.maf b/srtcore/filelist.maf index ce9e60711..596567bcc 100644 --- a/srtcore/filelist.maf +++ b/srtcore/filelist.maf @@ -1,4 +1,4 @@ - +# File list for SRT core SOURCES api.cpp @@ -14,9 +14,8 @@ epoll.cpp fec.cpp handshake.cpp list.cpp -logger_default.cpp -logger_defs.cpp -logging.cpp +logger_fas.cpp +../logging/logging.cpp md5.cpp packet.cpp packetfilter.cpp @@ -24,7 +23,7 @@ queue.cpp congctl.cpp socketconfig.cpp srt_c_api.cpp -srt_compat.c +../logging/hvu_compat.c strerror_defs.cpp sync.cpp tsbpd_time.cpp @@ -46,7 +45,7 @@ srt_shared.rc PUBLIC HEADERS srt.h -logging_api.h +../logging/logging_api.h access_control.h # version.h - NOTE: generated in the build and added to installation @@ -66,17 +65,20 @@ crypto.h epoll.h handshake.h list.h -logging.h +logger_fas.h +../logging/logging.h md5.h netinet_any.h +../logging/ofmt.h +../logging/ofmt_iostream.h packet.h sync.h queue.h congctl.h socketconfig.h -srt_compat.h +../logging/hvu_compat.h stats.h -threadname.h +../logging/hvu_threadname.h tsbpd_time.h utilities.h window.h diff --git a/srtcore/group.cpp b/srtcore/group.cpp index f949625d8..a8b7186ec 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -8,7 +8,7 @@ using namespace std; using namespace srt::sync; using namespace srt::groups; -using namespace srt_logging; +using namespace srt::logging; // The SRT_DEF_VERSION is defined in core.cpp. extern const int32_t SRT_DEF_VERSION; diff --git a/srtcore/group.h b/srtcore/group.h index dddb20dc2..8243ae546 100644 --- a/srtcore/group.h +++ b/srtcore/group.h @@ -159,7 +159,7 @@ class CUDTGroup /// @return true if the container still contains any sockets after the operation bool remove(SRTSOCKET id) { - using srt_logging::gmlog; + using srt::logging::gmlog; sync::ScopedLock g(m_GroupLock); bool empty = false; @@ -853,7 +853,7 @@ class CUDTGroup bool applyGroupTime(time_point& w_start_time, time_point& w_peer_start_time) { using sync::is_zero; - using srt_logging::gmlog; + using srt::logging::gmlog; if (is_zero(m_tsStartTime)) { diff --git a/srtcore/group_backup.cpp b/srtcore/group_backup.cpp index 9adb19607..bcb0d3ff0 100644 --- a/srtcore/group_backup.cpp +++ b/srtcore/group_backup.cpp @@ -26,7 +26,7 @@ namespace groups { using namespace std; -using namespace srt_logging; +using namespace srt::logging; const char* stateToStr(BackupMemberState state) { diff --git a/srtcore/handshake.cpp b/srtcore/handshake.cpp index 2cdfba950..b677e64fc 100644 --- a/srtcore/handshake.cpp +++ b/srtcore/handshake.cpp @@ -119,7 +119,7 @@ int CHandShake::load_from(const char* buf, size_t size) return 0; } -#ifdef ENABLE_LOGGING +#if ENABLE_LOGGING const char* srt_rejectreason_name [] = { "UNKNOWN", diff --git a/srtcore/list.cpp b/srtcore/list.cpp index 9346b8549..1d0ad7e12 100644 --- a/srtcore/list.cpp +++ b/srtcore/list.cpp @@ -55,19 +55,9 @@ modified by #include "list.h" #include "packet.h" #include "logging.h" +#include "logger_fas.h" -// Use "inline namespace" in C++11 -namespace srt_logging -{ -extern Logger qrlog; -extern Logger qslog; -extern Logger tslog; -} - -using srt_logging::qrlog; -using srt_logging::qslog; -using srt_logging::tslog; - +using namespace srt::logging; using namespace srt::sync; namespace srt diff --git a/srtcore/logger_default.cpp b/srtcore/logger_default.cpp deleted file mode 100644 index fa7e73b31..000000000 --- a/srtcore/logger_default.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - WARNING: Generated from ../scripts/generate-logging-defs.tcl - - DO NOT MODIFY. - - Copyright applies as per the generator script. - */ - - -#include "srt.h" -#include "logging.h" -#include "logger_defs.h" - -namespace srt_logging -{ - AllFaOn::AllFaOn() - { - allfa.set(SRT_LOGFA_GENERAL, true); - allfa.set(SRT_LOGFA_SOCKMGMT, true); - allfa.set(SRT_LOGFA_CONN, true); - allfa.set(SRT_LOGFA_XTIMER, true); - allfa.set(SRT_LOGFA_TSBPD, true); - allfa.set(SRT_LOGFA_RSRC, true); - - allfa.set(SRT_LOGFA_CONGEST, true); - allfa.set(SRT_LOGFA_PFILTER, true); - - allfa.set(SRT_LOGFA_API_CTRL, true); - - allfa.set(SRT_LOGFA_QUE_CTRL, true); - - allfa.set(SRT_LOGFA_EPOLL_UPD, true); - - allfa.set(SRT_LOGFA_API_RECV, true); - allfa.set(SRT_LOGFA_BUF_RECV, true); - allfa.set(SRT_LOGFA_QUE_RECV, true); - allfa.set(SRT_LOGFA_CHN_RECV, true); - allfa.set(SRT_LOGFA_GRP_RECV, true); - - allfa.set(SRT_LOGFA_API_SEND, true); - allfa.set(SRT_LOGFA_BUF_SEND, true); - allfa.set(SRT_LOGFA_QUE_SEND, true); - allfa.set(SRT_LOGFA_CHN_SEND, true); - allfa.set(SRT_LOGFA_GRP_SEND, true); - - allfa.set(SRT_LOGFA_INTERNAL, true); - - allfa.set(SRT_LOGFA_QUE_MGMT, true); - allfa.set(SRT_LOGFA_CHN_MGMT, true); - allfa.set(SRT_LOGFA_GRP_MGMT, true); - allfa.set(SRT_LOGFA_EPOLL_API, true); - } -} // namespace srt_logging diff --git a/srtcore/logger_defs.cpp b/srtcore/logger_defs.cpp deleted file mode 100644 index 041f6c8a7..000000000 --- a/srtcore/logger_defs.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - WARNING: Generated from ../scripts/generate-logging-defs.tcl - - DO NOT MODIFY. - - Copyright applies as per the generator script. - */ - - -#include "srt.h" -#include "logging.h" -#include "logger_defs.h" - -namespace srt_logging { AllFaOn logger_fa_all; } -// We need it outside the namespace to preserve the global name. -// It's a part of "hidden API" (used by applications) -SRT_API srt_logging::LogConfig srt_logger_config(srt_logging::logger_fa_all.allfa); - -namespace srt_logging -{ - Logger gglog(SRT_LOGFA_GENERAL, srt_logger_config, "SRT.gg"); - Logger smlog(SRT_LOGFA_SOCKMGMT, srt_logger_config, "SRT.sm"); - Logger cnlog(SRT_LOGFA_CONN, srt_logger_config, "SRT.cn"); - Logger xtlog(SRT_LOGFA_XTIMER, srt_logger_config, "SRT.xt"); - Logger tslog(SRT_LOGFA_TSBPD, srt_logger_config, "SRT.ts"); - Logger rslog(SRT_LOGFA_RSRC, srt_logger_config, "SRT.rs"); - - Logger cclog(SRT_LOGFA_CONGEST, srt_logger_config, "SRT.cc"); - Logger pflog(SRT_LOGFA_PFILTER, srt_logger_config, "SRT.pf"); - - Logger aclog(SRT_LOGFA_API_CTRL, srt_logger_config, "SRT.ac"); - - Logger qclog(SRT_LOGFA_QUE_CTRL, srt_logger_config, "SRT.qc"); - - Logger eilog(SRT_LOGFA_EPOLL_UPD, srt_logger_config, "SRT.ei"); - - Logger arlog(SRT_LOGFA_API_RECV, srt_logger_config, "SRT.ar"); - Logger brlog(SRT_LOGFA_BUF_RECV, srt_logger_config, "SRT.br"); - Logger qrlog(SRT_LOGFA_QUE_RECV, srt_logger_config, "SRT.qr"); - Logger krlog(SRT_LOGFA_CHN_RECV, srt_logger_config, "SRT.kr"); - Logger grlog(SRT_LOGFA_GRP_RECV, srt_logger_config, "SRT.gr"); - - Logger aslog(SRT_LOGFA_API_SEND, srt_logger_config, "SRT.as"); - Logger bslog(SRT_LOGFA_BUF_SEND, srt_logger_config, "SRT.bs"); - Logger qslog(SRT_LOGFA_QUE_SEND, srt_logger_config, "SRT.qs"); - Logger kslog(SRT_LOGFA_CHN_SEND, srt_logger_config, "SRT.ks"); - Logger gslog(SRT_LOGFA_GRP_SEND, srt_logger_config, "SRT.gs"); - - Logger inlog(SRT_LOGFA_INTERNAL, srt_logger_config, "SRT.in"); - - Logger qmlog(SRT_LOGFA_QUE_MGMT, srt_logger_config, "SRT.qm"); - Logger kmlog(SRT_LOGFA_CHN_MGMT, srt_logger_config, "SRT.km"); - Logger gmlog(SRT_LOGFA_GRP_MGMT, srt_logger_config, "SRT.gm"); - Logger ealog(SRT_LOGFA_EPOLL_API, srt_logger_config, "SRT.ea"); -} // namespace srt_logging diff --git a/srtcore/logger_defs.h b/srtcore/logger_defs.h deleted file mode 100644 index 63a4caf3e..000000000 --- a/srtcore/logger_defs.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - WARNING: Generated from ../scripts/generate-logging-defs.tcl - - DO NOT MODIFY. - - Copyright applies as per the generator script. - */ - - -#ifndef INC_SRT_LOGGER_DEFS_H -#define INC_SRT_LOGGER_DEFS_H - -#include "srt.h" -#include "logging.h" - -namespace srt_logging -{ - struct AllFaOn - { - LogConfig::fa_bitset_t allfa; - AllFaOn(); - }; - - extern Logger gglog; - extern Logger smlog; - extern Logger cnlog; - extern Logger xtlog; - extern Logger tslog; - extern Logger rslog; - - extern Logger cclog; - extern Logger pflog; - - extern Logger aclog; - - extern Logger qclog; - - extern Logger eilog; - - extern Logger arlog; - extern Logger brlog; - extern Logger qrlog; - extern Logger krlog; - extern Logger grlog; - - extern Logger aslog; - extern Logger bslog; - extern Logger qslog; - extern Logger kslog; - extern Logger gslog; - - extern Logger inlog; - - extern Logger qmlog; - extern Logger kmlog; - extern Logger gmlog; - extern Logger ealog; - -} // namespace srt_logging - -#endif diff --git a/srtcore/logger_fas.cpp b/srtcore/logger_fas.cpp new file mode 100644 index 000000000..4c64b2e66 --- /dev/null +++ b/srtcore/logger_fas.cpp @@ -0,0 +1,120 @@ +/* + WARNING: Generated from ../logging/generate-logging-defs.tcl + + DO NOT MODIFY. + + Copyright applies as per the generator script. + */ + + +#include "logging.h" +#include "logger_fas.h" + +namespace srt { namespace logging { + hvu::logging::LogConfigSingleton logger_config_si; + hvu::logging::LogConfig& logger_config() { return logger_config_si.instance();} + hvu::logging::Logger& gglog = logger_config().general; + + // Socket create/open/close/configure activities + hvu::logging::Logger smlog("sockmgmt", logger_config(), true, "SRT.sm"); + + + // Connection establishment and handshake + hvu::logging::Logger cnlog("conn", logger_config(), true, "SRT.cn"); + + + // The checkTimer and around activities + hvu::logging::Logger xtlog("xtimer", logger_config(), true, "SRT.xt"); + + + // The TsBPD thread + hvu::logging::Logger tslog("tsbpd", logger_config(), true, "SRT.ts"); + + + // System resource allocation and management + hvu::logging::Logger rslog("rsrc", logger_config(), true, "SRT.rs"); + + + // Congestion control module + hvu::logging::Logger cclog("congest", logger_config(), true, "SRT.cc"); + + + // Packet filter module + hvu::logging::Logger pflog("pfilter", logger_config(), true, "SRT.pf"); + + + // API part for socket and library managmenet + hvu::logging::Logger aclog("api_ctrl", logger_config(), true, "SRT.ac"); + + + // Queue control activities + hvu::logging::Logger qclog("que_ctrl", logger_config(), true, "SRT.qc"); + + + // EPoll, internal update activities + hvu::logging::Logger eilog("epoll_upd", logger_config(), true, "SRT.ei"); + + + // API part for receiving + hvu::logging::Logger arlog("api_recv", logger_config(), true, "SRT.ar"); + + + // Buffer, receiving side + hvu::logging::Logger brlog("buf_recv", logger_config(), true, "SRT.br"); + + + // Queue, receiving side + hvu::logging::Logger qrlog("que_recv", logger_config(), true, "SRT.qr"); + + + // CChannel, receiving side + hvu::logging::Logger krlog("chn_recv", logger_config(), true, "SRT.kr"); + + + // Group, receiving side + hvu::logging::Logger grlog("grp_recv", logger_config(), true, "SRT.gr"); + + + // API part for sending + hvu::logging::Logger aslog("api_send", logger_config(), true, "SRT.as"); + + + // Buffer, sending side + hvu::logging::Logger bslog("buf_send", logger_config(), true, "SRT.bs"); + + + // Queue, sending side + hvu::logging::Logger qslog("que_send", logger_config(), true, "SRT.qs"); + + + // CChannel, sending side + hvu::logging::Logger kslog("chn_send", logger_config(), true, "SRT.ks"); + + + // Group, sending side + hvu::logging::Logger gslog("grp_send", logger_config(), true, "SRT.gs"); + + + // Internal activities not connected directly to a socket + hvu::logging::Logger inlog("internal", logger_config(), true, "SRT.in"); + + + // Queue, management part + hvu::logging::Logger qmlog("que_mgmt", logger_config(), true, "SRT.qm"); + + + // CChannel, management part + hvu::logging::Logger kmlog("chn_mgmt", logger_config(), true, "SRT.km"); + + + // Group, management part + hvu::logging::Logger gmlog("grp_mgmt", logger_config(), true, "SRT.gm"); + + + // EPoll, API part + hvu::logging::Logger ealog("epoll_api", logger_config(), true, "SRT.ea"); + + + + +} } diff --git a/srtcore/logger_fas.h b/srtcore/logger_fas.h new file mode 100644 index 000000000..a293843a5 --- /dev/null +++ b/srtcore/logger_fas.h @@ -0,0 +1,98 @@ +/* + WARNING: Generated from ../logging/generate-logging-defs.tcl + + DO NOT MODIFY. + + Copyright applies as per the generator script. + */ + + +#ifndef SRT_LOGGING_LOGGER_FAS_H +#define SRT_LOGGING_LOGGER_FAS_H + +#include "logging.h" + +namespace srt { namespace logging { + extern hvu::logging::LogConfig& logger_config(); + extern hvu::logging::Logger& gglog; + + extern hvu::logging::Logger smlog; + + + extern hvu::logging::Logger cnlog; + + + extern hvu::logging::Logger xtlog; + + + extern hvu::logging::Logger tslog; + + + extern hvu::logging::Logger rslog; + + + extern hvu::logging::Logger cclog; + + + extern hvu::logging::Logger pflog; + + + extern hvu::logging::Logger aclog; + + + extern hvu::logging::Logger qclog; + + + extern hvu::logging::Logger eilog; + + + extern hvu::logging::Logger arlog; + + + extern hvu::logging::Logger brlog; + + + extern hvu::logging::Logger qrlog; + + + extern hvu::logging::Logger krlog; + + + extern hvu::logging::Logger grlog; + + + extern hvu::logging::Logger aslog; + + + extern hvu::logging::Logger bslog; + + + extern hvu::logging::Logger qslog; + + + extern hvu::logging::Logger kslog; + + + extern hvu::logging::Logger gslog; + + + extern hvu::logging::Logger inlog; + + + extern hvu::logging::Logger qmlog; + + + extern hvu::logging::Logger kmlog; + + + extern hvu::logging::Logger gmlog; + + + extern hvu::logging::Logger ealog; + + + + +} } + +#endif diff --git a/srtcore/logging.cpp b/srtcore/logging.cpp deleted file mode 100644 index db63fbb01..000000000 --- a/srtcore/logging.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - * SRT - Secure, Reliable, Transport - * Copyright (c) 2018 Haivision Systems Inc. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - */ - -/***************************************************************************** -written by - Haivision Systems Inc. - *****************************************************************************/ - - - -#include "logging.h" - -using namespace std; - - -namespace srt_logging -{ - -// Note: subscribe() and unsubscribe() functions are being called -// in the global constructor and destructor only, as the -// Logger objects (and inside them also their LogDispatcher) -// are being created. It's not predicted that LogDispatcher -// object are going to be created any other way than as -// global objects. Therefore the construction and destruction -// of them happens always in the main thread. - -void LogConfig::subscribe(LogDispatcher* lg) -{ - vector::iterator p = std::find(loggers.begin(), loggers.end(), lg); - if (p != loggers.end()) - return; // Do not register twice - - loggers.push_back(lg); -} - -void LogConfig::unsubscribe(LogDispatcher* lg) -{ - vector::iterator p = std::find(loggers.begin(), loggers.end(), lg); - if (p != loggers.end()) - { - loggers.erase(p); - } -} - -// This function doesn't have any protection on itself, -// however the API functions from which it is called, call -// it already under a mutex protection. -void LogConfig::updateLoggersState() -{ - for (vector::iterator p = loggers.begin(); - p != loggers.end(); ++p) - { - (*p)->Update(); - } -} - -void LogDispatcher::Update() -{ - bool enabled_in_fa = src_config->enabled_fa[fa]; - enabled = enabled_in_fa && level <= src_config->max_level; -} - - -// SendLogLine can be compiled normally. It's intermediately used by: -// - Proxy object, which is replaced by DummyProxy when !ENABLE_LOGGING -// - PrintLogLine, which has empty body when !ENABLE_LOGGING -void LogDispatcher::SendLogLine(const char* file, int line, const std::string& area, const std::string& msg) -{ - src_config->lock(); - if ( src_config->loghandler_fn ) - { - (*src_config->loghandler_fn)(src_config->loghandler_opaque, int(level), file, line, area.c_str(), msg.c_str()); - } - else if ( src_config->log_stream ) - { - src_config->log_stream->write(msg.data(), msg.size()); - src_config->log_stream->flush(); - } - src_config->unlock(); -} - - -#if ENABLE_LOGGING - -LogDispatcher::Proxy::Proxy(LogDispatcher& guy) : that(guy), that_enabled(that.CheckEnabled()) -{ - if (that_enabled) - { - i_file = ""; - i_line = 0; - flags = that.src_config->flags; - // Create logger prefix - that.CreateLogLinePrefix(os); - } -} - -LogDispatcher::Proxy LogDispatcher::operator()() -{ - return Proxy(*this); -} - -void LogDispatcher::CreateLogLinePrefix(srt::ofmtbufstream& serr) -{ - using namespace std; - using namespace srt; - - SRT_STATIC_ASSERT(ThreadName::BUFSIZE >= sizeof("hh:mm:ss.") * 2, // multiply 2 for some margin - "ThreadName::BUFSIZE is too small to be used for strftime"); - char tmp_buf[ThreadName::BUFSIZE]; - if (!isset(SRT_LOGF_DISABLE_TIME)) - { - // Not necessary if sending through the queue. - timeval tv; - gettimeofday(&tv, NULL); - struct tm tm = SysLocalTime((time_t) tv.tv_sec); - - if (strftime(tmp_buf, sizeof(tmp_buf), "%X.", &tm)) - { - serr << tmp_buf << fmt(tv.tv_usec, fmtc().fillzero().width(6)); - } - } - - // Note: ThreadName::get needs a buffer of size min. ThreadName::BUFSIZE - if (!isset(SRT_LOGF_DISABLE_THREADNAME) && ThreadName::get(tmp_buf)) - { - serr << OFMT_RAWSTR("/") << tmp_buf; - } - - if (!isset(SRT_LOGF_DISABLE_SEVERITY)) - { - serr.write(prefix, prefix_len); // include terminal 0 - } - - serr << OFMT_RAWSTR(": "); -} - -std::string LogDispatcher::Proxy::ExtractName(std::string pretty_function) -{ - if ( pretty_function == "" ) - return ""; - size_t pos = pretty_function.find('('); - if ( pos == std::string::npos ) - return pretty_function; // return unchanged. - - pretty_function = pretty_function.substr(0, pos); - - // There are also template instantiations where the instantiating - // parameters are encrypted inside. Therefore, search for the first - // open < and if found, search for symmetric >. - - int depth = 1; - pos = pretty_function.find('<'); - if ( pos != std::string::npos ) - { - size_t end = pos+1; - for(;;) - { - ++pos; - if ( pos == pretty_function.size() ) - { - --pos; - break; - } - if ( pretty_function[pos] == '<' ) - { - ++depth; - continue; - } - - if ( pretty_function[pos] == '>' ) - { - --depth; - if ( depth <= 0 ) - break; - continue; - } - } - - std::string afterpart = pretty_function.substr(pos+1); - pretty_function = pretty_function.substr(0, end) + ">" + afterpart; - } - - // Now see how many :: can be found in the name. - // If this occurs more than once, take the last two. - pos = pretty_function.rfind("::"); - - if ( pos == std::string::npos || pos < 2 ) - return pretty_function; // return whatever this is. No scope name. - - // Find the next occurrence of :: - if found, copy up to it. If not, - // return whatever is found. - pos -= 2; - pos = pretty_function.rfind("::", pos); - if ( pos == std::string::npos ) - return pretty_function; // nothing to cut - - return pretty_function.substr(pos+2); -} -#endif - -} // (end namespace srt_logging) - diff --git a/srtcore/logging.h b/srtcore/logging.h deleted file mode 100644 index ceb71a496..000000000 --- a/srtcore/logging.h +++ /dev/null @@ -1,510 +0,0 @@ -/* - * SRT - Secure, Reliable, Transport - * Copyright (c) 2018 Haivision Systems Inc. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - */ - -/***************************************************************************** -written by - Haivision Systems Inc. - *****************************************************************************/ - -#ifndef INC_SRT_LOGGING_H -#define INC_SRT_LOGGING_H - - -#include -#include -#include -#include -#include -#ifdef _WIN32 -#include "win/wintime.h" -#include -#else -#include -#endif - -#include "ofmt.h" -#include "srt.h" -#include "utilities.h" -#include "threadname.h" -#include "logging_api.h" -#include "srt_compat.h" -#include "sync.h" - -#ifdef __GNUC__ -#define PRINTF_LIKE __attribute__((format(printf,2,3))) -#else -#define PRINTF_LIKE -#endif - -#if ENABLE_LOGGING - -// GENERAL NOTE: All logger functions ADD THEIR OWN \n (EOL). Don't add any your own EOL character. -// The logging system may not add the EOL character, if appropriate flag was set in log settings. -// Anyway, treat the whole contents of eventually formatted message as exactly one line. - -// LOGC uses an iostream-like syntax, using the special 'log' symbol. -// This symbol isn't visible outside the log macro parameters. -// Usage: LOGC(gglog.Debug, log << param1 << param2 << param3); -#define LOGC(logdes, args) if (logdes.CheckEnabled()) \ -{ \ - srt_logging::LogDispatcher::Proxy log(logdes); \ - log.setloc(__FILE__, __LINE__, __FUNCTION__); \ - { (void)(const srt_logging::LogDispatcher::Proxy&)(args); } \ -} - -// LOGF uses printf-like style formatting. -// Usage: LOGF(gglog.Debug, "%s: %d", param1.c_str(), int(param2)); -// NOTE: LOGF is deprecated and should not be used -#define LOGF(logdes, ...) if (logdes.CheckEnabled()) logdes().setloc(__FILE__, __LINE__, __FUNCTION__).form(__VA_ARGS__) - -// LOGP is C++11 only OR with only one string argument. -// Usage: LOGP(gglog.Debug, param1, param2, param3); -#define LOGP(logdes, ...) if (logdes.CheckEnabled()) logdes.printloc(__FILE__, __LINE__, __FUNCTION__,##__VA_ARGS__) - -#define IF_LOGGING(instr,...) instr,##__VA_ARGS__ - -#if ENABLE_HEAVY_LOGGING - -#define HLOGC LOGC -#define HLOGP LOGP -#define HLOGF LOGF - -#define IF_HEAVY_LOGGING(instr,...) instr,##__VA_ARGS__ - -#else - -#define HLOGC(...) -#define HLOGF(...) -#define HLOGP(...) - -#define IF_HEAVY_LOGGING(instr,...) (void)0 - -#endif - -#else - -#define LOGC(...) -#define LOGF(...) -#define LOGP(...) - -#define HLOGC(...) -#define HLOGF(...) -#define HLOGP(...) - -#define IF_HEAVY_LOGGING(instr,...) (void)0 -#define IF_LOGGING(instr,...) (void)0 - -#endif - -namespace srt_logging -{ - -struct LogConfig -{ - typedef std::bitset fa_bitset_t; - fa_bitset_t enabled_fa; // NOTE: assumed atomic reading - LogLevel::type max_level; // NOTE: assumed atomic reading - std::ostream* log_stream; - SRT_LOG_HANDLER_FN* loghandler_fn; - void* loghandler_opaque; - mutable srt::sync::Mutex mutex; - int flags; - std::vector loggers; - - LogConfig(const fa_bitset_t& efa, - LogLevel::type l = LogLevel::warning, - std::ostream* ls = &std::cerr) - : enabled_fa(efa) - , max_level(l) - , log_stream(ls) - , loghandler_fn() - , loghandler_opaque() - , flags() - { - } - - ~LogConfig() - { - } - - void lock() const SRT_TSA_WILL_LOCK(mutex) { mutex.lock(); } - void unlock() const SRT_TSA_WILL_UNLOCK(mutex) { mutex.unlock(); } - - void subscribe(LogDispatcher*); - void unsubscribe(LogDispatcher*); - void updateLoggersState(); -}; - -// The LogDispatcher class represents the object that is responsible for -// a decision whether to log something or not, and if so, print the log. -struct SRT_API LogDispatcher -{ -private: - int fa; - LogLevel::type level; - static const size_t MAX_PREFIX_SIZE = 32; - char prefix[MAX_PREFIX_SIZE+1]; - size_t prefix_len; - srt::sync::atomic enabled; - LogConfig* src_config; - - bool isset(int flg) { return (src_config->flags & flg) != 0; } - -public: - - LogDispatcher(int functional_area, LogLevel::type log_level, const char* your_pfx, - const char* logger_pfx /*[[nullable]]*/, LogConfig& config): - fa(functional_area), - level(log_level), - enabled(false), - src_config(&config) - { - const size_t your_pfx_len = your_pfx ? strlen(your_pfx) : 0; - const size_t logger_pfx_len = logger_pfx ? strlen(logger_pfx) : 0; - - if (logger_pfx && your_pfx_len + logger_pfx_len + 1 < MAX_PREFIX_SIZE) - { - memcpy(prefix, your_pfx, your_pfx_len); - prefix[your_pfx_len] = ':'; - memcpy(prefix + your_pfx_len + 1, logger_pfx, logger_pfx_len); - prefix[your_pfx_len + logger_pfx_len + 1] = '\0'; - prefix_len = your_pfx_len + logger_pfx_len + 1; - } - else if (your_pfx) - { - // Prefix too long, so copy only your_pfx and only - // as much as it fits - size_t copylen = std::min(+MAX_PREFIX_SIZE, your_pfx_len); - memcpy(prefix, your_pfx, copylen); - prefix[copylen] = '\0'; - prefix_len = copylen; - } - else - { - prefix[0] = '\0'; - prefix_len = 0; - } - config.subscribe(this); - Update(); - } - - ~LogDispatcher() - { - src_config->unsubscribe(this); - } - - void Update(); - - bool CheckEnabled() { return enabled; } - - void CreateLogLinePrefix(srt::ofmtbufstream&); - void SendLogLine(const char* file, int line, const std::string& area, const std::string& sl); - - // log.Debug("This is the ", nth, " time"); <--- C++11 only. - // log.Debug() << "This is the " << nth << " time"; <--- C++03 available. - -#if HAVE_CXX11 - - template - void PrintLogLine(const char* file, int line, const std::string& area, Args&&... args); - - template - void operator()(Args&&... args) - { - PrintLogLine("UNKNOWN.c++", 0, "UNKNOWN", args...); - } - - template - void printloc(const char* file, int line, const std::string& area, Args&&... args) - { - PrintLogLine(file, line, area, args...); - } -#else - template - void PrintLogLine(const char* file, int line, const std::string& area, const Arg& arg); - - // For C++03 (older) standard provide only with one argument. - template - void operator()(const Arg& arg) - { - PrintLogLine("UNKNOWN.c++", 0, "UNKNOWN", arg); - } - - void printloc(const char* file, int line, const std::string& area, const std::string& arg1) - { - PrintLogLine(file, line, area, arg1); - } -#endif - -#if ENABLE_LOGGING - - struct Proxy; - friend struct Proxy; - - Proxy operator()(); -#else - - // Dummy proxy that does nothing - struct DummyProxy - { - DummyProxy(LogDispatcher&) - { - } - - template - DummyProxy& operator<<(const T& ) // predicted for temporary objects - { - return *this; - } - - // DEPRECATED: DO NOT use LOGF/HLOGF macros anymore. - // Use iostream-style formatting with LOGC or a direct argument with LOGP. - SRT_ATR_DEPRECATED_PX DummyProxy& form(const char*, ...) SRT_ATR_DEPRECATED - { - return *this; - } - - DummyProxy& vform(const char*, va_list) - { - return *this; - } - - DummyProxy& setloc(const char* , int , std::string) - { - return *this; - } - }; - - DummyProxy operator()() - { - return DummyProxy(*this); - } - -#endif - -}; - -#if ENABLE_LOGGING - -struct LogDispatcher::Proxy -{ - LogDispatcher& that; - - srt::ofmtbufstream os; - - // Cache the 'enabled' state in the beginning. If the logging - // becomes enabled or disabled in the middle of the log, we don't - // want it to be partially printed anyway. - bool that_enabled; - int flags; - - // CACHE!!! - const char* i_file; - int i_line; - std::string area; - - Proxy& setloc(const char* f, int l, std::string a) - { - i_file = f; - i_line = l; - area = a; - return *this; - } - - // Left for future. Not sure if it's more convenient - // to use this to translate __PRETTY_FUNCTION__ to - // something short, or just let's leave __FUNCTION__ - // or better __func__. - std::string ExtractName(std::string pretty_function); - - Proxy(LogDispatcher& guy); - - // Copy constructor is needed due to noncopyable ostringstream. - // This is used only in creation of the default object, so just - // use the default values, just copy the location cache. - Proxy(const Proxy& p): that(p.that), area(p.area) - { - i_file = p.i_file; - i_line = p.i_line; - that_enabled = false; - flags = p.flags; - } - - - template - Proxy& operator<<(const T& arg) // predicted for temporary objects - { - if ( that_enabled ) - { - os << arg; - } - return *this; - } - - // Special case for atomics, as passing them to the fmt facility - // requires unpacking the real underlying value. - template - Proxy& operator<<(const srt::sync::atomic& arg) - { - if (that_enabled) - { - os << arg.load(); - } - return *this; - } - -#if HAVE_CXX11 - - void dispatch() {} - - template - void dispatch(const Arg1& a1, const Args&... others) - { - *this << a1; - dispatch(others...); - } - - // Special dispatching for atomics must be provided here. - // By some reason, "*this << a1" expression gets dispatched - // to the general version of operator<<, not the overload for - // atomic. Even though the compiler shows Arg1 type as atomic. - template - void dispatch(const srt::sync::atomic& a1, const Args&... others) - { - *this << a1.load(); - dispatch(others...); - } - -#endif - - ~Proxy() - { - if (that_enabled) - { - if ((flags & SRT_LOGF_DISABLE_EOL) == 0) - os << OFMT_RAWSTR("\n"); // XXX would be nice to use a symbol for it - - that.SendLogLine(i_file, i_line, area, os.str()); - } - // Needed in destructor? - //os.clear(); - //os.str(""); - } - - Proxy& form(const char* fmts, ...) PRINTF_LIKE - { - if ( !that_enabled ) - return *this; - - if ( !fmts || fmts[0] == '\0' ) - return *this; - - va_list ap; - va_start(ap, fmts); - vform(fmts, ap); - va_end(ap); - return *this; - } - - Proxy& vform(const char* fmts, va_list ap) - { - char buf[512]; - -#if defined(_MSC_VER) && _MSC_VER < 1900 - _vsnprintf(buf, sizeof(buf) - 1, fmts, ap); -#else - vsnprintf(buf, sizeof(buf), fmts, ap); -#endif - size_t len = strlen(buf); - if ( buf[len-1] == '\n' ) - { - // Remove EOL character, should it happen to be at the end. - // The EOL will be added at the end anyway. - buf[len-1] = '\0'; - } - - os.write(buf, len); - return *this; - } -}; - - -#endif - -class Logger -{ - int m_fa; - LogConfig& m_config; - -public: - - LogDispatcher Debug; - LogDispatcher Note; - LogDispatcher Warn; - LogDispatcher Error; - LogDispatcher Fatal; - - Logger(int functional_area, LogConfig& config, const char* logger_pfx = NULL): - m_fa(functional_area), - m_config(config), - Debug ( m_fa, LogLevel::debug, " D", logger_pfx, m_config ), - Note ( m_fa, LogLevel::note, ".N", logger_pfx, m_config ), - Warn ( m_fa, LogLevel::warning, "!W", logger_pfx, m_config ), - Error ( m_fa, LogLevel::error, "*E", logger_pfx, m_config ), - Fatal ( m_fa, LogLevel::fatal, "!!FATAL!!", logger_pfx, m_config ) - { - } -}; - - -#if HAVE_CXX11 - -//extern std::mutex Debug_mutex; - -inline void PrintArgs(std::ostringstream&) {} - -template -inline void PrintArgs(std::ostringstream& serr, Arg1&& arg1, Args&&... args) -{ - serr << std::forward(arg1); - PrintArgs(serr, args...); -} - -// Add exceptional handling for sync::atomic -template -inline void PrintArgs(std::ostringstream& serr, const srt::sync::atomic& arg1, Args&&... args) -{ - serr << arg1.load(); - PrintArgs(serr, args...); -} - -template -inline void LogDispatcher::PrintLogLine(const char* file SRT_ATR_UNUSED, int line SRT_ATR_UNUSED, const std::string& area SRT_ATR_UNUSED, Args&&... args SRT_ATR_UNUSED) -{ -#ifdef ENABLE_LOGGING - Proxy(*this).dispatch(args...); -#endif -} - -#else // !HAVE_CXX11 - -template -inline void LogDispatcher::PrintLogLine(const char* file SRT_ATR_UNUSED, int line SRT_ATR_UNUSED, const std::string& area SRT_ATR_UNUSED, const Arg& arg SRT_ATR_UNUSED) -{ -#ifdef ENABLE_LOGGING - Proxy(*this) << arg; -#endif -} - -#endif // HAVE_CXX11 - -} - -#endif // INC_SRT_LOGGING_H diff --git a/srtcore/packet.cpp b/srtcore/packet.cpp index 4d3cc4b33..3cc6f4d0c 100644 --- a/srtcore/packet.cpp +++ b/srtcore/packet.cpp @@ -164,13 +164,10 @@ modified by #include "packet.h" #include "handshake.h" #include "logging.h" +#include "logger_fas.h" #include "handshake.h" -namespace srt_logging -{ -extern Logger inlog; -} -using namespace srt_logging; +using namespace srt::logging; namespace srt { diff --git a/srtcore/packetfilter.cpp b/srtcore/packetfilter.cpp index e8b2a6102..10b413fc7 100644 --- a/srtcore/packetfilter.cpp +++ b/srtcore/packetfilter.cpp @@ -23,7 +23,7 @@ #include "logging.h" using namespace std; -using namespace srt_logging; +using namespace srt::logging; using namespace srt::sync; namespace srt { diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index 6e2abdcd4..590035c64 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -58,13 +58,14 @@ modified by #include "common.h" #include "api.h" #include "netinet_any.h" -#include "threadname.h" +#include "hvu_threadname.h" #include "sync.h" #include "logging.h" using namespace std; using namespace srt::sync; -using namespace srt_logging; +using namespace srt::logging; +using namespace hvu; // ThreadName namespace srt { diff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp index 2d4062f09..43c669a5b 100644 --- a/srtcore/socketconfig.cpp +++ b/srtcore/socketconfig.cpp @@ -51,6 +51,9 @@ written by #include "srt.h" #include "socketconfig.h" +#include "ofmt.h" + +using namespace hvu; // fmt namespace srt { @@ -93,7 +96,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - using namespace srt_logging; + using namespace srt::logging; const int ival = cast_optval(optval, optlen); const int handshake_size = CHandShake::m_iContentSize + (sizeof(uint32_t) * SRT_HS_E_SIZE); const int minval = int(CPacket::udpHeaderSize(AF_INET6) + CPacket::HDR_SIZE + handshake_size); @@ -118,7 +121,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - using namespace srt_logging; + using namespace srt::logging; const int fc = cast_optval(optval, optlen); if (fc < co.DEF_MIN_FLIGHT_PKT) { @@ -306,7 +309,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - using namespace srt_logging; + using namespace srt::logging; #ifdef SRT_ENABLE_BINDTODEVICE using namespace std; @@ -380,7 +383,7 @@ struct CSrtConfigSetter #ifdef SRT_ENABLE_ENCRYPTION if (val == false && co.iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM) { - using namespace srt_logging; + using namespace srt::logging; LOGC(aclog.Error, log << "Can't disable TSBPD as long as AES GCM is enabled."); throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); } @@ -451,7 +454,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - using namespace srt_logging; + using namespace srt::logging; #ifdef SRT_ENABLE_ENCRYPTION // Password must be 10-80 characters. // Or it can be empty to clear the password. @@ -478,7 +481,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - using namespace srt_logging; + using namespace srt::logging; #ifdef SRT_ENABLE_ENCRYPTION const int v = cast_optval(optval, optlen); int const allowed[4] = { @@ -632,7 +635,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - using namespace srt_logging; + using namespace srt::logging; const int val = cast_optval(optval, optlen); if (val < 0) { @@ -734,7 +737,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - using namespace srt_logging; + using namespace srt::logging; const int val = cast_optval(optval, optlen); if (val < 0) @@ -768,7 +771,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - using namespace srt_logging; + using namespace srt::logging; const int val = cast_optval(optval, optlen); if (val < 0) @@ -829,7 +832,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - using namespace srt_logging; + using namespace srt::logging; std::string arg((const char*)optval, optlen); // Parse the configuration string prematurely SrtFilterConfig fc; @@ -868,7 +871,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - using namespace srt_logging; + using namespace srt::logging; // This option is meaningless for the socket itself. // It's set here just for the sake of setting it on a listener // socket so that it is then applied on the group when a @@ -918,7 +921,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - using namespace srt_logging; + using namespace srt::logging; const int val = cast_optval(optval, optlen); if (val < CSrtConfig::CIPHER_MODE_AUTO || val > CSrtConfig::CIPHER_MODE_AES_GCM) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); @@ -945,7 +948,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& , const void* , int ) { - using namespace srt_logging; + using namespace srt::logging; #ifdef SRT_ENABLE_ENCRYPTION LOGC(aclog.Error, log << "SRT was built without AEAD enabled."); #else diff --git a/srtcore/socketconfig.h b/srtcore/socketconfig.h index 656ec87b7..d59459210 100644 --- a/srtcore/socketconfig.h +++ b/srtcore/socketconfig.h @@ -61,7 +61,7 @@ written by #include "congctl.h" #include "packet.h" #include "handshake.h" -#include "logger_defs.h" +#include "logger_fas.h" #include "packetfilter.h" // SRT Version constants diff --git a/srtcore/srt.h b/srtcore/srt.h index 48f1d248c..2c73754c2 100644 --- a/srtcore/srt.h +++ b/srtcore/srt.h @@ -600,7 +600,6 @@ enum SRT_REJECT_REASON #define SRT_REJC_PREDEFINED 1000 // Standard server error codes #define SRT_REJC_USERDEFINED 2000 // User defined error codes - enum SRT_CLOSE_REASON { SRT_CLS_UNKNOWN, // Unset @@ -632,69 +631,6 @@ typedef struct SRT_CLOSE_INFO #define SRT_CLSC_USER 100 -// Logging API - specialization for SRT. - -// WARNING: This part is generated. - -// Logger Functional Areas -// Note that 0 is "general". - -// Values 0* - general, unqualified -// Values 1* - control -// Values 2* - receiving -// Values 3* - sending -// Values 4* - management - -// Made by #define so that it's available also for C API. - -// Use ../scripts/generate-logging-defs.tcl to regenerate. - -// SRT_LOGFA BEGIN GENERATED SECTION { - -#define SRT_LOGFA_GENERAL 0 // gglog: General uncategorized log, for serious issues only -#define SRT_LOGFA_SOCKMGMT 1 // smlog: Socket create/open/close/configure activities -#define SRT_LOGFA_CONN 2 // cnlog: Connection establishment and handshake -#define SRT_LOGFA_XTIMER 3 // xtlog: The checkTimer and around activities -#define SRT_LOGFA_TSBPD 4 // tslog: The TsBPD thread -#define SRT_LOGFA_RSRC 5 // rslog: System resource allocation and management - -#define SRT_LOGFA_CONGEST 7 // cclog: Congestion control module -#define SRT_LOGFA_PFILTER 8 // pflog: Packet filter module - -#define SRT_LOGFA_API_CTRL 11 // aclog: API part for socket and library managmenet - -#define SRT_LOGFA_QUE_CTRL 13 // qclog: Queue control activities - -#define SRT_LOGFA_EPOLL_UPD 16 // eilog: EPoll, internal update activities - -#define SRT_LOGFA_API_RECV 21 // arlog: API part for receiving -#define SRT_LOGFA_BUF_RECV 22 // brlog: Buffer, receiving side -#define SRT_LOGFA_QUE_RECV 23 // qrlog: Queue, receiving side -#define SRT_LOGFA_CHN_RECV 24 // krlog: CChannel, receiving side -#define SRT_LOGFA_GRP_RECV 25 // grlog: Group, receiving side - -#define SRT_LOGFA_API_SEND 31 // aslog: API part for sending -#define SRT_LOGFA_BUF_SEND 32 // bslog: Buffer, sending side -#define SRT_LOGFA_QUE_SEND 33 // qslog: Queue, sending side -#define SRT_LOGFA_CHN_SEND 34 // kslog: CChannel, sending side -#define SRT_LOGFA_GRP_SEND 35 // gslog: Group, sending side - -#define SRT_LOGFA_INTERNAL 41 // inlog: Internal activities not connected directly to a socket - -#define SRT_LOGFA_QUE_MGMT 43 // qmlog: Queue, management part -#define SRT_LOGFA_CHN_MGMT 44 // kmlog: CChannel, management part -#define SRT_LOGFA_GRP_MGMT 45 // gmlog: Group, management part -#define SRT_LOGFA_EPOLL_API 46 // ealog: EPoll, API part - -#define SRT_LOGFA_HAICRYPT 6 // hclog: Haicrypt module area -#define SRT_LOGFA_APPLOG 10 // aplog: Applications - -// } SRT_LOGFA END GENERATED SECTION - -// To make a typical int64_t size, although still use std::bitset. -// C API will carry it over. -#define SRT_LOGFA_LASTNONE 63 - enum SRT_KM_STATE { SRT_KM_S_UNSECURED = 0, // No encryption @@ -988,7 +924,7 @@ SRT_API void srt_resetlogfa(const int* fara, size_t fara_size); // This isn't predicted, will be only available in SRT C++ API. // For the time being, until this API is ready, use UDT::setlogstream. // SRT_API void srt_setlogstream(std::ostream& stream); -SRT_API void srt_setloghandler(void* opaque, SRT_LOG_HANDLER_FN* handler); +SRT_API void srt_setloghandler(void* opaque, HVU_LOG_HANDLER_FN* handler); SRT_API void srt_setlogflags(int flags); @@ -1083,22 +1019,18 @@ SRT_API SRTSOCKET srt_connect_group(SRTSOCKET group, SRT_SOCKGROUPCONFIG name[], namespace srt { -SRT_API void setloglevel(srt_logging::LogLevel::type ll); -SRT_API void addlogfa(srt_logging::LogFA fa); -SRT_API void dellogfa(srt_logging::LogFA fa); -SRT_API void resetlogfa(std::set fas); +SRT_API void setloglevel(hvu::logging::LogLevel::type ll); +SRT_API void addlogfa(int fa); +SRT_API void dellogfa(int fa); +SRT_API void resetlogfa(std::set fas); SRT_API void resetlogfa(const int* fara, size_t fara_size); SRT_API void setlogstream(std::ostream& stream); -SRT_API void setloghandler(void* opaque, SRT_LOG_HANDLER_FN* handler); +SRT_API void setloghandler(void* opaque, HVU_LOG_HANDLER_FN* handler); SRT_API void setlogflags(int flags); SRT_API bool setstreamid(SRTSOCKET u, const std::string& sid); SRT_API std::string getstreamid(SRTSOCKET u); -// Namespace alias -namespace logging { - using namespace srt_logging; -} } // namespace srt diff --git a/srtcore/srt_c_api.cpp b/srtcore/srt_c_api.cpp index 33f152100..97960b25c 100644 --- a/srtcore/srt_c_api.cpp +++ b/srtcore/srt_c_api.cpp @@ -29,7 +29,7 @@ written by using namespace std; using namespace srt; - +using namespace srt::logging; extern "C" { @@ -389,32 +389,35 @@ SRTSTATUS srt_epoll_release(int eid) { return CUDT::epoll_release(eid); } void srt_setloglevel(int ll) { - srt::setloglevel(srt_logging::LogLevel::type(ll)); + logger_config().set_maxlevel(hvu::logging::LogLevel::type(ll)); } void srt_addlogfa(int fa) { - srt::addlogfa(srt_logging::LogFA(fa)); + int farray[1] = { fa }; + logger_config().enable_fa(farray, 1, true); } void srt_dellogfa(int fa) { - srt::dellogfa(srt_logging::LogFA(fa)); + int farray[1] = { fa }; + logger_config().enable_fa(farray, 1, false); } void srt_resetlogfa(const int* fara, size_t fara_size) { - srt::resetlogfa(fara, fara_size); + logger_config().enable_fa(0, 0, false); + logger_config().enable_fa(fara, fara_size, true); } -void srt_setloghandler(void* opaque, SRT_LOG_HANDLER_FN* handler) +void srt_setloghandler(void* opaque, HVU_LOG_HANDLER_FN* handler) { - srt::setloghandler(opaque, handler); + logger_config().set_handler(opaque, handler); } void srt_setlogflags(int flags) { - srt::setlogflags(flags); + logger_config().set_flags(flags); } int srt_getsndbuffer(SRTSOCKET sock, size_t* blocks, size_t* bytes) @@ -489,7 +492,6 @@ const char* const srt_rejection_reason_msg [] = { const char* srt_rejectreason_str(int id) { - using namespace srt_logging; if (id == SRT_REJX_FALLBACK) { return "Application fallback (default) rejection reason"; diff --git a/srtcore/srt_sync_cxx98.h b/srtcore/srt_sync_cxx98.h new file mode 100644 index 000000000..b9ed40159 --- /dev/null +++ b/srtcore/srt_sync_cxx98.h @@ -0,0 +1,31 @@ +/* + * SRT - Secure, Reliable, Transport + * Copyright (c) 2018 Haivision Systems Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +/***************************************************************************** +written by + Haivision Systems Inc. + *****************************************************************************/ + +// This file should provide the standard way of sync facilities (mutex, scoped lock, atomic, threads) +// This requires, however, at least C++11. For C++98 and C++03 you need to provide some external +// facility. + +#ifndef INC_HVU_SYNC_H +#define INC_HVU_SYNC_H + +#include "sync.h" +#include "atomic.h" +#define HVU_EXT_MUTEX srt::sync::Mutex +#define HVU_EXT_LOCKGUARD srt::sync::ScopedLock +#define HVU_EXT_ATOMIC srt::sync::atomic +#define HVU_EXT_THIS_THREAD srt::sync::this_thread + +#endif + diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index 2fe47a043..254741081 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -14,8 +14,10 @@ #include #include "sync.h" #include "srt.h" -#include "srt_compat.h" +#include "hvu_compat.h" +#include "hvu_threadname.h" #include "logging.h" +#include "logger_fas.h" #include "common.h" // HAVE_CXX11 is defined in utilities.h, included with common.h. @@ -24,11 +26,7 @@ #include #endif -namespace srt_logging -{ - extern Logger inlog; -} -using namespace srt_logging; +using namespace srt::logging; using namespace std; namespace srt @@ -38,6 +36,7 @@ namespace sync std::string FormatTime(const steady_clock::time_point& timestamp) { + using namespace hvu; if (is_zero(timestamp)) { // Use special string for 0 @@ -55,9 +54,8 @@ std::string FormatTime(const steady_clock::time_point& timestamp) if (days) out << days << OFMT_RAWSTR("D "); - fmtc d02, dec0; - d02.dec().fillzero().width(2); - dec0.dec().fillzero().width(decimals); + fmtc d02 = fmtc().dec().fillzero().width(2), + dec0 = fmtc().dec().fillzero().width(decimals); out << fmt(hours, d02) << OFMT_RAWSTR(":") << fmt(minutes, d02) << OFMT_RAWSTR(":") @@ -69,6 +67,8 @@ std::string FormatTime(const steady_clock::time_point& timestamp) std::string FormatTimeSys(const steady_clock::time_point& timestamp) { + using namespace hvu; + const time_t now_s = ::time(NULL); // get current time in seconds const steady_clock::time_point now_timestamp = steady_clock::now(); const int64_t delta_us = count_microseconds(timestamp - now_timestamp); @@ -109,7 +109,7 @@ bool StartThread(CThread& th, ThreadFunc&& f, void* args, const string& name) bool StartThread(CThread& th, void* (*f) (void*), void* args, const string& name) #endif { - ThreadName tn(name); + hvu::ThreadName tn(name); try { #if HAVE_FULL_CXX11 || defined(ENABLE_STDCXX_SYNC) diff --git a/srtcore/sync.h b/srtcore/sync.h index e9a8341af..beecac366 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -1112,6 +1112,7 @@ struct DurationUnitName template inline std::string FormatDuration(const steady_clock::duration& dur) { + using namespace hvu; return fmtcat(fmt(DurationUnitName::count(dur), std::fixed), DurationUnitName::name()); } diff --git a/srtcore/sync_cxx11.cpp b/srtcore/sync_cxx11.cpp index 6d3ca934f..b31745c4f 100644 --- a/srtcore/sync_cxx11.cpp +++ b/srtcore/sync_cxx11.cpp @@ -13,7 +13,6 @@ #include #include #include "sync.h" -#include "srt_compat.h" #include "common.h" //////////////////////////////////////////////////////////////////////////////// diff --git a/srtcore/sync_posix.cpp b/srtcore/sync_posix.cpp index 0dd1f4928..63ffcb3e5 100644 --- a/srtcore/sync_posix.cpp +++ b/srtcore/sync_posix.cpp @@ -15,8 +15,9 @@ #include "sync.h" #include "utilities.h" #include "srt.h" -#include "srt_compat.h" +#include "hvu_compat.h" #include "logging.h" +#include "logger_fas.h" #include "common.h" #if defined(_WIN32) @@ -26,11 +27,7 @@ #include #endif -namespace srt_logging -{ - extern Logger inlog; -} -using namespace srt_logging; +using namespace srt::logging; namespace srt { diff --git a/srtcore/tsbpd_time.cpp b/srtcore/tsbpd_time.cpp index bda8f5210..ea057e479 100644 --- a/srtcore/tsbpd_time.cpp +++ b/srtcore/tsbpd_time.cpp @@ -10,10 +10,10 @@ #include "tsbpd_time.h" #include "logging.h" -#include "logger_defs.h" +#include "logger_fas.h" #include "packet.h" -using namespace srt_logging; +using namespace srt::logging; using namespace srt::sync; namespace srt diff --git a/srtcore/utilities.h b/srtcore/utilities.h index 60ffe60b9..e8118ee74 100644 --- a/srtcore/utilities.h +++ b/srtcore/utilities.h @@ -297,7 +297,7 @@ class FixedArray void throw_invalid_index(int i) const { - throw std::runtime_error(fmtcat(OFMT_RAWSTR("Index "), i, OFMT_RAWSTR(" out of range"))); + throw std::runtime_error(hvu::fmtcat(OFMT_RAWSTR("Index "), i, OFMT_RAWSTR(" out of range"))); } private: @@ -960,7 +960,7 @@ inline std::string BufferStamp(const char* mem, size_t size) } // Convert to hex string - return srt::fmts(sum, srt::fmtc().fillzero().width(8).uhex()); + return hvu::fmts(sum, hvu::fmtc().fillzero().width(8).uhex()); } template diff --git a/test/test_bonding.cpp b/test/test_bonding.cpp index 460a8d5eb..ce1d8fa1d 100644 --- a/test/test_bonding.cpp +++ b/test/test_bonding.cpp @@ -13,8 +13,12 @@ #include "common.h" #include "netinet_any.h" #include "socketconfig.h" +#include "logger_fas.h" +#include "hvu_threadname.h" +using namespace srt::logging; + TEST(Bonding, SRTConnectGroup) { srt::TestInit srtinit; @@ -233,7 +237,7 @@ TEST(Bonding, NonBlockingGroupConnect) { SRT_SOCKSTATUS st = srt_getsockstate(write[i]); std::cout << "Epoll write[" << i << "]: " << write[i] - << " ST:" << srt_logging::SockStatusStr(st) + << " ST:" << srt::SockStatusStr(st) << " (removing from epoll)\n"; EXPECT_EQ(srt_epoll_remove_usock(poll_id, write[i]), 0); } @@ -691,7 +695,7 @@ TEST(Bonding, DeadLinkUpdate) char srcbuf [] = "1234ABCD"; thread td = thread([&]() { - srt::ThreadName::set("TEST-conn"); + hvu::ThreadName::set("TEST-conn"); cout << "[T] Connecting 1...\n"; const SRTSOCKET member1 = srt_connect(group, sa.get(), sa.size()); @@ -791,7 +795,7 @@ TEST(Bonding, DeadLinkUpdate) if (nrecv == -1) { cout << "ERROR: " << srt_strerror(err, syserr) << endl; - cout << "STATUS: " << srt_logging::SockStatusStr(srt_getsockstate(acp)) << endl; + cout << "STATUS: " << srt::SockStatusStr(srt_getsockstate(acp)) << endl; } else { @@ -808,7 +812,7 @@ TEST(Bonding, DeadLinkUpdate) if (nrecv2 == -1) { cout << "ERROR: " << srt_strerror(err, syserr) << endl; - cout << "STATUS: " << srt_logging::SockStatusStr(srt_getsockstate(acp)) << endl; + cout << "STATUS: " << srt::SockStatusStr(srt_getsockstate(acp)) << endl; } else { @@ -955,7 +959,7 @@ TEST(Bonding, ConnectNonBlocking) auto acthr = std::thread([&lsn_eid, &connect_passed, &accept_passed, &checks_done]() { SRT_EPOLL_EVENT ev[3]; - ThreadName::set("TEST_A"); + hvu::ThreadName::set("TEST_A"); cout << "[A] Waiting for main thread to pass connect()\n"; @@ -1517,10 +1521,10 @@ TEST(Bonding, BackupPrioritySelection) srt_setsockflag(ss, SRTO_GROUPMINSTABLETIMEO, &stabtimeo, sizeof stabtimeo); //srt_setloglevel(LOG_DEBUG); - srt::resetlogfa( std::set { - SRT_LOGFA_GRP_SEND, - SRT_LOGFA_GRP_MGMT, - SRT_LOGFA_CONN + srt::resetlogfa( std::set { + gslog.id(), + gmlog.id(), + cnlog.id() }); sockaddr_any sa = srt::CreateAddr("127.0.0.1", 4200, AF_INET); @@ -1747,7 +1751,7 @@ TEST(Bonding, BackupPrioritySelection) CheckLinksAgain: for (size_t i = 0; i < mc.grpdata_size; ++i) { - cout << "[" << i << "]" << srt_logging::MemberStatusStr(gdata[i].memberstate) + cout << "[" << i << "]" << srt::MemberStatusStr(gdata[i].memberstate) << " weight=" << gdata[i].weight; if (gdata[i].memberstate == SRT_GST_RUNNING) { diff --git a/test/test_common.cpp b/test/test_common.cpp index be8a4e49b..759716dec 100644 --- a/test/test_common.cpp +++ b/test/test_common.cpp @@ -119,10 +119,10 @@ TEST(SRTAPI, SyncRendezvousHangs) EXPECT_EQ(srt_rendezvous(sock, (sockaddr*)&local_sa, sizeof local_sa, (sockaddr*)&peer_sa, sizeof peer_sa), SRT_ERROR); - std::cout << "After-rendezvous @" << sock << " state: " << srt_logging::SockStatusStr(srt_getsockstate(sock)) << std::endl; + std::cout << "After-rendezvous @" << sock << " state: " << SockStatusStr(srt_getsockstate(sock)) << std::endl; close_thread.join(); - std::cout << "After-thread @" << sock << " state: " << srt_logging::SockStatusStr(srt_getsockstate(sock)) << std::endl; + std::cout << "After-thread @" << sock << " state: " << SockStatusStr(srt_getsockstate(sock)) << std::endl; ASSERT_LE(duration, 1lu); // Worst case it will compare uint64_t against uint32_t on 32-bit systems. } diff --git a/test/test_enforced_encryption.cpp b/test/test_enforced_encryption.cpp index 9461e18a0..c0d95a512 100644 --- a/test/test_enforced_encryption.cpp +++ b/test/test_enforced_encryption.cpp @@ -442,13 +442,13 @@ class TestEnforcedEncryption if (expect.socket_state[CHECK_SOCKET_ACCEPTED] == SRTS_BROKEN) { EXPECT_GE(sockstate, SRTS_BROKEN) << "[T] SOCKET @" << accepted_socket << " state=" - << srt_logging::SockStatusStr(sockstate); + << SockStatusStr(sockstate); } else { EXPECT_EQ(sockstate, expect.socket_state[CHECK_SOCKET_ACCEPTED]) << "[T] SOCKET @" << accepted_socket - << " state=" << srt_logging::SockStatusStr(sockstate) - << " (expected " << srt_logging::SockStatusStr(expect.socket_state[CHECK_SOCKET_ACCEPTED]) << ")"; + << " state=" << SockStatusStr(sockstate) + << " (expected " << SockStatusStr(expect.socket_state[CHECK_SOCKET_ACCEPTED]) << ")"; EXPECT_EQ(GetSocketOption(accepted_socket, SRTO_SNDKMSTATE), expect.km_state[CHECK_SOCKET_ACCEPTED]); } diff --git a/test/test_epoll.cpp b/test/test_epoll.cpp index 382476925..fce74d564 100644 --- a/test/test_epoll.cpp +++ b/test/test_epoll.cpp @@ -660,7 +660,7 @@ void testListenerReady(const bool LATE_CALL, size_t nmembers) EXPECT_EQ(SRT_EPOLL_OPT(fdset[0].events), SRT_EPOLL_UPDATE); SRTSOCKET joined = extra_call.get(); EXPECT_NE(joined, SRT_INVALID_SOCK); - std::cout << fmtcat("Extra joined: @", joined, "\n"); + std::cout << hvu::fmtcat("Extra joined: @", joined, "\n"); } std::vector gdata; @@ -674,7 +674,7 @@ void testListenerReady(const bool LATE_CALL, size_t nmembers) int groupndata = srt_group_data(sock, gdata.data(), (&inoutlen)); EXPECT_NE(groupndata, SRT_ERROR); - srt::ofmtbufstream sout; + hvu::ofmtbufstream sout; if (groupndata == SRT_ERROR) sout.puts("ERROR: ", srt_getlasterror_str(), " OUTLEN: ", inoutlen); else diff --git a/test/test_file_transmission.cpp b/test/test_file_transmission.cpp index 5d4f27506..ab4196ee8 100644 --- a/test/test_file_transmission.cpp +++ b/test/test_file_transmission.cpp @@ -19,7 +19,7 @@ #include "srt.h" #include "netinet_any.h" -#include "threadname.h" +#include "hvu_threadname.h" #include #include @@ -101,7 +101,7 @@ TEST(FileTransmission, Upload) auto client = std::thread([&] { - srt::ThreadName::set("TEST_RCV"); + hvu::ThreadName::set("TEST_RCV"); SRTSOCKET accepted_sock; try { diff --git a/test/test_listen_callback.cpp b/test/test_listen_callback.cpp index 42200c242..e48bff00c 100644 --- a/test/test_listen_callback.cpp +++ b/test/test_listen_callback.cpp @@ -13,7 +13,7 @@ #include "srt.h" #include "access_control.h" #include "utilities.h" -#include "threadname.h" +#include "hvu_threadname.h" using namespace srt; @@ -82,7 +82,7 @@ class ListenerCallback void AcceptLoop(std::future accept_go_on) { - srt::ThreadName::set("T/AcceptLoop"); + hvu::ThreadName::set("T/AcceptLoop"); // Setup EID in order to pick up either readiness or error. // THis is only to make a formal response side, nothing here is to be tested. diff --git a/test/test_reuseaddr.cpp b/test/test_reuseaddr.cpp index 575f54f59..003a3bfae 100644 --- a/test/test_reuseaddr.cpp +++ b/test/test_reuseaddr.cpp @@ -266,7 +266,7 @@ class ReuseAddr : public srt::Test if (bind_res != -1) break; - std::cout << srt::fmtcat("[T/S] ... retry #", i, "\n"); + std::cout << hvu::fmtcat("[T/S] ... retry #", i, "\n"); std::this_thread::sleep_for(std::chrono::milliseconds(500)); } diff --git a/test/test_socketdata.cpp b/test/test_socketdata.cpp index db32020de..bbc71b549 100644 --- a/test/test_socketdata.cpp +++ b/test/test_socketdata.cpp @@ -15,7 +15,7 @@ using namespace std; using namespace std::chrono; using namespace srt; -using namespace srt_logging; +using namespace srt::logging; TEST(SocketData, PeerName) { diff --git a/test/test_threadname.cpp b/test/test_threadname.cpp index 0b03686a4..142ad6a5d 100644 --- a/test/test_threadname.cpp +++ b/test/test_threadname.cpp @@ -2,9 +2,9 @@ #include #include "gtest/gtest.h" -#include "threadname.h" +#include "hvu_threadname.h" -using namespace srt; +using namespace hvu; TEST(ThreadName, GetSet) { diff --git a/testing/srt-test-file.cpp b/testing/srt-test-file.cpp index 5f9f52132..0baa61f30 100644 --- a/testing/srt-test-file.cpp +++ b/testing/srt-test-file.cpp @@ -29,10 +29,10 @@ written by #include #include #include +#include #include "apputil.hpp" #include "uriparser.hpp" -#include "logsupport.hpp" #include "socketoptions.hpp" #include "verbose.hpp" #include "testmedia.hpp" @@ -51,7 +51,7 @@ static bool g_skip_flushing = false; using namespace std; using namespace srt; -srt_logging::Logger applog(SRT_LOGFA_APP, srt_logger_config, "srt-file"); +hvu::logging::Logger applog("app", srt::logging::logger_config(), true, "srt-file"); int main( int argc, char** argv ) { @@ -108,9 +108,8 @@ int main( int argc, char** argv ) } string loglevel = Option(params, "error", o_loglevel); - srt_logging::LogLevel::type lev = SrtParseLogLevel(loglevel); + hvu::logging::LogLevel::type lev = hvu::logging::parse_level(loglevel); srt::setloglevel(lev); - srt::addlogfa(SRT_LOGFA_APP); bool verbo = OptionPresent(params, o_verbose); if (verbo) diff --git a/testing/srt-test-file.maf b/testing/srt-test-file.maf index 337415225..334b6d338 100644 --- a/testing/srt-test-file.maf +++ b/testing/srt-test-file.maf @@ -6,6 +6,4 @@ testmedia.cpp ../apps/verbose.cpp ../apps/socketoptions.cpp ../apps/uriparser.cpp -../apps/logsupport.cpp -../apps/logsupport_appdefs.cpp diff --git a/testing/srt-test-live.cpp b/testing/srt-test-live.cpp index 44585f072..2d642ec30 100644 --- a/testing/srt-test-live.cpp +++ b/testing/srt-test-live.cpp @@ -64,11 +64,10 @@ #include #include -#include "srt_compat.h" +#include "hvu_compat.h" #include "apputil.hpp" #include "uriparser.hpp" // UriParser #include "socketoptions.hpp" -#include "logsupport.hpp" #include "testmedia.hpp" // requires access to SRT-dependent globals #include "verbose.hpp" @@ -78,6 +77,7 @@ #include #include #include +#include // Define as 1 to test how the stubbed non-bonding version is working. #ifndef ENABLE_BONDING @@ -87,7 +87,8 @@ using namespace std; using namespace srt; -srt_logging::Logger applog(SRT_LOGFA_APP, srt_logger_config, "srt-live"); +hvu::logging::Logger applog("app", srt::logging::logger_config(), true, "srt-live"); + map g_options; @@ -281,10 +282,6 @@ bool CheckMediaSpec(const string& prefix, const vector& spec, string& w_ extern "C" void TestLogHandler(void* opaque, int level, const char* file, int line, const char* area, const char* message); -namespace srt_logging -{ - extern Logger glog; -} extern "C" int SrtCheckGroupHook(void* , SRTSOCKET acpsock, int , const sockaddr*, const char* ) { @@ -568,17 +565,18 @@ int main( int argc, char** argv ) cerr << "List of functional areas:\n"; map revmap; - for (auto entry: SrtLogFAList()) - revmap[entry.second] = entry.first; + for (size_t i = 0; i < srt::logging::logger_config().size(); ++i) + revmap[i] = srt::logging::logger_config().name(i); - int en10 = 0; + // Each group on a new line + int en6 = 0; for (auto entry: revmap) { cerr << " " << entry.second; - if (entry.first/10 != en10) + if (entry.first/6 != en6) { cerr << endl; - en10 = entry.first/10; + en6 = entry.first/6; } } cerr << endl; @@ -694,20 +692,21 @@ int main( int argc, char** argv ) size_t stoptime = Option(params, "0", o_stoptime); std::ofstream logfile_stream; // leave unused if not set - srt_setloglevel(SrtParseLogLevel(loglevel)); + srt_setloglevel(hvu::logging::parse_level(loglevel)); string logfa_on, logfa_off; ParseLogFASpec(logfa, (logfa_on), (logfa_off)); - set fasoff = SrtParseLogFA(logfa_off); - set fason = SrtParseLogFA(logfa_on); + set fasoff = hvu::logging::parse_fa(srt::logging::logger_config(), logfa_off); + set missing_on; + set fason = hvu::logging::parse_fa(srt::logging::logger_config(), logfa_on, &missing_on); auto fa_del = [fasoff]() { - for (set::iterator i = fasoff.begin(); i != fasoff.end(); ++i) + for (set::iterator i = fasoff.begin(); i != fasoff.end(); ++i) srt_dellogfa(*i); }; auto fa_add = [fason]() { - for (set::iterator i = fason.begin(); i != fason.end(); ++i) + for (set::iterator i = fason.begin(); i != fason.end(); ++i) srt_addlogfa(*i); }; @@ -730,17 +729,21 @@ int main( int argc, char** argv ) fa_del(); } - - srt::addlogfa(SRT_LOGFA_APP); + if (!missing_on.empty()) + { + cerr << "WARNING: unknown logging FA: "; + copy(missing_on.begin(), missing_on.end(), ostream_iterator(cerr, " ")); + cerr << endl; + } char NAME[] = "SRTLIB"; if ( internal_log ) { srt_setlogflags( 0 - | SRT_LOGF_DISABLE_TIME - | SRT_LOGF_DISABLE_SEVERITY - | SRT_LOGF_DISABLE_THREADNAME - | SRT_LOGF_DISABLE_EOL + | HVU_LOGF_DISABLE_TIME + | HVU_LOGF_DISABLE_SEVERITY + | HVU_LOGF_DISABLE_THREADNAME + | HVU_LOGF_DISABLE_EOL ); srt_setloghandler(NAME, TestLogHandler); } @@ -1007,29 +1010,21 @@ int main( int argc, char** argv ) void TestLogHandler(void* opaque, int level, const char* file, int line, const char* area, const char* message) { - char prefix[100] = ""; - if ( opaque ) { -#ifdef _MSC_VER - strncpy_s(prefix, sizeof(prefix), (char*)opaque, _TRUNCATE); -#else - strncpy(prefix, (char*)opaque, sizeof(prefix) - 1); - prefix[sizeof(prefix) - 1] = '\0'; -#endif + std::string prefix; + if (opaque) + { + const char* instr = (const char*)opaque; + size_t len = strlen(instr); + if (len > 10) + len = 10; + prefix = ":" + string(instr, len); } + time_t now; time(&now); - char buf[1024]; - struct tm local = SysLocalTime(now); - size_t pos = strftime(buf, 1024, "[%c ", &local); - -#ifdef _MSC_VER - // That's something weird that happens on Microsoft Visual Studio 2013 - // Trying to keep portability, while every version of MSVS is a different plaform. - // On MSVS 2015 there's already a standard-compliant snprintf, whereas _snprintf - // is available on backward compatibility and it doesn't work exactly the same way. -#define snprintf _snprintf -#endif - snprintf(buf+pos, 1024-pos, "%s:%d(%s)]{%d} %s", file, line, area, level, message); + struct tm local = hvu::SysLocalTime(now); - cerr << buf << endl; + cerr << "[" << std::put_time(&local, "%c") << " " << file << ":" << line + << "(" << area << ")]{" << level << "} " << prefix << message + << endl; } diff --git a/testing/srt-test-live.maf b/testing/srt-test-live.maf index e80d79ec7..363ae73f3 100644 --- a/testing/srt-test-live.maf +++ b/testing/srt-test-live.maf @@ -8,6 +8,4 @@ testmedia.cpp ../apps/verbose.cpp ../apps/socketoptions.cpp ../apps/uriparser.cpp -../apps/logsupport.cpp -../apps/logsupport_appdefs.cpp diff --git a/testing/srt-test-mpbond.cpp b/testing/srt-test-mpbond.cpp index 8a5143ddf..3275bfa31 100644 --- a/testing/srt-test-mpbond.cpp +++ b/testing/srt-test-mpbond.cpp @@ -22,11 +22,10 @@ #include "apputil.hpp" // CreateAddr #include "uriparser.hpp" // UriParser #include "socketoptions.hpp" -#include "logsupport.hpp" #include "testmediabase.hpp" #include "testmedia.hpp" #include "netinet_any.h" -#include "threadname.h" +#include "logger_fas.h" #include "verbose.hpp" #include @@ -40,7 +39,7 @@ #define signal_alarm(fn) signal(SIGALRM, fn) #endif -srt_logging::Logger applog(SRT_LOGFA_APP, srt_logger_config, "srt-mpbond"); +hvu::logging::Logger applog("app", srt::logging::logger_config(), true, "srt-mpbond"); using namespace srt; using namespace std; @@ -134,9 +133,8 @@ int main( int argc, char** argv ) bool mode_output = OptionPresent(params, o_output); string loglevel = Option(params, "error", "ll", "loglevel"); - srt_logging::LogLevel::type lev = SrtParseLogLevel(loglevel); + hvu::logging::LogLevel::type lev = hvu::logging::parse_level(loglevel); srt::setloglevel(lev); - srt::addlogfa(SRT_LOGFA_APP); // Check verbose option before extracting the argument so that Verb()s // can be displayed also when they report something about option parsing. diff --git a/testing/srt-test-mpbond.maf b/testing/srt-test-mpbond.maf index e2609b1b0..8e5f10965 100644 --- a/testing/srt-test-mpbond.maf +++ b/testing/srt-test-mpbond.maf @@ -6,6 +6,4 @@ testmedia.cpp ../apps/verbose.cpp ../apps/socketoptions.cpp ../apps/uriparser.cpp -../apps/logsupport.cpp -../apps/logsupport_appdefs.cpp diff --git a/testing/srt-test-multiplex.cpp b/testing/srt-test-multiplex.cpp index f1f226fae..a24d0ed2c 100644 --- a/testing/srt-test-multiplex.cpp +++ b/testing/srt-test-multiplex.cpp @@ -22,15 +22,15 @@ #include "apputil.hpp" // CreateAddr #include "uriparser.hpp" // UriParser #include "socketoptions.hpp" -#include "logsupport.hpp" #include "testmediabase.hpp" #include "testmedia.hpp" #include "netinet_any.h" -#include "threadname.h" #include "verbose.hpp" #include #include +#include +#include // Make the windows-nonexistent alarm an empty call #ifdef _WIN32 @@ -48,7 +48,7 @@ using namespace srt; // So far, this function must be used and up to this length of payload. const size_t DEFAULT_CHUNK = 1316; -srt_logging::Logger applog(SRT_LOGFA_APP, srt_logger_config, "srt-mplex"); +hvu::logging::Logger applog("app", srt::logging::logger_config(), false, "srt-mplex"); volatile bool siplex_int_state = false; void OnINT_SetIntState(int) @@ -197,7 +197,7 @@ class MediaBase med.name = name; // Ok, got this, so we can start transmission. - srt::ThreadName tn(thread_name); + hvu::ThreadName tn(thread_name); med.runner = thread( [&med]() { med.TransmissionLoop(); }); return med; @@ -564,9 +564,8 @@ int main( int argc, char** argv ) } string loglevel = Option(params, "error", "ll", "loglevel"); - srt_logging::LogLevel::type lev = SrtParseLogLevel(loglevel); + hvu::logging::LogLevel::type lev = hvu::logging::parse_level(loglevel); srt::setloglevel(lev); - srt::addlogfa(SRT_LOGFA_APP); string verbo = Option(params, "no", "v", "verbose"); if ( verbo == "" || !false_names.count(verbo) ) @@ -592,7 +591,7 @@ int main( int argc, char** argv ) SrtModel m(up.host(), iport, up.parameters()); - srt::ThreadName::set("main"); + hvu::ThreadName::set("main"); // Note: for input, there must be an exactly defined // number of sources. The loop rolls up to all these sources. @@ -635,7 +634,7 @@ int main( int argc, char** argv ) applog.Error() << "Unable to select a link for id=" << id << ": " << msg; } - srt::ThreadName::set("main"); + hvu::ThreadName::set("main"); } applog.Note() << "All local stream definitions covered. Waiting for interrupt/broken all connections."; diff --git a/testing/srt-test-multiplex.maf b/testing/srt-test-multiplex.maf index 5e7cd8507..231e56671 100644 --- a/testing/srt-test-multiplex.maf +++ b/testing/srt-test-multiplex.maf @@ -7,6 +7,4 @@ testmedia.cpp ../apps/verbose.cpp ../apps/socketoptions.cpp ../apps/uriparser.cpp -../apps/logsupport.cpp -../apps/logsupport_appdefs.cpp diff --git a/testing/srt-test-relay.cpp b/testing/srt-test-relay.cpp index 725efadb0..0b1e4af8e 100755 --- a/testing/srt-test-relay.cpp +++ b/testing/srt-test-relay.cpp @@ -36,12 +36,11 @@ written by #include "apputil.hpp" #include "uriparser.hpp" -#include "logsupport.hpp" #include "logging.h" #include "socketoptions.hpp" #include "verbose.hpp" #include "testmedia.hpp" -#include "threadname.h" +#include "hvu_threadname.h" using namespace std; @@ -51,7 +50,7 @@ using namespace srt; bool Upload(UriParser& srt, UriParser& file); bool Download(UriParser& srt, UriParser& file); -srt_logging::Logger applog(SRT_LOGFA_APP, srt_logger_config, "srt-relay"); +hvu::logging::Logger applog("app", srt::logging::logger_config(), true, "srt-relay"); std::atomic g_program_established {false}; @@ -172,23 +171,42 @@ int main( int argc, char** argv ) } string loglevel = Option(params, "error", o_loglevel); - string logfa = Option(params, "", o_logfa); - srt_logging::LogLevel::type lev = SrtParseLogLevel(loglevel); - srt::setloglevel(lev); - if (logfa == "") + vector logfa = Option(params, o_logfa); + srt_setloglevel(hvu::logging::parse_level(loglevel)); + + string logfa_on, logfa_off; + ParseLogFASpec(logfa, (logfa_on), (logfa_off)); + + set fasoff = hvu::logging::parse_fa(srt::logging::logger_config(), logfa_off); + set fason = hvu::logging::parse_fa(srt::logging::logger_config(), logfa_on); + + auto fa_del = [fasoff]() { + for (set::iterator i = fasoff.begin(); i != fasoff.end(); ++i) + srt_dellogfa(*i); + }; + + auto fa_add = [fason]() { + for (set::iterator i = fason.begin(); i != fason.end(); ++i) + srt_addlogfa(*i); + }; + + if (logfa_off == "all") { - srt::addlogfa(SRT_LOGFA_APP); + // If the spec is: + // -lfa ~all control app + // then we first delete all, then enable given ones + fa_del(); + fa_add(); } else { - // Add only selected FAs - set unknown_fas; - set fas = SrtParseLogFA(logfa, &unknown_fas); - srt::resetlogfa(fas); - - // The general parser doesn't recognize the "app" FA, we check it here. - if (unknown_fas.count("app")) - srt::addlogfa(SRT_LOGFA_APP); + // Otherwise we first add all those that have to be added, + // then delete those unwanted. This embraces both + // -lfa control app ~cc + // and + // -lfa all ~cc + fa_add(); + fa_del(); } string verbo = Option(params, "no", o_verbose); @@ -393,7 +411,7 @@ SrtMainLoop::SrtMainLoop(const string& srt_uri, bool input_echoback, const strin void SrtMainLoop::InputRunner() { - srt::ThreadName::set("InputRN"); + hvu::ThreadName::set("InputRN"); // An extra thread with a loop that reads from the external input // and writes into the SRT medium. When echoback mode is used, // this thread isn't started at all and instead the SRT reading @@ -439,7 +457,7 @@ void SrtMainLoop::run() std::ostringstream tns; tns << "Input:" << this; - srt::ThreadName tn(tns.str()); + hvu::ThreadName tn(tns.str()); m_input_thr = thread([this] { try { InputRunner(); diff --git a/testing/srt-test-relay.maf b/testing/srt-test-relay.maf index 33cba8173..eba1cc137 100644 --- a/testing/srt-test-relay.maf +++ b/testing/srt-test-relay.maf @@ -8,6 +8,4 @@ testactivemedia.cpp ../apps/verbose.cpp ../apps/socketoptions.cpp ../apps/uriparser.cpp -../apps/logsupport.cpp -../apps/logsupport_appdefs.cpp diff --git a/testing/testactivemedia.cpp b/testing/testactivemedia.cpp index 44c96ee65..7d6a74c86 100644 --- a/testing/testactivemedia.cpp +++ b/testing/testactivemedia.cpp @@ -11,7 +11,7 @@ const char* fmt_yesno(bool b) { return b ? "yes" : "no"; } void SourceMedium::Runner() { - srt::ThreadName::set("SourceRN"); + hvu::ThreadName::set("SourceRN"); Verb() << VerbLock << "Starting SourceMedium: " << this; for (;;) @@ -71,7 +71,7 @@ MediaPacket SourceMedium::Extract() void TargetMedium::Runner() { - srt::ThreadName::set("TargetRN"); + hvu::ThreadName::set("TargetRN"); auto on_return_set = OnReturnSet(running, false); Verb() << VerbLock << "Starting TargetMedium: " << this; for (;;) diff --git a/testing/testactivemedia.hpp b/testing/testactivemedia.hpp index e92abbe0c..4a1fdb761 100644 --- a/testing/testactivemedia.hpp +++ b/testing/testactivemedia.hpp @@ -9,15 +9,15 @@ #include #include "testmedia.hpp" -#include "logsupport.hpp" #define SRT_ENABLE_VERBOSE_LOCK 1 #include "verbose.hpp" #include "logging.h" -#include "threadname.h" +#include "logger_fas.h" +#include "hvu_threadname.h" -extern srt_logging::Logger applog; +extern hvu::logging::Logger applog; template struct Medium @@ -57,7 +57,7 @@ struct Medium running = true; std::ostringstream tns; tns << typeid(*this).name() << ":" << this; - srt::ThreadName tn(tns.str()); + hvu::ThreadName tn(tns.str()); thr = std::thread( [this] { RunnerBase(); } ); } diff --git a/testing/testmedia.cpp b/testing/testmedia.cpp index 0a6bbbd7f..802832235 100755 --- a/testing/testmedia.cpp +++ b/testing/testmedia.cpp @@ -33,21 +33,23 @@ #include "common.h" #include "api.h" #include "logging.h" +#include "ofmt.h" #include "utilities.h" #include "apputil.hpp" #include "socketoptions.hpp" #include "uriparser.hpp" #include "testmedia.hpp" -#include "srt_compat.h" +#include "hvu_compat.h" #include "verbose.hpp" using namespace std; using namespace srt; +using namespace hvu; -using srt_logging::KmStateStr; -using srt_logging::SockStatusStr; -using srt_logging::MemberStatusStr; +using srt::KmStateStr; +using srt::SockStatusStr; +using srt::MemberStatusStr; srt::sync::atomic transmit_throw_on_interrupt {false}; srt::sync::atomic transmit_int_state {false}; @@ -108,7 +110,9 @@ struct CloseReasonMap } g_close_reason; // Do not unblock. Copy this to an app that uses applog and set appropriate name. -//srt_logging::Logger applog(SRT_LOGFA_APP, srt_logger_config, "srt-test"); +// app_logger_config must be also declared in the same place (it must be +// initialized before this object can be initialized). +//hvu::logging::Logger applog("app", app_logger_config, true, "srt-test"); std::shared_ptr transmit_stats_writer; @@ -887,7 +891,7 @@ SRTSTATUS SrtCommon::ConfigurePost(SRTSOCKET sock) if (result == SRT_ERROR) { #ifdef PLEASE_LOG - extern srt_logging::Logger applog; + extern hvu::logging::Logger applog; applog.Error() << "ERROR SETTING OPTION: SRTO_SNDSYN"; #endif return result; @@ -898,7 +902,7 @@ SRTSTATUS SrtCommon::ConfigurePost(SRTSOCKET sock) if (result == SRT_ERROR) { #ifdef PLEASE_LOG - extern srt_logging::Logger applog; + extern hvu::logging::Logger applog; applog.Error() << "ERROR SETTING OPTION: SRTO_SNDTIMEO"; #endif return result; @@ -1606,7 +1610,7 @@ void SrtCommon::SetupRendezvous(string adapter, string host, int port) void SrtCommon::Close() { #if PLEASE_LOG - extern srt_logging::Logger applog; + extern hvu::logging::Logger applog; LOGP(applog.Error, "CLOSE requested - closing socket @", m_sock); #endif bool any = false; @@ -1746,7 +1750,7 @@ void SrtCommon::UpdateGroupStatus(const SRT_SOCKGROUPDATA* grpdata, size_t grpda SrtSource::SrtSource(string host, int port, std::string path, const map& par) { Init(host, port, path, par, SRT_EPOLL_IN); - hostport_copy = srt::fmtcat(host, ":"_V, port); + hostport_copy = fmtcat(host, ":"_V, port); } static void PrintSrtStats(SRTSOCKET sock, bool clr, bool bw, bool stats) @@ -1859,7 +1863,7 @@ MediaPacket SrtSource::Read(size_t chunk) throw ReadEOF(hostport_copy); } #if PLEASE_LOG - extern srt_logging::Logger applog; + extern hvu::logging::Logger applog; LOGC(applog.Debug, log << "recv: #" << mctrl.msgno << " %" << mctrl.pktseq << " " << BufferStamp(data.data(), stat) << " BELATED: " << ((srt_time_now()-mctrl.srctime)/1000.0) << "ms"); #endif @@ -2322,8 +2326,7 @@ void UdpCommon::Setup(string host, int port, map attr) void UdpCommon::Error(int err, string src) { - char buf[512]; - string message = SysStrError(err, buf, 512u); + string message = hvu::SysStrError(err); if (Verbose::on) Verb() << "FAILURE\n" << src << ": [" << err << "] " << message; diff --git a/testing/testmedia.hpp b/testing/testmedia.hpp index b8ee12a93..022b45b68 100644 --- a/testing/testmedia.hpp +++ b/testing/testmedia.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include // use srt::sync::atomic instead of std::atomic for the sake of logging @@ -29,8 +30,43 @@ extern srt::sync::atomic transmit_int_state; extern std::shared_ptr transmit_stats_writer; -const srt_logging::LogFA SRT_LOGFA_APP = 10; -extern srt_logging::Logger applog; +extern hvu::logging::Logger applog; + +// Temporary; it's not a good idea to put it into apputils.hpp until this is +// extracted the options library from. +inline void ParseLogFASpec(const std::vector& speclist, std::string& w_on, std::string& w_off) +{ + using namespace std; + + hvu::ofmtbufstream son, soff; + + for (auto& s: speclist) + { + string name; + bool on = true; + if (s[0] == '+') + name = s.substr(1); + else if (s[0] == '~') + { + name = s.substr(1); + on = false; + } + else + name = s; + + if (on) + son << "," << name; + else + soff << "," << name; + } + + const string& sons = son.str(); + const string& soffs = soff.str(); + + w_on = sons.empty() ? string() : sons.substr(1); + w_off = soffs.empty() ? string() : soffs.substr(1); +} + // Trial version of an exception. Try to implement later an official // interruption mechanism in SRT using this.