LCOV - code coverage report
Current view: top level - foo/src - logger.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 185 238 77.7 %
Date: 2026-02-28 10:41:24 Functions: 37 48 77.1 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2026 Savoir-faire Linux Inc.
       3             :  *
       4             :  *  This program is free software: you can redistribute it and/or modify
       5             :  *  it under the terms of the GNU General Public License as published by
       6             :  *  the Free Software Foundation, either version 3 of the License, or
       7             :  *  (at your option) any later version.
       8             :  *
       9             :  *  This program is distributed in the hope that it will be useful,
      10             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      12             :  *  GNU General Public License for more details.
      13             :  *
      14             :  *  You should have received a copy of the GNU General Public License
      15             :  *  along with this program. If not, see <https://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include <cstdio>
      19             : #include <cstring>
      20             : #include <cerrno>
      21             : #include <ctime>
      22             : 
      23             : #include "client/jami_signal.h"
      24             : 
      25             : #include <fmt/core.h>
      26             : #include <fmt/format.h>
      27             : #include <fmt/compile.h>
      28             : 
      29             : #ifdef _MSC_VER
      30             : #include <sys_time.h>
      31             : #else
      32             : #include <sys/time.h>
      33             : #endif
      34             : 
      35             : #include <atomic>
      36             : #include <condition_variable>
      37             : #include <functional>
      38             : #include <fstream>
      39             : #include <string>
      40             : #include <ios>
      41             : #include <mutex>
      42             : #include <thread>
      43             : #include <array>
      44             : #include <list>
      45             : 
      46             : #include "fileutils.h"
      47             : #include "logger.h"
      48             : 
      49             : #include <stdio.h>
      50             : #ifdef __linux__
      51             : #include <unistd.h>
      52             : #include <syslog.h>
      53             : #include <sys/syscall.h>
      54             : #endif // __linux__
      55             : 
      56             : #ifdef __ANDROID__
      57             : #ifndef APP_NAME
      58             : #define APP_NAME "libjami"
      59             : #endif /* APP_NAME */
      60             : #endif
      61             : 
      62             : #define END_COLOR "\033[0m"
      63             : 
      64             : #ifndef _WIN32
      65             : #define RED    "\033[22;31m"
      66             : #define YELLOW "\033[01;33m"
      67             : #define CYAN   "\033[22;36m"
      68             : #else
      69             : #define FOREGROUND_WHITE 0x000f
      70             : #define RED              FOREGROUND_RED + 0x0008
      71             : #define YELLOW           FOREGROUND_RED + FOREGROUND_GREEN + 0x0008
      72             : #define CYAN             FOREGROUND_BLUE + FOREGROUND_GREEN + 0x0008
      73             : #define LIGHT_GREEN      FOREGROUND_GREEN + 0x0008
      74             : #endif // _WIN32
      75             : 
      76             : #define LOGFILE "jami"
      77             : 
      78             : namespace jami {
      79             : 
      80             : static constexpr auto ENDL = '\n';
      81             : 
      82             : #ifndef __GLIBC__
      83             : static const char*
      84             : check_error(int result, char* buffer)
      85             : {
      86             :     switch (result) {
      87             :     case 0:
      88             :         return buffer;
      89             : 
      90             :     case ERANGE: /* should never happen */
      91             :         return "unknown (too big to display)";
      92             : 
      93             :     default:
      94             :         return "unknown (invalid error number)";
      95             :     }
      96             : }
      97             : 
      98             : static const char*
      99             : check_error(char* result, char*)
     100             : {
     101             :     return result;
     102             : }
     103             : #endif
     104             : 
     105             : void
     106           0 : strErr()
     107             : {
     108             : #ifdef __GLIBC__
     109           0 :     JAMI_ERR("%m");
     110             : #else
     111             :     char buf[1000];
     112             :     JAMI_ERR("%s", check_error(strerror_r(errno, buf, sizeof(buf)), buf));
     113             : #endif
     114           0 : }
     115             : 
     116             : // extract the last component of a pathname (extract a filename from its dirname)
     117             : static constexpr std::string_view
     118      599743 : stripDirName(std::string_view path)
     119             : {
     120      599743 :     if (!path.empty()) {
     121      599699 :         size_t pos = path.find_last_of("/\\");
     122      599898 :         if (pos != std::string_view::npos)
     123      194802 :             return path.substr(pos + 1);
     124             :     }
     125      405091 :     return path;
     126             : }
     127             : 
     128             : std::string
     129      299568 : formatHeader(std::string_view file, unsigned line)
     130             : {
     131             : #ifdef __linux__
     132      299568 :     auto tid = syscall(__NR_gettid) & 0xffff;
     133             : #else
     134             :     auto tid = std::this_thread::get_id();
     135             : #endif // __linux__
     136             : 
     137             :     unsigned int secs, milli;
     138             :     struct timeval tv;
     139      300101 :     if (!gettimeofday(&tv, NULL)) {
     140      300086 :         secs = tv.tv_sec;
     141      300086 :         milli = tv.tv_usec / 1000; // suppose that milli < 1000
     142             :     } else {
     143           0 :         secs = time(NULL);
     144           0 :         milli = 0;
     145             :     }
     146             : 
     147      300086 :     if (!file.empty()) {
     148      899981 :         return fmt::format(FMT_COMPILE("[{: >3d}.{:0<3d}|{: >4}|{: <24s}:{: <4d}] "),
     149             :                            secs,
     150             :                            milli,
     151             :                            tid,
     152      599476 :                            stripDirName(file),
     153      299441 :                            line);
     154             :     } else {
     155           0 :         return fmt::format(FMT_COMPILE("[{: >3d}.{:0<3d}|{: >4}] "), secs, milli, tid);
     156             :     }
     157             : }
     158             : 
     159             : std::string
     160       22325 : formatPrintfArgs(const char* format, va_list ap)
     161             : {
     162       22325 :     std::string ret;
     163             :     /* A good guess of what we might encounter. */
     164             :     static constexpr size_t default_buf_size = 80;
     165             : 
     166       22318 :     ret.resize(default_buf_size);
     167             : 
     168             :     /* Necessary if we don't have enough space in buf. */
     169             :     va_list cp;
     170       22320 :     va_copy(cp, ap);
     171             : 
     172       22320 :     int size = vsnprintf(ret.data(), ret.size(), format, ap);
     173             : 
     174             :     /* Not enough space?  Well try again. */
     175       22314 :     if ((size_t) size >= ret.size()) {
     176        1440 :         ret.resize(size + 1);
     177        1440 :         vsnprintf((char*) ret.data(), ret.size(), format, cp);
     178             :     }
     179             : 
     180       22338 :     ret.resize(size);
     181             : 
     182       22322 :     va_end(cp);
     183             : 
     184       44644 :     return ret;
     185           0 : }
     186             : 
     187             : struct Logger::Msg
     188             : {
     189             :     Msg() = delete;
     190             : 
     191      277546 :     Msg(int level, std::string_view file, unsigned line, bool linefeed, std::string_view tag, std::string&& message)
     192      277546 :         : file_(stripDirName(file))
     193      277612 :         , line_(line)
     194      277612 :         , tag_(tag)
     195      277612 :         , payload_(std::move(message))
     196      277192 :         , level_(level)
     197      277192 :         , linefeed_(linefeed)
     198      277192 :         , header_(formatHeader(file_, line_))
     199      277202 :     {}
     200             : 
     201       22327 :     Msg(int level, std::string_view file, unsigned line, bool linefeed, std::string_view tag, const char* fmt, va_list ap)
     202       22327 :         : file_(stripDirName(file))
     203       22326 :         , line_(line)
     204       22326 :         , tag_(tag)
     205       22326 :         , payload_(formatPrintfArgs(fmt, ap))
     206       22322 :         , level_(level)
     207       22322 :         , linefeed_(linefeed)
     208       22322 :         , header_(formatHeader(file_, line_))
     209       22317 :     {}
     210             : 
     211         702 :     Msg(Msg&& other) = default;
     212      299345 :     Msg& operator=(Msg&& other) = default;
     213             : 
     214             :     std::string_view file_;
     215             :     unsigned line_;
     216             :     std::string_view tag_;
     217             :     std::string payload_;
     218             :     int level_;
     219             :     bool linefeed_;
     220             :     std::string header_;
     221             : };
     222             : 
     223             : class Logger::Handler
     224             : {
     225             : public:
     226           0 :     virtual ~Handler() = default;
     227             : 
     228             :     virtual void consume(const Msg& msg) = 0;
     229             : 
     230         906 :     virtual void enable(bool en) { enabled_.store(en, std::memory_order_relaxed); }
     231     1500455 :     bool isEnable() { return enabled_.load(std::memory_order_relaxed); }
     232             : 
     233             : protected:
     234             :     std::atomic_bool enabled_ {false};
     235             : };
     236             : 
     237             : class ConsoleLog final : public Logger::Handler
     238             : {
     239             : public:
     240          38 :     ConsoleLog() = default;
     241             : 
     242             : #ifdef _WIN32
     243             :     void printLogImpl(const Logger::Msg& msg, bool with_color)
     244             :     {
     245             :         // If we are using Visual Studio, we can use OutputDebugString to print
     246             :         // to the "Output" window. Otherwise, we just use fputs to stderr.
     247             :         static std::function<void(const char* str)> fputsFunc = [](const char* str) {
     248             :             fputs(str, stderr);
     249             :         };
     250             :         static std::function<void(const char* str)> outputDebugStringFunc = [](const char* str) {
     251             :             OutputDebugStringA(str);
     252             :         };
     253             :         static std::function<void()> putcFunc = []() {
     254             :             putc(ENDL, stderr);
     255             :         };
     256             :         // These next two functions will be used to print the message and line ending.
     257             :         static auto printFunc = IsDebuggerPresent() ? outputDebugStringFunc : fputsFunc;
     258             :         static auto endlFunc = IsDebuggerPresent() ? []() { OutputDebugStringA("\n"); } : putcFunc;
     259             : 
     260             :         WORD saved_attributes;
     261             :         static HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
     262             :         auto& header = msg.header_;
     263             :         if (with_color) {
     264             :             static WORD color_header = CYAN;
     265             :             WORD color_prefix = LIGHT_GREEN;
     266             :             CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
     267             : 
     268             :             switch (msg.level_) {
     269             :             case LOG_ERR:
     270             :                 color_prefix = RED;
     271             :                 break;
     272             : 
     273             :             case LOG_WARNING:
     274             :                 color_prefix = YELLOW;
     275             :                 break;
     276             :             }
     277             : 
     278             :             GetConsoleScreenBufferInfo(hConsole, &consoleInfo);
     279             :             saved_attributes = consoleInfo.wAttributes;
     280             :             SetConsoleTextAttribute(hConsole, color_header);
     281             : 
     282             :             printFunc(header.c_str());
     283             : 
     284             :             SetConsoleTextAttribute(hConsole, saved_attributes);
     285             :             SetConsoleTextAttribute(hConsole, color_prefix);
     286             :         } else {
     287             :             printFunc(header.c_str());
     288             :         }
     289             : 
     290             :         if (!msg.tag_.empty())
     291             :             printFunc(msg.tag_.data());
     292             :         printFunc(msg.payload_.c_str());
     293             : 
     294             :         if (msg.linefeed_) {
     295             :             endlFunc();
     296             :         }
     297             : 
     298             :         if (with_color) {
     299             :             SetConsoleTextAttribute(hConsole, saved_attributes);
     300             :         }
     301             :     }
     302             : #else
     303      300045 :     void printLogImpl(const Logger::Msg& msg, bool with_color)
     304             :     {
     305      300045 :         if (with_color) {
     306      300045 :             constexpr const char* color_header = CYAN;
     307      300045 :             const char* color_prefix = "";
     308             : 
     309      300045 :             switch (msg.level_) {
     310        6297 :             case LOG_ERR:
     311        6297 :                 color_prefix = RED;
     312        6297 :                 break;
     313             : 
     314       32470 :             case LOG_WARNING:
     315       32470 :                 color_prefix = YELLOW;
     316       32470 :                 break;
     317             :             }
     318             : 
     319      300045 :             fputs(color_header, stderr);
     320      300045 :             fwrite(msg.header_.c_str(), 1, msg.header_.size(), stderr);
     321      300045 :             fputs(END_COLOR, stderr);
     322      300045 :             fputs(color_prefix, stderr);
     323             :         } else {
     324           0 :             fwrite(msg.header_.c_str(), 1, msg.header_.size(), stderr);
     325             :         }
     326             : 
     327      300045 :         if (!msg.tag_.empty())
     328       71533 :             fwrite(msg.tag_.data(), 1, msg.tag_.size(), stderr);
     329      300045 :         fputs(msg.payload_.c_str(), stderr);
     330             : 
     331      300045 :         if (with_color) {
     332      300045 :             fputs(END_COLOR, stderr);
     333             :         }
     334      300045 :         if (msg.linefeed_) {
     335      300041 :             putc(ENDL, stderr);
     336             :         }
     337      300045 :     }
     338             : #endif /* _WIN32 */
     339             : 
     340             :     bool withColor_ = !(getenv("NO_COLOR") || getenv("NO_COLORS") || getenv("NO_COLOUR") || getenv("NO_COLOURS"));
     341             : 
     342      300045 :     void consume(const Logger::Msg& msg) override { printLogImpl(msg, withColor_); }
     343             : };
     344             : 
     345             : class SysLog final : public Logger::Handler
     346             : {
     347             : public:
     348          38 :     SysLog()
     349          38 :     {
     350             : #ifdef _WIN32
     351             :         ::openlog(LOGFILE, WINLOG_PID, WINLOG_MAIL);
     352             : #else
     353             : #ifndef __ANDROID__
     354          38 :         ::openlog(LOGFILE, LOG_NDELAY, LOG_USER);
     355             : #endif
     356             : #endif /* _WIN32 */
     357          38 :     }
     358             : 
     359           0 :     void consume(const Logger::Msg& msg) override
     360             :     {
     361             : #ifdef __ANDROID__
     362             :         __android_log_write(msg.level_, msg.file_.data(), msg.payload_.c_str());
     363             : #else
     364           0 :         ::syslog(msg.level_,
     365             :                  "%.*s%.*s",
     366           0 :                  (int) msg.tag_.size(),
     367             :                  msg.tag_.data(),
     368           0 :                  (int) msg.payload_.size(),
     369             :                  msg.payload_.data());
     370             : #endif
     371           0 :     }
     372             : };
     373             : 
     374             : class MonitorLog final : public Logger::Handler
     375             : {
     376             : public:
     377          38 :     MonitorLog() = default;
     378             : 
     379           0 :     void consume(const Logger::Msg& msg) override
     380             :     {
     381           0 :         auto message = msg.header_ + msg.payload_;
     382           0 :         emitSignal<libjami::ConfigurationSignal::MessageSend>(message);
     383           0 :     }
     384             : };
     385             : 
     386             : class FileLog final : public Logger::Handler
     387             : {
     388             : public:
     389          38 :     FileLog() = default;
     390             : 
     391         302 :     void setFile(const std::string& path)
     392             :     {
     393         302 :         std::lock_guard lk(mtx_);
     394         302 :         if (file_.is_open())
     395           0 :             file_.close();
     396             : 
     397         302 :         if (not path.empty()) {
     398           0 :             file_.open(path, std::ofstream::out | std::ofstream::app);
     399           0 :             if (file_)
     400           0 :                 enable(true);
     401             :             else
     402           0 :                 enable(false);
     403             :         } else {
     404         302 :             enable(false);
     405             :         }
     406         302 :     }
     407             : 
     408           0 :     void consume(const Logger::Msg& msg) override
     409             :     {
     410           0 :         std::lock_guard lk(mtx_);
     411           0 :         if (file_.is_open()) {
     412           0 :             file_ << msg.header_ << msg.tag_ << msg.payload_;
     413           0 :             if (msg.linefeed_)
     414           0 :                 file_ << ENDL;
     415           0 :             file_.flush();
     416             :         }
     417           0 :     }
     418             : 
     419             : private:
     420             :     std::mutex mtx_;
     421             :     std::ofstream file_;
     422             : };
     423             : 
     424             : class LogDispatcher final
     425             : {
     426             : public:
     427      600452 :     static LogDispatcher& instance()
     428             :     {
     429      600452 :         static LogDispatcher* self = new LogDispatcher();
     430      600428 :         return *self;
     431             :     }
     432             : 
     433      299467 :     void log(Logger::Msg&& msg)
     434             :     {
     435             :         {
     436      299467 :             std::lock_guard lk(mtx_);
     437      300118 :             if (!running_)
     438          71 :                 return;
     439      300047 :             if (!recycleQueue_.empty()) {
     440      299345 :                 msgQueue_.splice(msgQueue_.end(), recycleQueue_, recycleQueue_.begin());
     441      299345 :                 msgQueue_.back() = std::move(msg);
     442             :             } else {
     443         702 :                 msgQueue_.emplace_back(std::move(msg));
     444             :             }
     445      300118 :         }
     446      300042 :         cv_.notify_one();
     447             :     }
     448             : 
     449         302 :     void stop()
     450             :     {
     451             :         {
     452         302 :             std::lock_guard lk(mtx_);
     453         302 :             if (!running_)
     454           0 :                 return;
     455         302 :             running_ = false;
     456         302 :         }
     457         302 :         cv_.notify_all();
     458         302 :         if (thread_.joinable())
     459         302 :             thread_.join();
     460         302 :         recycleQueue_.splice(recycleQueue_.end(), std::move(msgQueue_));
     461             :     }
     462             : 
     463             :     ConsoleLog consoleLog;
     464             :     SysLog sysLog;
     465             :     MonitorLog monitorLog;
     466             :     FileLog fileLog;
     467             : 
     468         302 :     void enableFileLog(const std::string& path)
     469             :     {
     470         302 :         fileLog.setFile(path);
     471         302 :         checkStatus();
     472         302 :     }
     473             : 
     474         302 :     void enableConsoleLog(bool en)
     475             :     {
     476         302 :         consoleLog.enable(en);
     477         302 :         checkStatus();
     478             : #ifdef _WIN32
     479             :         static WORD original_attributes;
     480             :         if (en) {
     481             :             if (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()) {
     482             :                 FILE *fpstdout = stdout, *fpstderr = stderr;
     483             :                 freopen_s(&fpstdout, "CONOUT$", "w", stdout);
     484             :                 freopen_s(&fpstderr, "CONOUT$", "w", stderr);
     485             :                 // Save the original state of the console window(in case AttachConsole worked).
     486             :                 CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
     487             :                 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo);
     488             :                 original_attributes = consoleInfo.wAttributes;
     489             :                 SetConsoleCP(CP_UTF8);
     490             :                 SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
     491             :             }
     492             :         } else {
     493             :             // Restore the original state of the console window in case we attached.
     494             :             SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), original_attributes);
     495             :             FreeConsole();
     496             :         }
     497             : #endif
     498         302 :     }
     499             : 
     500         302 :     void enableSysLog(bool en)
     501             :     {
     502         302 :         sysLog.enable(en);
     503         302 :         checkStatus();
     504         302 :     }
     505             : 
     506           0 :     void enableMonitorLog(bool en)
     507             :     {
     508           0 :         monitorLog.enable(en);
     509           0 :         checkStatus();
     510           0 :     }
     511             : 
     512      300860 :     bool isEnabled()
     513             :     {
     514      300860 :         return consoleLog.isEnable() || sysLog.isEnable() || monitorLog.isEnable() || fileLog.isEnable();
     515             :     }
     516             : 
     517             : private:
     518          38 :     LogDispatcher() = default;
     519             : 
     520         906 :     void checkStatus()
     521             :     {
     522         906 :         bool en = isEnabled();
     523         906 :         std::thread t;
     524             :         {
     525         906 :             std::lock_guard lk(mtx_);
     526         906 :             if (en && !running_) {
     527         302 :                 running_ = true;
     528         302 :                 thread_ = std::thread(&LogDispatcher::loop, this);
     529         604 :             } else if (!en && running_) {
     530           0 :                 running_ = false;
     531           0 :                 t = std::move(thread_);
     532             :             }
     533         906 :         }
     534         906 :         if (t.joinable()) {
     535           0 :             cv_.notify_all();
     536           0 :             t.join();
     537           0 :             std::lock_guard lk(mtx_);
     538           0 :             recycleQueue_.splice(recycleQueue_.end(), std::move(msgQueue_));
     539           0 :         }
     540         906 :     }
     541             : 
     542         302 :     void loop()
     543             :     {
     544         302 :         std::unique_lock lk(mtx_);
     545      251157 :         while (running_) {
     546      675333 :             cv_.wait(lk, [this] { return not msgQueue_.empty() or not running_; });
     547      250855 :             auto local = std::move(msgQueue_);
     548      250855 :             lk.unlock();
     549      550900 :             for (auto& msg : local) {
     550      300045 :                 if (sysLog.isEnable())
     551           0 :                     sysLog.consume(msg);
     552      300045 :                 if (monitorLog.isEnable())
     553           0 :                     monitorLog.consume(msg);
     554      300045 :                 if (consoleLog.isEnable())
     555      300045 :                     consoleLog.consume(msg);
     556      300045 :                 if (fileLog.isEnable())
     557           0 :                     fileLog.consume(msg);
     558             : 
     559      300045 :                 msg.payload_ = {};
     560      300045 :                 msg.header_ = {};
     561             :             }
     562      250855 :             lk.lock();
     563      250855 :             if (recycleQueue_.size() < 128)
     564      250849 :                 recycleQueue_.splice(recycleQueue_.end(), local);
     565      250855 :         }
     566         302 :     }
     567             : 
     568             :     std::mutex mtx_;
     569             :     std::condition_variable cv_;
     570             :     std::list<Logger::Msg> msgQueue_;
     571             :     std::list<Logger::Msg> recycleQueue_;
     572             :     bool running_ {false};
     573             :     std::thread thread_;
     574             : };
     575             : 
     576             : void
     577         302 : Logger::setConsoleLog(bool en)
     578             : {
     579         302 :     LogDispatcher::instance().enableConsoleLog(en);
     580         302 : }
     581             : 
     582             : void
     583         302 : Logger::setSysLog(bool en)
     584             : {
     585         302 :     LogDispatcher::instance().enableSysLog(en);
     586         302 : }
     587             : 
     588             : void
     589           0 : Logger::setMonitorLog(bool en)
     590             : {
     591           0 :     LogDispatcher::instance().enableMonitorLog(en);
     592           0 : }
     593             : 
     594             : void
     595           0 : Logger::setFileLog(const std::string& path)
     596             : {
     597           0 :     LogDispatcher::instance().enableFileLog(path);
     598           0 : }
     599             : 
     600             : LIBJAMI_PUBLIC void
     601       22336 : Logger::log(int level, const char* file, unsigned line, bool linefeed, const char* fmt, ...)
     602             : {
     603             :     va_list ap;
     604       22336 :     va_start(ap, fmt);
     605       22336 :     vlog(level, file, line, linefeed, fmt, ap);
     606       22336 :     va_end(ap);
     607       22336 : }
     608             : 
     609             : static std::atomic_bool debugEnabled_ {false};
     610             : 
     611             : void
     612         302 : Logger::setDebugMode(bool enable)
     613             : {
     614         302 :     debugEnabled_.store(enable, std::memory_order_relaxed);
     615         302 : }
     616             : 
     617             : bool
     618       77576 : Logger::debugEnabled()
     619             : {
     620       77576 :     return debugEnabled_.load(std::memory_order_relaxed);
     621             : }
     622             : 
     623             : void
     624       22335 : Logger::vlog(int level, const char* file, unsigned line, bool linefeed, const char* fmt, va_list ap)
     625             : {
     626       22335 :     if (level < LOG_WARNING and not debugEnabled_.load(std::memory_order_relaxed)) {
     627           1 :         return;
     628             :     }
     629             : 
     630       22335 :     if (!LogDispatcher::instance().isEnabled()) {
     631           1 :         return;
     632             :     }
     633             : 
     634             :     /* Timestamp is generated here. */
     635       22322 :     Msg msg(level, file, line, linefeed, {}, fmt, ap);
     636       22323 :     LogDispatcher::instance().log(std::move(msg));
     637       22340 : }
     638             : 
     639             : void
     640      277654 : Logger::write(int level, std::string_view file, unsigned line, bool linefeed, std::string_view tag, std::string&& message)
     641             : {
     642      277654 :     if (!LogDispatcher::instance().isEnabled()) {
     643           0 :         return;
     644             :     }
     645             :     /* Timestamp is generated here. */
     646      277559 :     Msg msg(level, file, line, linefeed, tag, std::move(message));
     647      277203 :     LogDispatcher::instance().log(std::move(msg));
     648      277766 : }
     649             : 
     650             : void
     651         302 : Logger::fini()
     652             : {
     653             :     // Force close on file and join thread
     654         302 :     LogDispatcher::instance().enableFileLog({});
     655         302 :     LogDispatcher::instance().stop();
     656             : 
     657             : #ifdef _WIN32
     658             :     Logger::setConsoleLog(false);
     659             : #endif /* _WIN32 */
     660         302 : }
     661             : 
     662             : } // namespace jami

Generated by: LCOV version 1.14