LCOV - code coverage report
Current view: top level - Source - logging.cpp (source / functions) Coverage Total Hit
Test: coverage Lines: 56.0 % 50 28
Test Date: 2026-03-02 16:42:41 Functions: 83.3 % 6 5

            Line data    Source code
       1              : #include "logging.hpp"
       2              : 
       3              : #include "distributed.h"
       4              : #include "dynamicConfig.hpp"
       5              : 
       6              : #ifdef __ANDROID__
       7              : std::string backtrace([[maybe_unused]] int skip) {
       8              :    ////@todo backtrace for android
       9              :    return "";
      10              : }
      11              : 
      12              : #elif __linux__
      13              : #include <cxxabi.h> // for __cxa_demangle
      14              : #include <dlfcn.h>  // for dladdr
      15              : #include <execinfo.h>
      16              : #include <signal.h>
      17              : #include <stdio.h>
      18              : #include <stdlib.h>
      19              : #include <unistd.h>
      20              : 
      21            0 : std::string backtrace([[maybe_unused]] int skip) {
      22              :    void *    callstack[128];
      23              :    const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
      24              :    char      buf[1024];
      25            0 :    int       nFrames = backtrace(callstack, nMaxFrames);
      26            0 :    char **   symbols = backtrace_symbols(callstack, nFrames);
      27              : 
      28            0 :    std::ostringstream trace_buf;
      29            0 :    for (int i = skip; i < nFrames; i++) {
      30              :       Dl_info info;
      31            0 :       if (dladdr(callstack[i], &info)) {
      32              :          char *demangled = nullptr;
      33              :          int   status;
      34            0 :          demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status);
      35            0 :          std::snprintf(buf, sizeof(buf), "%-3d %*p %s + %zd\n", i, static_cast<int>(2 + sizeof(void *) * 2), callstack[i],
      36            0 :                        status == 0 ? demangled : info.dli_sname, (char *)callstack[i] - (char *)info.dli_saddr);
      37            0 :          free(demangled);
      38              :       }
      39              :       else {
      40            0 :          std::snprintf(buf, sizeof(buf), "%-3d %*p\n", i, static_cast<int>(2 + sizeof(void *) * 2), callstack[i]);
      41              :       }
      42            0 :       trace_buf << buf;
      43            0 :       std::snprintf(buf, sizeof(buf), "%s\n", symbols[i]);
      44            0 :       trace_buf << buf;
      45              :    }
      46            0 :    free(symbols);
      47            0 :    if (nFrames == nMaxFrames) trace_buf << "[truncated]\n";
      48            0 :    return trace_buf.str();
      49            0 : }
      50              : 
      51              : #elif defined __MINGW32__
      52              : std::string backtrace([[maybe_unused]] int skip) {
      53              :    ////@todo backtrace for mingw
      54              :    return "";
      55              : }
      56              : 
      57              : #elif defined _WIN32
      58              : //#include "dbg_win.h"
      59              : 
      60              : std::string backtrace([[maybe_unused]] int skip) {
      61              : /*
      62              :    std::stringstream               buff;
      63              :    std::vector<windbg::StackFrame> stack = windbg::stack_trace();
      64              :    buff << "Callstack: \n";
      65              :    for (unsigned int i = 0; i < stack.size(); ++i) {
      66              :       buff << "0x" << std::hex << stack[i].address << ": " << stack[i].name << "(" << std::dec << stack[i].line << ") in " << stack[i].module << "\n";
      67              :    }
      68              :    return buff.str();
      69              : */
      70              :    return "";
      71              : }
      72              : 
      73              : #elif defined __CYGWIN__
      74              : std::string backtrace([[maybe_unused]] int skip) {
      75              :    ///@todo backtrace for cygwin
      76              :    return "";
      77              : }
      78              : 
      79              : #endif
      80              : 
      81              : namespace Logging {
      82              : 
      83              : std::mutex                     LogIt::_mutex;
      84              : std::unique_ptr<std::ofstream> LogIt::_of;
      85              : 
      86              : COMType ct = CT_uci;
      87              : 
      88              : #if defined(__MINGW32__) || defined(__MINGW64__)
      89              : #   define localtime_r(T,Tm) (localtime_s(Tm,T) ? NULL : Tm)
      90              : #endif
      91              : 
      92        43292 : [[nodiscard]] std::string showDate() {
      93        43292 :    std::stringstream str;
      94              : #ifdef _MSC_VER
      95              :    const auto n = std::chrono::system_clock::now();
      96              :    str << n;
      97              : #else // previous code is only valid on very recent g++ and clang++ currently
      98        43292 :    const auto msecEpoch = std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now().time_since_epoch());
      99              :    char       buffer[64];
     100        43292 :    const auto tt = Clock::to_time_t(Clock::time_point(msecEpoch));
     101              :    struct tm  localTime;
     102        43292 :    std::strftime(buffer, 63, "%Y-%m-%d %H:%M:%S", localtime_r(&tt, &localTime));
     103        43292 :    str << buffer << "-" << std::setw(3) << std::setfill('0') << msecEpoch.count() % 1000;
     104              : #endif
     105        43292 :    return str.str();
     106        43292 : }
     107              : 
     108        43942 : LogIt::~LogIt() {
     109              :    std::lock_guard lock(_mutex);
     110        43942 :    if (_level != logGUI) { // those are "comments" and are prefixed with _protocolComment[ct] ("info string" for UCI)
     111        43292 :       const std::string rankStr = Distributed::moreThanOneProcess() ? (std::string("(") + std::to_string(Distributed::rank) + ") ") : "";
     112       129876 :       const std::string str = std::string(_protocolComment[ct]) + std::string(_levelNames[_level]) + showDate() + ": " + rankStr + _buffer.str();
     113        43292 :       if ( _level >= DynamicConfig::minOutputLevel ) {
     114              : #ifdef WITH_FMTLIB
     115              :          if ( ct == CT_pretty ){
     116              :             std::cout << fmt::format(_levelStyles[_level], str) << std::endl;
     117              :          }
     118              :          else
     119              : #endif
     120              :          std::cout << str << std::endl;
     121              :       }
     122              :       // debug file output is *not* depending on DynamicConfig::minOutputLevel
     123        43292 :       if (_of) (*_of) << str << std::endl;
     124              :    }
     125              :    else { // those are direct GUI outputs (like bestmove, feature, option, ...)
     126          650 :       if ( _level >= DynamicConfig::minOutputLevel ) {
     127          560 :          std::cout << _buffer.str() << std::flush << std::endl;
     128              :       }
     129              :       // debug file output is *not* depending on DynamicConfig::minOutputLevel
     130          650 :       if (_of) (*_of) << _buffer.str() << std::flush << std::endl;
     131              :    }
     132              :    if (_level >= logError) {
     133              : #ifdef DEBUG_BACKTRACE
     134              :       std::cout << backtrace() << std::endl;
     135              : #endif
     136              :    }
     137        43942 :    if (_level >= logFatal) {
     138              :       Distributed::finalize();
     139            0 :       exit(1);
     140              :    }
     141        43942 : }
     142              : 
     143           22 : void hellooo() {
     144              :    if (Distributed::isMainProcess()) {
     145              : #ifdef WITH_NNUE
     146           22 :       std::cout << Logging::_protocolComment[Logging::ct] << "This is Minic version " << MinicVersion << " (NNUE available)" << std::endl;
     147              : #else
     148              :       std::cout << Logging::_protocolComment[Logging::ct] << "This is Minic version " << MinicVersion << std::endl;
     149              : #endif
     150              :       if (Distributed::moreThanOneProcess()) {
     151              :          std::cout << Logging::_protocolComment[Logging::ct] << "MPI version running on " << Distributed::worldSize << " process" << std::endl;
     152              :       }
     153              :    }
     154           22 : }
     155              : 
     156           22 : void init() {
     157           22 :    if (DynamicConfig::debugMode) {
     158            0 :       if (DynamicConfig::debugFile.empty()) DynamicConfig::debugFile = "minic.debug";
     159              :       LogIt::_of = std::unique_ptr<std::ofstream>(
     160            0 :           new std::ofstream(DynamicConfig::debugFile + "_" + std::to_string(Distributed::rank) + "_" +
     161            0 :                             std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now().time_since_epoch()).count())));
     162              :    }
     163           22 : }
     164              : 
     165           21 : void finalize() {
     166           21 :    if (LogIt::_of) { LogIt::_of.reset(); }
     167           21 : }
     168              : 
     169              : } // namespace Logging
        

Generated by: LCOV version 2.0-1