LCOV - code coverage report
Current view: top level - src/core/log - logger.cpp (source / functions) Hit Total Coverage
Test: libopenmodelviewer coverage Lines: 96 99 97.0 %
Date: 2025-07-03 20:26:48 Functions: 18 19 94.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //
       2             : // Copyright 2024 OpenModelViewer Authors
       3             : // 
       4             : // Licensed under the Apache License, Version 2.0 (the "License");
       5             : // you may not use this file except in compliance with the License.
       6             : // You may obtain a copy of the License at
       7             : // 
       8             : //     http://www.apache.org/licenses/LICENSE-2.0
       9             : // 
      10             : // Unless required by applicable law or agreed to in writing, software
      11             : // distributed under the License is distributed on an "AS IS" BASIS,
      12             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             : // See the License for the specific language governing permissions and
      14             : // limitations under the License.
      15             : //
      16             : 
      17             : #include "openmodelviewer/core/log/logger.hpp"
      18             : 
      19             : #include <algorithm>
      20             : 
      21             : namespace openmodelviewer::core::log
      22             : {
      23          27 :         Logger::Logger(LogLevel level) :
      24          27 :                 m_minLogLevel(level)
      25             :         {
      26          27 :                 m_working = false;
      27          27 :         }
      28             : 
      29          10 :         Logger::Logger(std::initializer_list<std::shared_ptr<ILogSink>> sinks, LogLevel level) :
      30          10 :                 m_minLogLevel(level)
      31             :         {
      32          10 :                 m_working = false;
      33             : 
      34          20 :                 for (auto& sink : sinks)
      35             :                 {
      36          10 :                         this->addSink(sink);
      37             :                 }
      38          10 :         }
      39             : 
      40          37 :         Logger::~Logger()
      41             :         {
      42          37 :                 this->stop();
      43          37 :         }
      44             : 
      45          24 :         bool Logger::start()
      46             :         {
      47          24 :                 if (m_working.load())
      48             :                 {
      49           0 :                         return false;
      50             :                 }
      51             : 
      52          24 :                 m_working = true;
      53             : 
      54          48 :                 m_worker = std::thread(
      55          24 :                         [this]()
      56             :                         {
      57          24 :                                 this->process();
      58          24 :                         }
      59          24 :                 );
      60             : 
      61          24 :                 return true;
      62             :         }
      63             : 
      64          59 :         void Logger::stop()
      65             :         {
      66          59 :                 if (!m_working.exchange(false))
      67             :                 {
      68          35 :                         return;
      69             :                 }
      70             : 
      71             :                 {
      72          24 :                         std::lock_guard<std::mutex> lock(m_logMutex);
      73          24 :                         m_workCondition.notify_all();
      74          24 :                 }
      75             : 
      76          24 :                 if(m_worker.joinable())
      77             :                 {
      78          24 :                         m_worker.join();
      79             :                 }
      80             :         }
      81             : 
      82      236344 :         bool Logger::isRunning() const noexcept
      83             :         {
      84      236344 :                 return m_working.load();
      85             :         }
      86             : 
      87           9 :         void Logger::flush()
      88             :         {
      89           9 :                 std::unique_lock<std::mutex> lock(m_logMutex);
      90             : 
      91           9 :                 std::vector<std::unique_ptr<LogEntry>> buffer;
      92           9 :                 dumpQueue(buffer);
      93             : 
      94           9 :                 lock.unlock();
      95             : 
      96           9 :                 dispatch(buffer);
      97           9 :         }
      98             : 
      99          12 :         void Logger::addSink(std::shared_ptr<ILogSink> sink)
     100             :         {
     101          12 :                 if (!sink)
     102             :                 {
     103           0 :                         return;
     104             :                 }
     105             : 
     106          12 :                 std::lock_guard<std::mutex> lock(m_sinkMutex);
     107          12 :                 m_sinks.push_back(sink);
     108          12 :         }
     109             : 
     110           1 :         void Logger::removeSink(const std::shared_ptr<ILogSink>& sink)
     111             :         {
     112           1 :                 if (!sink)
     113             :                 {
     114           0 :                         return;
     115             :                 }
     116             : 
     117           1 :                 std::lock_guard<std::mutex> lock(m_sinkMutex);
     118           1 :                 m_sinks.erase(std::remove(m_sinks.begin(), m_sinks.end(), sink), m_sinks.end());
     119           1 :         }
     120             : 
     121           1 :         void Logger::setMinLevel(LogLevel level) noexcept
     122             :         {
     123           1 :                 m_minLogLevel = level;
     124           1 :         }
     125             : 
     126           2 :         LogLevel Logger::getMinLevel() const noexcept
     127             :         {
     128           2 :                 return m_minLogLevel;
     129             :         }
     130             : 
     131        1414 :         void Logger::process()
     132             :         {
     133             :                 while (true)
     134             :                 {
     135        1414 :                         std::vector<std::unique_ptr<LogEntry>> buffer;
     136             : 
     137             :                         {
     138        1414 :                                 std::unique_lock<std::mutex> lock(m_logMutex);
     139        1414 :                                 m_workCondition.wait(lock, [&]
     140             :                                 {
     141        1487 :                                         return !m_logQueue.empty() || !m_working.load();
     142             :                                 });
     143             : 
     144        1414 :                                 if (!m_working.load() && m_logQueue.empty())
     145             :                                 {
     146          24 :                                         break;
     147             :                                 }
     148             : 
     149        1390 :                                 dumpQueue(buffer);
     150        1414 :                         }
     151             : 
     152        1390 :                         dispatch(buffer);
     153        2804 :                 }
     154          24 :         }
     155             : 
     156      236042 :         void Logger::logv(LogLevel level, std::string message)
     157             :         {
     158      236042 :                 if (level < m_minLogLevel || !this->isRunning())
     159             :                 {
     160           2 :                         return;
     161             :                 }
     162             : 
     163      236555 :                 auto entry = std::make_unique<LogEntry>(level, std::move(message));
     164             : 
     165      232370 :                 std::lock_guard<std::mutex> lock(m_logMutex);
     166      240014 :                 m_logQueue.push_back(std::move(entry));
     167             : 
     168      240014 :                 m_workCondition.notify_one();
     169      240014 :         }
     170             : 
     171           2 :         void Logger::logvi(LogLevel level, std::string message)
     172             :         {
     173           2 :                 if (level < m_minLogLevel || !this->isRunning())
     174             :                 {
     175           1 :                         return;
     176             :                 }
     177             : 
     178           1 :                 auto entry = std::make_unique<LogEntry>(level, std::move(message));
     179             :                 
     180           1 :                 std::vector<std::unique_ptr<LogEntry>> buffer;
     181           1 :                 buffer.push_back(std::move(entry));
     182             : 
     183           1 :                 this->dispatch(buffer);
     184           1 :         }
     185             : 
     186        1400 :         void Logger::dispatch(const std::vector<std::unique_ptr<LogEntry>>& buffer) const
     187             :         {
     188        1400 :                 std::lock_guard<std::mutex> lock(m_sinkMutex);
     189             : 
     190      241415 :                 for (auto& entry : buffer)
     191             :                 {
     192      480028 :                         for (auto& sink : m_sinks)
     193             :                         {
     194      240013 :                                 if (sink != nullptr)
     195             :                                 {
     196      240013 :                                         sink->log(*entry);
     197             :                                 }
     198             :                         }
     199             :                 }
     200        1400 :         }
     201             : 
     202        1399 :         void Logger::dumpQueue(std::vector<std::unique_ptr<LogEntry>>& buffer)
     203             :         {
     204        1399 :                 buffer.clear();
     205        1399 :                 buffer.reserve(m_logQueue.size());
     206             : 
     207      241413 :                 for (auto& uniqueEntry : m_logQueue)
     208             :                 {
     209      240014 :                         buffer.push_back(std::move(uniqueEntry));
     210             :                 }
     211        1399 :                 m_logQueue.clear();
     212        1399 :         }
     213             : }

Generated by: LCOV version 1.14