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 : }