TeaSpeak-Client/native/serverconnection/src/logger.cpp

125 lines
3.6 KiB
C++

#include <iostream>
#include <NanGet.h>
#include "logger.h"
/* Basic */
void(*logger::_force_log)(logger::category::value, logger::level::level_enum /* lvl */, const std::string_view& /* message */);
void force_log_raw(logger::category::value, spdlog::level::level_enum level, const std::string_view &message);
void force_log_node(logger::category::value, spdlog::level::level_enum, const std::string_view &);
#ifdef NODEJS_API
#include <include/NanEventCallback.h>
#include <include/NanStrings.h>
/* NODE JS */
struct LogMessage {
uint8_t level;
uint8_t category;
std::string message;
LogMessage* next_message;
};
std::mutex log_messages_lock;
LogMessage* log_messages_head = nullptr;
LogMessage** log_messages_tail = &log_messages_head;
Nan::callback_t<> log_messages_callback;
struct StdExternalStringResourceBase : public v8::String::ExternalOneByteStringResource {
public:
explicit StdExternalStringResourceBase(const std::string& message) : message(message) {}
const char *data() const override {
return this->message.data();
}
size_t length() const override {
return this->message.length();
}
private:
std::string message;
};
inline v8::MaybeLocal<v8::Function> get_logger_method() {
v8::Local<v8::Object> global_context = Nan::GetCurrentContext()->Global();
auto logger = Nan::GetLocal<v8::Object>(global_context, "logger");
if(!logger.IsEmpty()) {
auto log_function = Nan::Get<v8::Function>(logger, "log");
if(!log_function.IsEmpty()) return log_function;
}
auto console = Nan::GetLocal<v8::Object>(global_context, "console");
assert(!console.IsEmpty());
return Nan::Get<v8::Function>(console, "log");
}
void logger::initialize_node() {
log_messages_callback = Nan::async_callback([]{
Nan::HandleScope scope;
auto isolate = Nan::GetCurrentContext()->GetIsolate();
auto logger_method = get_logger_method();
v8::Local<v8::Value> arguments[3];
while(true) {
std::unique_lock messages_lock(log_messages_lock);
if(!log_messages_head)
break;
auto entry = log_messages_head;
log_messages_head = entry->next_message;
if(!log_messages_head)
log_messages_tail = &log_messages_head;
messages_lock.unlock();
if(!logger_method.IsEmpty()) {
auto logger = logger_method.ToLocalChecked();
arguments[0] = Nan::New<v8::Number>(entry->category);
arguments[1] = Nan::New<v8::Number>(entry->level);
arguments[2] = v8::String::NewExternalOneByte(isolate, new StdExternalStringResourceBase(entry->message)).ToLocalChecked();
logger.As<v8::Function>()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 3, arguments);
} else {
std::cout << "Failed to log message! Invalid method!" << std::endl;
}
delete entry;
}
});
logger::_force_log = force_log_node;
}
void force_log_node(logger::category::value category, spdlog::level::level_enum level, const std::string_view &message) {
auto entry = new LogMessage{};
entry->level = level;
entry->category = category;
entry->message = std::string(message.data(), message.length());
entry->next_message = nullptr;
{
std::lock_guard lock(log_messages_lock);
*log_messages_tail = entry;
log_messages_tail = &(entry->next_message);
}
log_messages_callback();
}
#endif
void logger::initialize_raw() {
logger::_force_log = force_log_raw;
}
void force_log_raw(logger::category::value category, spdlog::level::level_enum level, const std::string_view &message) {
std::cout << "[" << level << "][" << category << "] " << message << std::endl;
}
void logger::err_handler(const std::string &message) {
std::cout << "[ERROR] " << message << std::endl;
}