LCOV - code coverage report
Current view: top level - core/core/utils - SPLog.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 113 120 94.2 %
Date: 2024-05-12 00:16:13 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2016-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "SPLog.h"
      25             : 
      26             : #if MODULE_STAPPLER_THREADS
      27             : #include "SPThread.h"
      28             : #endif
      29             : 
      30             : #if ANDROID
      31             : #include <android/log.h>
      32             : #endif
      33             : 
      34             : namespace STAPPLER_VERSIONIZED stappler::log {
      35             : 
      36             : static const constexpr int MAX_LOG_FUNC = 16;
      37             : 
      38             : #if DEBUG
      39             : static std::bitset<6> s_logMask;
      40             : #else
      41             : static std::bitset<6> s_logMask = (1 | 2 | 4 | 8);
      42             : #endif
      43             : 
      44        3864 : static void DefaultLog2(LogType type, const StringView &tag, const StringView &text) {
      45        3864 :         std::stringstream stream;
      46             : 
      47             : #if !ANDROID
      48        3864 :         switch (type) {
      49        1275 :         case LogType::Verbose: stream << "Verbose: "; break;
      50        1400 :         case LogType::Debug: break;
      51          25 :         case LogType::Info: stream << "Info: "; break;
      52         180 :         case LogType::Warn: stream << "Warn: "; break;
      53         884 :         case LogType::Error: stream << "Error: "; break;
      54         100 :         case LogType::Fatal: stream << "Fatal: "; break;
      55             :         }
      56             : #endif
      57             : 
      58             : #if MODULE_STAPPLER_THREADS
      59        3864 :         if (auto local = thread::ThreadInfo::getThreadLocal()) {
      60         400 :                 if (!local->managed) {
      61           0 :                         stream << "[Thread:" << std::this_thread::get_id() << "] ";
      62         400 :                 } else if (local->threadId == thread::ThreadInfo::mainThreadId) {
      63           0 :                         stream << "[MainThread] ";
      64         400 :                 } else if (local->detouched) {
      65         400 :                         stream << "[" << local->name << "] ";
      66             :                 } else {
      67           0 :                         stream << "[" << local->name << ":" << local->threadId << ":" << local->workerId << "] ";
      68             :                 }
      69             :         } else {
      70        3464 :                 stream << "[Log] ";
      71             :         }
      72             : #endif
      73             : 
      74             : #if !ANDROID
      75        3864 :         stream << tag << ": ";
      76             : #endif
      77        3864 :         stream << text;
      78             : #ifndef __apple__
      79        3864 :         stream << "\n";
      80             : #endif
      81             : 
      82        3864 :         auto str = stream.str();
      83             : 
      84             : #if ANDROID
      85             :         switch (type) {
      86             :         case LogType::Verbose: __android_log_print(ANDROID_LOG_VERBOSE, tag.data(), "%s", str.c_str()); break;
      87             :         case LogType::Debug: __android_log_print(ANDROID_LOG_DEBUG, tag.data(), "%s", str.c_str()); break;
      88             :         case LogType::Info: __android_log_print(ANDROID_LOG_INFO, tag.data(), "%s", str.c_str()); break;
      89             :         case LogType::Warn: __android_log_print(ANDROID_LOG_WARN, tag.data(), "%s", str.c_str()); break;
      90             :         case LogType::Error: __android_log_print(ANDROID_LOG_ERROR, tag.data(), "%s", str.c_str()); break;
      91             :         case LogType::Fatal: __android_log_print(ANDROID_LOG_FATAL, tag.data(), "%s", str.c_str()); break;
      92             :         }
      93             : #else
      94        3864 :         fwrite(str.c_str(), str.length(), 1, stdout);
      95        3864 :         fflush(stdout);
      96             : #endif // platform switch
      97        3864 : }
      98             : 
      99        3864 : static void DefaultLog(LogType type, const StringView &tag, CustomLog::Type t, CustomLog::VA &va) {
     100        3864 :         if (t == CustomLog::Text) {
     101        3814 :                 DefaultLog2(type, tag, va.text);
     102             :         } else {
     103             :                 char stackBuf[1_KiB];
     104             :                 va_list tmpList;
     105          50 :                 va_copy(tmpList, va.format.args);
     106          50 :                 int size = vsnprintf(stackBuf, size_t(1_KiB - 1), va.format.format, tmpList);
     107          50 :                 va_end(tmpList);
     108          50 :                 if (size > int(1_KiB - 1)) {
     109          25 :                         char *buf = new char[size + 1];
     110          25 :                         size = vsnprintf(buf, size_t(size), va.format.format, va.format.args);
     111          25 :                         DefaultLog2(type, tag, StringView(buf, size));
     112          25 :                         delete [] buf;
     113          25 :                 } else if (size >= 0) {
     114          25 :                         DefaultLog2(type, tag, StringView(stackBuf, size));
     115             :                 } else {
     116           0 :                         DefaultLog2(type, tag, "Log error");
     117             :                 }
     118             :         }
     119        3864 : }
     120             : 
     121             : struct CustomLogManager : RefBase<memory::StandartInterface> {
     122             :         CustomLog::log_fn logFuncArr[MAX_LOG_FUNC] = { 0 };
     123             :         std::atomic<int> logFuncCount;
     124             :         std::mutex logFuncMutex;
     125             : 
     126        4014 :         static Rc<CustomLogManager> get() {
     127             :                 static std::mutex s_mutex;
     128        4014 :                 static Rc<CustomLogManager> ptr;
     129             : 
     130        4014 :                 std::unique_lock<std::mutex> lock(s_mutex);
     131        4014 :                 if (!ptr) {
     132          25 :                         ptr = Rc<CustomLogManager>::alloc();
     133             :                 }
     134        8028 :                 return ptr;
     135        4014 :         }
     136             : 
     137         100 :         void insert(CustomLog::log_fn fn) {
     138         100 :                 logFuncMutex.lock();
     139         200 :                 if (logFuncCount.load() < MAX_LOG_FUNC) {
     140         100 :                         logFuncArr[logFuncCount] = fn;
     141         100 :                         ++ logFuncCount;
     142             :                 }
     143         100 :                 logFuncMutex.unlock();
     144         100 :         }
     145             : 
     146         100 :         void remove(CustomLog::log_fn fn) {
     147         100 :                 logFuncMutex.lock();
     148         100 :                 int count = logFuncCount.load();
     149         150 :                 for (int i = 0; i < count; i++) {
     150         150 :                         if (logFuncArr[i] == fn) {
     151         100 :                                 if (i != count - 1) {
     152           0 :                                         memmove(&logFuncArr[i], &logFuncArr[i + 1], (count - i - 1) * sizeof(CustomLog::log_fn));
     153             :                                 }
     154         100 :                                 -- logFuncCount;
     155         100 :                                 break;
     156             :                         }
     157             :                 }
     158         100 :                 logFuncMutex.unlock();
     159         100 :         }
     160             : 
     161        3864 :         void log(LogType type, const StringView tag, CustomLog::Type t, CustomLog::VA &va) {
     162        3864 :                 if (s_logMask.test(toInt(type))) {
     163           0 :                         return;
     164             :                 }
     165             : 
     166        3864 :                 int count = logFuncCount.load();
     167        3864 :                 if (count == 0) {
     168        3764 :                         DefaultLog(type, tag, t, va);
     169             :                 } else {
     170         100 :                         bool success = true;
     171         100 :                         logFuncMutex.lock();
     172         100 :                         count = logFuncCount.load();
     173         250 :                         for (int i = 0; i < count; i++) {
     174         150 :                                 success = logFuncArr[i](type, tag, t, va);
     175         150 :                                 if (!success) {
     176           0 :                                         break;
     177             :                                 }
     178             :                         }
     179         100 :                         logFuncMutex.unlock();
     180         100 :                         if (success) {
     181         100 :                                 DefaultLog(type, tag, t, va);
     182             :                         }
     183             :                 }
     184             :         }
     185             : };
     186             : 
     187         100 : CustomLog::CustomLog(log_fn logfn) : fn(logfn) {
     188         100 :         manager = CustomLogManager::get();
     189         100 :         if (fn) {
     190         100 :                 static_cast<CustomLogManager *>(manager.get())->insert(fn);
     191             :         }
     192         100 : }
     193             : 
     194         125 : CustomLog::~CustomLog() {
     195         125 :         if (fn) {
     196          75 :                 static_cast<CustomLogManager *>(manager.get())->remove(fn);
     197             :         }
     198         125 : }
     199             : 
     200          25 : CustomLog::CustomLog(CustomLog && other) : fn(other.fn) {
     201          25 :         manager = CustomLogManager::get();
     202          25 :         other.fn = nullptr;
     203          25 : }
     204             : 
     205          25 : CustomLog& CustomLog::operator=(CustomLog && other) {
     206          25 :         manager = CustomLogManager::get();
     207          25 :         if (fn && fn != other.fn) {
     208          25 :                 static_cast<CustomLogManager *>(manager.get())->remove(fn);
     209             :         }
     210          25 :         fn = other.fn;
     211          25 :         other.fn = nullptr;
     212          25 :         return *this;
     213             : }
     214             : 
     215          25 : void setLogFilterMask(std::bitset<6> &&mask) {
     216          25 :         s_logMask = move(mask);
     217          25 : }
     218             : 
     219          25 : std::bitset<6> getlogFilterMask() {
     220          25 :         return s_logMask;
     221             : }
     222             : 
     223          50 : void format(LogType type, const StringView &tag, const char *fmt, ...) {
     224          50 :         CustomLog::VA va;
     225          50 :     va_start(va.format.args, fmt);
     226          50 :     va.format.format = fmt;
     227             : 
     228          50 :     auto m = CustomLogManager::get();
     229          50 :         m->log(type, tag, CustomLog::Format, va);
     230             : 
     231          50 :     va_end(va.format.args);
     232          50 : }
     233             : 
     234        3814 : void text(LogType type, const StringView &tag, const StringView &text) {
     235        3814 :         CustomLog::VA va;
     236        3814 :         va.text = text;
     237        3814 :     auto m = CustomLogManager::get();
     238        3814 :         m->log(type, tag, CustomLog::Text, va);
     239        3814 : }
     240             : 
     241             : }

Generated by: LCOV version 1.14