245 lines
4.4 KiB
C++
Executable File
245 lines
4.4 KiB
C++
Executable File
// License: Modified MIT (NON-AI)
|
|
// See the LICENSE file in the root directory for license information.
|
|
// Copyright 2025 Timothy Prepscius
|
|
|
|
#if defined(TJP_CORE_HEADER_ONLY)
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "Detail.hpp"
|
|
|
|
#include "Util.inl"
|
|
#include "../io/memstream.hpp"
|
|
#include "../algorithm/set_has.hpp"
|
|
#include "../algorithm/unused.hpp"
|
|
#include "../string/as_string_view.hpp"
|
|
|
|
#include <sstream>
|
|
#include <fstream>
|
|
|
|
namespace tjp::core::log::detail {
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
bool operator==(const Story &lhs, const Story &rhs)
|
|
{
|
|
return
|
|
lhs.hash == rhs.hash &&
|
|
lhs.name == rhs.name;
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
bool operator<(const Story &lhs, const Story &rhs)
|
|
{
|
|
if (lhs.hash == rhs.hash)
|
|
return lhs.name < rhs.name;
|
|
|
|
return lhs.hash < rhs.hash;
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
Manager::Manager() :
|
|
file(this),
|
|
termSupportsColor(detectIfColorIsAvailable())
|
|
{
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
Manager &getManager()
|
|
{
|
|
static Manager manager;
|
|
return manager;
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
void Stories::clear()
|
|
{
|
|
all = false;
|
|
names.clear();
|
|
activated.clear();
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
void Stories::activate(const Story &s)
|
|
{
|
|
if (s.name == "*")
|
|
{
|
|
all = true;
|
|
return;
|
|
}
|
|
|
|
if (!set_has(activated, s))
|
|
{
|
|
names.push_back(String(s.name));
|
|
|
|
Story s_ = s;
|
|
s_.name = names.back();
|
|
activated.insert (s_);
|
|
}
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
bool Stories::isActivated (const Story &s)
|
|
{
|
|
return all || set_has(activated, s);
|
|
}
|
|
|
|
// ---------------
|
|
|
|
struct File::I {
|
|
std::ofstream file;
|
|
} ;
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
File::File(Manager *manager_) :
|
|
manager(manager_)
|
|
{
|
|
i = new I();
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
File::~File()
|
|
{
|
|
delete i;
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
Settings &File::getSettings()
|
|
{
|
|
return manager->settings;
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
void File::start()
|
|
{
|
|
if (i->file.is_open())
|
|
i->file.close();
|
|
|
|
auto &settings = getSettings();
|
|
|
|
i->file.open(
|
|
settings.LogFileName,
|
|
settings.AppendToLogFile ?
|
|
std::ios::app :
|
|
std::ios::out
|
|
);
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
void File::write(const StringView &s)
|
|
{
|
|
if (!i->file)
|
|
return;
|
|
|
|
sizeWritten += s.size();
|
|
i->file << s;
|
|
i->file.flush();
|
|
|
|
checkRotate();
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
void File::checkRotate()
|
|
{
|
|
auto &settings = getSettings();
|
|
|
|
if (settings.RotateSize != 0 && sizeWritten > settings.RotateSize)
|
|
rotate();
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
void File::rotate()
|
|
{
|
|
char data[256];
|
|
GetTimeStamp(data, std::size(data), '_');
|
|
rotateTo(getSettings().LogFileName + "." + data);
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
void File::rotateTo(const std::string_view &name_)
|
|
{
|
|
i->file.close();
|
|
|
|
auto name = std::string(name_);
|
|
remove(name.c_str());
|
|
rename(getSettings().LogFileName.c_str(), name.c_str());
|
|
|
|
sizeWritten = 0;
|
|
start();
|
|
}
|
|
|
|
// -------
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
void Manager::writeToConsole (const StringView &s)
|
|
{
|
|
auto lock = std::lock_guard<Mutex>(mutex);
|
|
|
|
char data[256];
|
|
core::io::omemstream_ out;
|
|
out << "XD " << __GetLogStamp__(data, termSupportsColor) << s;
|
|
|
|
auto externalConsolePrint = external.console;
|
|
if (externalConsolePrint)
|
|
return externalConsolePrint(core::as_string_view(out.data));
|
|
|
|
fwrite((void *)out.data.data(), 1, out.data.size(), stdout);
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
void Manager::writeToDebugger (const StringView &s)
|
|
{
|
|
auto lock = std::lock_guard<Mutex>(mutex);
|
|
|
|
char data[256];
|
|
unused(data);
|
|
|
|
auto externalDebuggerPrint = external.debugger;
|
|
if (externalDebuggerPrint)
|
|
{
|
|
#ifdef SYS_ANDROID
|
|
core::io::omemstream_ out_;
|
|
out_ << __GetLogStamp__(data, false) << s;
|
|
auto out = as_string_view(out_.data);
|
|
#else
|
|
auto &out = s;
|
|
#endif
|
|
externalDebuggerPrint(out);
|
|
}
|
|
|
|
#ifdef WIN32
|
|
OutputDebugString (__GetLogStamp__(data, false));
|
|
OutputDebugString (s.c_str());
|
|
#endif
|
|
}
|
|
|
|
TJP_CORE_HEADER_ONLY_INLINE
|
|
void Manager::writeToLog (const StringView &s)
|
|
{
|
|
auto externalLogPrint = external.log;
|
|
bool willWrite = externalLogPrint || settings.LogToFileActivated;
|
|
if (willWrite)
|
|
{
|
|
char data[256];
|
|
core::io::omemstream_ out;
|
|
out << __GetLogStamp__(data, false) << s;
|
|
auto outs = as_string_view(out.data);
|
|
|
|
if (externalLogPrint)
|
|
externalLogPrint(outs);
|
|
|
|
if (settings.LogToFileActivated)
|
|
file.write(outs);
|
|
|
|
#ifdef USE_OSX_LOG
|
|
// Define a custom log category
|
|
static os_log_t os_log_ = os_log_create("com.timprepscius.crown", "std");
|
|
|
|
// Log a message with default log level
|
|
os_log(os_log_, "%s", s.c_str());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|