// License: Modified MIT (NON-AI) // See the LICENSE file in the root directory for license information. // Copyright 2025 Timothy Prepscius #pragma once #include #include #include #include #include "../algorithm/set_has.hpp" #include "../algorithm/is_in.hpp" namespace tjp::core::log::detail { TJP_CORE_HEADER_ONLY_INLINE long timeSinceEpochMillisec() { using namespace std::chrono; return duration_cast(system_clock::now().time_since_epoch()).count() % 1000000; } TJP_CORE_HEADER_ONLY_INLINE bool detectIfColorIsAvailable() { // is the stdout redirected, if so no color if (getenv("FORCE_COLOR")) return true; if (!isatty(fileno(stdout))) return false; const char* term = getenv("TERM"); if (!term) return false; // Some terminals support color std::string_view term_(term); if (term_ == "dumb") return false; return true; } using ThreadID = uint64_t; ThreadID getCurrentThreadID(); TJP_CORE_HEADER_ONLY_INLINE ThreadID getCurrentThreadID () { #ifdef WIN32 return GetCurrentThreadId(); #else return (ThreadID)pthread_self(); #endif } TJP_CORE_HEADER_ONLY_INLINE char * GetTimeStamp (char *data, int size, char marker=0) { #ifdef WIN32 __time64_t ltime; _time64( <ime ); char *timestr = _ctime64(<ime); // auto threadID = getCurrentThreadID(); #else std::time_t t = std::time(nullptr); char timestr[128]; std::strftime(timestr, size, "%Y%m%d_%H:%M:%S", std::localtime(&t)); // auto threadID = getCurrentThreadID(); #endif snprintf (data, size, "%s.%06ld", timestr, timeSinceEpochMillisec()); if (marker) for (auto *c=data; *c; ++c) if (*c == ':' || *c == '.') *c = marker; return data; } TJP_CORE_HEADER_ONLY_INLINE char * __GetLogStamp__ (char *data, bool colorize) { char timeStamp[128]; GetTimeStamp(timeStamp, std::size(timeStamp)); auto threadID = getCurrentThreadID(); auto dataSize = 256; if (colorize) { // all of the threadIDs are divisible by 128, so we use 127 auto color = (int)threadID % 127 + 1; #if defined(SYS_LINUX) || defined(SYS_ANDROID) snprintf (data, dataSize, "%s \033[38;5;%dm%lx\033[0m | ", timeStamp, color, threadID); #else snprintf (data, dataSize, "%s \033[38;5;%dm%llx\033[0m | ", timeStamp, color, threadID); #endif } else { #if defined(SYS_LINUX) || defined(SYS_ANDROID) snprintf (data, dataSize, "%s %lx | ", timeStamp, threadID); #else snprintf (data, dataSize, "%s %llx | ", timeStamp, threadID); #endif } return data; } TJP_CORE_HEADER_ONLY_INLINE std::string methodName(const char *prettyFunction_) { if (!prettyFunction_) return "[]"; std::string_view prettyFunction(prettyFunction_); auto end = prettyFunction.find('('); if (end == std::string_view::npos) end = 0; auto begin = end; auto stack = 0; decltype(begin) skipEnd = 0; decltype(begin) skipBegin = 0; for (begin = end; begin > 0; begin--) { if (prettyFunction[begin] == '>') { if (stack == 0) skipEnd = begin; stack++; } if (prettyFunction[begin] == '<') { stack--; if (stack == 0) skipBegin = begin; } if (prettyFunction[begin] == ' ' && stack == 0) break; } while (begin < end && is_in(prettyFunction[begin], ' ', '&', '*')) begin = begin+1; std::string part; if (skipBegin != skipEnd) part = std::string(prettyFunction.substr(begin,skipBegin-begin+1)) + std::string(prettyFunction.substr(skipEnd, end-skipEnd)); else part = prettyFunction.substr(begin,end-begin); if (part.size() > 30) return part.substr(part.size() - 30); return part; } } // namespace