*: port to spdlog

Later commits will work on creating loggers for each component.
This commit is contained in:
Lily Tsuru 2024-03-10 06:34:42 -04:00
parent 3a6f7e7d7d
commit 919490a8c0
21 changed files with 58 additions and 442 deletions

3
.gitmodules vendored
View File

@ -196,3 +196,6 @@
[submodule "third_party/boost/mysql"]
path = third_party/boost/mysql
url = https://github.com/boostorg/mysql.git
[submodule "third_party/spdlog"]
path = third_party/spdlog
url = https://github.com/gabime/spdlog

View File

@ -2,10 +2,6 @@ add_library(base_base
assert.cpp
backoff.cpp
html_escape.cpp
# logging library
logger.cpp
stdout_sink.cpp
)
lobbyserver_target(base_base)
@ -13,6 +9,7 @@ lobbyserver_target(base_base)
target_link_libraries(base_base PUBLIC
# techinically not needed anymore but /shrug
base::impl
spdlog::spdlog
)
add_library(base::base ALIAS base_base)

View File

@ -1,13 +1,11 @@
#include <cstdio>
#include <cstdlib>
#include <base/logger.hpp>
#include <spdlog/spdlog.h>
namespace base {
static Logger gAssertLogger{MakeChannelId(MessageSource::Base, MessageComponentSource::Base_Assertions)};
[[noreturn]] void ExitMsg(const char* message) {
gAssertLogger.Fatal("{}", message);
spdlog::error("{}", message);
std::exit(0xAF);
}

View File

@ -1,172 +0,0 @@
#include <base/assert.hpp>
#include <base/logger.hpp>
#include <base/types.hpp>
#include <condition_variable>
#include <cstddef>
#include <deque>
#include <iostream>
#include <mutex>
#include <thread>
namespace base {
namespace logger_detail {
static constexpr std::string_view SeverityToString(MessageSeverity sev) {
// This must match order of logger_detail::MessageSeverity.
const char* MessageSeverityStringTable[] = { "Debug", "Info", "Warn", "Error", "Fatal" };
return MessageSeverityStringTable[static_cast<std::size_t>(sev)];
}
constexpr static auto ChannelToString(ChannelId channelId) -> std::string_view {
MessageSource src;
MessageComponentSource comp;
ChannelIdToComponents(channelId, src, comp);
switch(src) {
case MessageSource::Main: {
switch(comp) {
case MessageComponentSource::Main_Global: return "Main::Global";
default: BASE_CHECK(false, "Invalid component source");
}
};
case MessageSource::Base: {
switch(comp) {
case MessageComponentSource::Base_Assertions: return "Base::Assert";
default: BASE_CHECK(false, "Invalid component source");
}
};
case MessageSource::Http: {
switch(comp) {
case MessageComponentSource::Http_Server: return "HTTP::Server";
case MessageComponentSource::Http_WebSocketClient: return "HTTP::WebSocketClient";
default: BASE_CHECK(false, "Invalid component source");
}
};
case MessageSource::Server: {
switch(comp) {
case MessageComponentSource::Server_Server: return "LobbyServer2::Server";
default: BASE_CHECK(false, "Invalid component source");
}
};
default: BASE_CHECK(false, "Invalid channel source {:04x}", static_cast<u16>(src));
}
}
struct LoggerThreadData {
// Logger thread stuff
std::thread loggerThread;
std::mutex logQueueMutex;
std::condition_variable logQueueCv;
std::deque<MessageData> logQueue;
bool logThreadShutdown = false;
// N.B: This is stored/cached here just because it really does
// *NOT* need to be in a hot path.
const std::chrono::time_zone* timeZone = std::chrono::current_zone();
bool ShouldUnblock() {
// Always unblock if the logger thread needs to be shut down.
if(logThreadShutdown)
return true;
return !logQueue.empty();
}
void PushMessage(MessageData&& md) {
{
std::unique_lock<std::mutex> lk(logQueueMutex);
logQueue.emplace_back(std::move(md));
}
logQueueCv.notify_one();
}
};
Unique<LoggerThreadData> threadData;
void LoggerGlobalState::LoggerThread() {
auto& self = The();
// Fancy thread names.
pthread_setname_np(pthread_self(), "LoggerThread");
while(true) {
std::unique_lock<std::mutex> lk(threadData->logQueueMutex);
if(threadData->logQueue.empty()) {
// Await for messages.
threadData->logQueueCv.wait(lk, []() { return threadData->ShouldUnblock(); });
}
// Flush the logger queue until there are no more messages.
while(!threadData->logQueue.empty()) {
self.OutputMessage(threadData->logQueue.back());
threadData->logQueue.pop_back();
}
// Shutdown if requested.
if(threadData->logThreadShutdown)
break;
}
}
LoggerGlobalState& LoggerGlobalState::The() {
static LoggerGlobalState storage;
return storage;
}
LoggerGlobalState::LoggerGlobalState() {
// Spawn the logger thread
threadData = std::make_unique<LoggerThreadData>();
threadData->loggerThread = std::thread(&LoggerGlobalState::LoggerThread);
}
LoggerGlobalState::~LoggerGlobalState() {
// Shut down the logger thread
threadData->logThreadShutdown = true;
threadData->logQueueCv.notify_all();
threadData->loggerThread.join();
}
void LoggerGlobalState::AttachSink(Sink& sink) {
sinks.push_back(&sink);
}
void LoggerGlobalState::OutputMessage(const MessageData& data) {
// give up early if no sinks are attached
if(sinks.empty())
return;
if(data.severity < logLevel)
return;
auto formattedLoggerMessage =
std::format("[{:%F %H:%M:%S}|{}|{}] {}", std::chrono::floor<std::chrono::milliseconds>(threadData->timeZone->to_local(data.time)),
SeverityToString(data.severity), ChannelToString(data.channelId), data.message);
for(auto sink : sinks)
sink->OutputMessage(formattedLoggerMessage);
}
} // namespace logger_detail
Logger& Logger::Global() {
static Logger globalLogger;
return globalLogger;
}
void Logger::VOut(MessageSeverity severity, std::string_view format, std::format_args args) {
logger_detail::MessageData data {
.time = std::chrono::system_clock::now(), .severity = severity, .channelId = channelId, .message = std::vformat(format, args)
};
// Push data into logger thread.
logger_detail::threadData->PushMessage(std::move(data));
}
} // namespace base

View File

@ -1,212 +0,0 @@
//! Logging utilities for the Support Library
//! Using Standard C++ <format>
#pragma once
#include <chrono>
#include <cstdint>
#include <format>
#include <base/types.hpp>
#include <vector>
namespace base {
namespace logger_detail {
enum class MessageSeverity { Debug, Info, Warning, Error, Fatal };
/// A message source. In our tree, this is essentially defined as
/// each library the server's made up of.
enum class MessageSource : u16 { Main = 0x1000, Base, Http, Server };
/// A component source. This basically defines "what" part of a source
/// is creating the message. For instance, the HTTP library has multiple
/// components which can each log messages.
enum class MessageComponentSource : u16 {
// The "default" global logger channel
Main_Global = 0x1000,
Base_Assertions = 0x10,
Http_Server = 0x50,
Http_Router,
Http_WebSocketClient,
Server_Server = 0x60,
};
/// A channel ID. `enum class`es are used to avoid confusion with a normal u32,
/// and to also add addional interface type safety.
///
/// A channel ID looks something like:
/// ssssssss ssssssss cccccccc cccccccc
///
/// Where:
/// s: message source
/// c: message component source
enum class ChannelId : u32 {};
/// Create a channel ID from a source and component source.
constexpr static ChannelId MakeChannelId(MessageSource source, MessageComponentSource component) {
auto srcbits = std::bit_cast<u16>(source);
auto cmpbits = std::bit_cast<u16>(component);
return static_cast<ChannelId>((static_cast<u32>(srcbits) << 16 | cmpbits));
}
/// Splits a channel ID into its individual components.
constexpr static void ChannelIdToComponents(ChannelId id, MessageSource& src, MessageComponentSource& component) {
src = static_cast<MessageSource>((static_cast<u32>(id) & 0xffff0000) >> 16);
component = static_cast<MessageComponentSource>(static_cast<u32>(id) & 0x0000ffff);
}
/// The default global channel ID.
constexpr static auto ChannelGlobal = MakeChannelId(MessageSource::Main, MessageComponentSource::Main_Global);
/// Message data. This is only used by logger sinks.
struct MessageData {
std::chrono::system_clock::time_point time;
MessageSeverity severity;
ChannelId channelId; // the channel ID.
std::string message; // DO NOT SET THIS, IT WILL BE OVERWRITTEN AND I WILL BE VERY SAD -lily
};
/// A logger sink. Outputs messages to some device (a TTY), a file,
/// what have you. Basically a interface for the logger to spit stuff out.
///
/// # Notes
/// Sinks do not run on the main application thread. Instead, they run on a
/// single Support Library internal thread which the only purpose of is to
/// stream logger messages and output them, from a internally managed queue.
///
/// This is techinically a implementation detail, but for implementers of logger
/// sinks it's probably a good idea for them to know just in case.
///
/// Do note that you probably don't have to actually do any thread-safety magic
/// in your sink implementation, since it's only a single thread/etc...
struct Sink {
virtual void OutputMessage(std::string_view message) = 0;
};
/// Shared global state all loggers use.
struct LoggerGlobalState {
static LoggerGlobalState& The();
void AttachSink(Sink& sink);
void OutputMessage(const MessageData& data);
/// Get the current log level.
MessageSeverity GetLogLevel() const { return logLevel; }
/// Set the current log level.
void SetLogLevel(MessageSeverity newLogLevel) { logLevel = newLogLevel; }
private:
LoggerGlobalState();
~LoggerGlobalState();
std::vector<Sink*> sinks;
MessageSeverity logLevel { MessageSeverity::Info };
static void LoggerThread();
};
inline auto& GlobalState() {
return LoggerGlobalState::The();
}
} // namespace logger_detail
using logger_detail::ChannelId;
using logger_detail::MessageComponentSource;
using logger_detail::MessageSource;
using logger_detail::MakeChannelId;
/// Attach a sink to all Support loggers; allowing it to output logger messages.
inline void AttachSink(logger_detail::Sink& sink) {
logger_detail::GlobalState().AttachSink(sink);
}
inline logger_detail::MessageSeverity GetLogLevel() {
return logger_detail::GlobalState().GetLogLevel();
}
inline void SetLogLevel(logger_detail::MessageSeverity newLevel) {
return logger_detail::GlobalState().SetLogLevel(newLevel);
}
struct Logger {
using MessageSeverity = logger_detail::MessageSeverity;
using MessageData = logger_detail::MessageData;
using Sink = logger_detail::Sink;
/// Get the global instance of the logger.
static Logger& Global();
Logger() : Logger(logger_detail::ChannelGlobal) {}
constexpr explicit Logger(ChannelId channel) { this->channelId = channel; }
Logger(const Logger&) = delete;
Logger(Logger&&) = delete;
template <class... Args>
inline void Debug(std::string_view fmt, Args... args) {
VOut(MessageSeverity::Debug, fmt, std::make_format_args(std::forward<Args>(args)...));
}
template <class... Args>
inline void Info(std::string_view fmt, Args... args) {
VOut(MessageSeverity::Info, fmt, std::make_format_args(std::forward<Args>(args)...));
}
template <class... Args>
inline void Warning(std::string_view fmt, Args... args) {
VOut(MessageSeverity::Warning, fmt, std::make_format_args(std::forward<Args>(args)...));
}
template <class... Args>
inline void Error(std::string_view fmt, Args... args) {
VOut(MessageSeverity::Error, fmt, std::make_format_args(std::forward<Args>(args)...));
}
template <class... Args>
inline void Fatal(std::string_view fmt, Args... args) {
VOut(MessageSeverity::Fatal, fmt, std::make_format_args(std::forward<Args>(args)...));
}
private:
void VOut(MessageSeverity severity, std::string_view format, std::format_args args);
ChannelId channelId;
};
template <class... Args>
constexpr void LogDebug(std::string_view format, Args... args) {
Logger::Global().Debug(format, std::forward<Args>(args)...);
}
template <class... Args>
constexpr void LogInfo(std::string_view format, Args... args) {
Logger::Global().Info(format, std::forward<Args>(args)...);
}
template <class... Args>
constexpr void LogWarning(std::string_view format, Args... args) {
Logger::Global().Warning(format, std::forward<Args>(args)...);
}
template <class... Args>
constexpr void LogError(std::string_view format, Args... args) {
Logger::Global().Error(format, std::forward<Args>(args)...);
}
template <class... Args>
constexpr void LogFatal(std::string_view format, Args... args) {
Logger::Global().Fatal(format, std::forward<Args>(args)...);
}
} // namespace base

View File

@ -14,6 +14,7 @@ add_library(base_http
lobbyserver_target(base_http)
target_link_libraries(base_http PUBLIC
spdlog::spdlog
base::impl
Boost::url

View File

@ -1,5 +1,5 @@
#include <sys/socket.h>
#include <spdlog/spdlog.h>
#include <boost/beast/core/flat_buffer.hpp>
#include <boost/beast/http/read.hpp>
@ -71,7 +71,8 @@ namespace base::http {
struct Server::Impl {
struct Session {
Session(Impl& impl, Server::StreamType&& stream) : impl(impl), stream(std::move(stream)) {}
Session(Impl& impl, Server::StreamType&& stream)
: impl(impl), stream(std::move(stream)) {}
void Close() {
if(stream.socket().is_open()) {
@ -107,7 +108,7 @@ namespace base::http {
}
} catch(bsys::system_error& ec) {
// if(ec.code() != beast::http::error::end_of_stream)
// logger.Error("Error in http::BasicServer::DoSession(): {}", ec.what());
// spdlog::error("Error in http::BasicServer::DoSession(): {}", ec.what());
}
// todo: standalone close() function
@ -180,7 +181,8 @@ namespace base::http {
using RouteVariant = std::variant<Server::RouteHandler, Server::WebSocketRouteHandler>;
template <class ProtocolEndpoint>
Impl(asio::any_io_executor ioc, ProtocolEndpoint ep) : exec(ioc), ep(ep), acceptor(ioc) {}
Impl(asio::any_io_executor ioc, ProtocolEndpoint ep)
: exec(ioc), ep(ep), acceptor(ioc) {}
void On(beast::http::verb verb, std::string_view path, Server::RouteHandler handler) {
handlerStorage.emplace_back(handler);
@ -192,7 +194,7 @@ namespace base::http {
if(errstr) {
// error inserting into tree
logger.Error("Error inserting route \"{}\" into tree: {}", path, errstr);
spdlog::error("Error inserting route \"{}\" into tree: {}", path, errstr);
free(errstr);
return;
}
@ -205,7 +207,7 @@ namespace base::http {
&errstr);
if(errstr) {
// error inserting into tree
logger.Error("Error inserting route \"{}\" into tree: {}", path, errstr);
spdlog::error("Error inserting route \"{}\" into tree: {}", path, errstr);
free(errstr);
return;
}
@ -216,7 +218,7 @@ namespace base::http {
char* errstr { nullptr };
tree.compile(&errstr);
if(errstr) {
logger.Error("Error compiling route tree: {}", errstr);
spdlog::error("Error compiling route tree: {}", errstr);
free(errstr);
return false;
}
@ -315,7 +317,7 @@ namespace base::http {
using reuse_port = asio::detail::socket_option::boolean<SOL_SOCKET, SO_REUSEPORT>;
acceptor.set_option(reuse_port(true));
logger.Info("Able to enable SO_NODELAY; doing so");
spdlog::info("Able to enable SO_NODELAY; doing so");
acceptor.set_option(asio::ip::tcp::no_delay { true });
}
@ -332,7 +334,7 @@ namespace base::http {
} catch(bsys::system_error& ec) {
// Filter out "operation cancelled", because that's not really an error we need to know about.
if(ec.code() != asio::error::operation_aborted)
logger.Error("Error in http::BasicServer::Listener(): {}", ec.what());
spdlog::error("Error in http::BasicServer::Listener(): {}", ec.what());
}
listening = false;
@ -372,8 +374,6 @@ namespace base::http {
bool listening { false };
asio::basic_socket_acceptor<GenericProtocol> acceptor;
Logger logger { MakeChannelId(MessageSource::Http, MessageComponentSource::Http_Server) };
};
Server::Server(asio::any_io_executor ioc, asio::ip::tcp::endpoint ep) {

View File

@ -4,7 +4,6 @@
#include <http/request.hpp>
#include <http/response.hpp>
#include <http/websocket_client.hpp>
#include <base/logger.hpp>
#include <base/types.hpp>
namespace base::http {

View File

@ -3,6 +3,7 @@
#include <http/websocket_client.hpp>
#include <http/proxy_address.hpp>
#include <base/assert.hpp>
#include <spdlog/spdlog.h>
namespace base::http {
@ -83,7 +84,7 @@ namespace base::http {
asio::deferred);
}
} catch(bsys::error_code& ec) {
logger.Error("Error when closing (not fatal): {}", ec.what());
spdlog::error("Error when closing (not fatal): {}", ec.what());
}
// notify the send task that it needs to stop
@ -138,7 +139,7 @@ namespace base::http {
self->sendQueue.shrink_to_fit();
}
} catch(bsys::system_error& ec) {
// logger.Error("failure in write end: {}", ec.what());
// spdlog::error("failure in write end: {}", ec.what());
}
co_await self->Close();
@ -184,7 +185,7 @@ namespace base::http {
} catch(bsys::system_error& ec) {
// TODO: this should be re-enabled but doesn't seem to limit properly
// if(ec.code() != beast::websocket::error::closed || ec.code() != asio::error::eof)
// logger.Error("fail in read end {}", ec.what());
// spdlog::error("fail in read end {}", ec.what());
}
co_await self->Close();

View File

@ -4,7 +4,6 @@
#include <http/request.hpp>
#include <http/websocket_message.hpp>
#include <base/async_condition_variable.hpp>
#include <base/logger.hpp>
#include <base/types.hpp>
namespace base::http {
@ -70,8 +69,6 @@ namespace base::http {
Request upgrade;
Logger logger { MakeChannelId(MessageSource::Http, MessageComponentSource::Http_WebSocketClient) };
constexpr static u32 MAX_MESSAGES_IN_QUEUE = 256;
Awaitable<void> WriteEnd();

View File

@ -1,6 +1,5 @@
#pragma once
#include <base/assert.hpp>
#include <base/logger.hpp>
#include <base/types.hpp>
namespace base::http {

View File

@ -3,6 +3,8 @@
#include <boost/asio/read.hpp>
#include <boost/asio/write.hpp>
#include <spdlog/spdlog.h>
#include "DirtySockServer.hpp"
constexpr static auto MAX_PAYLOAD_SIZE = 4 * (1024 * 1024);
@ -30,7 +32,7 @@ namespace ls {
// Sanity check. I don't expect game payloa
if(header.payloadSize > MAX_PAYLOAD_SIZE) {
base::LogError("WOAH! Message size {} MB larger than {}MB..", (static_cast<float>(header.payloadSize) / 1024 / 1024), (static_cast<float>(MAX_PAYLOAD_SIZE) / 1024 / 1024));
spdlog::error("WOAH! Message size {} MB larger than {}MB..", (static_cast<float>(header.payloadSize) / 1024 / 1024), (static_cast<float>(MAX_PAYLOAD_SIZE) / 1024 / 1024));
co_return nullptr;
}
@ -48,7 +50,7 @@ namespace ls {
co_return MessageFactory::CreateAndParseMessage(header, propertyBuffer);
} catch(bsys::system_error& ec) {
if(ec.code() != asio::error::operation_aborted)
base::LogError("Error in DirtySockClient::WriteMessage(): {}", ec.what());
spdlog::error("Error in DirtySockClient::WriteMessage(): {}", ec.what());
co_return nullptr;
}
}
@ -62,7 +64,7 @@ namespace ls {
co_await asio::async_write(stream, asio::buffer(buf), asio::deferred);
} catch(bsys::system_error& ec) {
if(ec.code() != asio::error::operation_aborted)
base::LogError("Error in DirtySockClient::WriteMessage(): {}", ec.what());
spdlog::error("Error in DirtySockClient::WriteMessage(): {}", ec.what());
}
}
@ -76,14 +78,14 @@ namespace ls {
co_await message->Process(shared_from_this());
} else {
// This will occur if parsing fails or etc.
base::LogError("Error parsing message, closing connection");
spdlog::error("Error parsing message, closing connection");
Close();
co_return;
}
}
} catch(bsys::system_error& ec) {
if(ec.code() != asio::error::operation_aborted)
base::LogError("Error in DirtySockClient::Run(): {}", ec.what());
spdlog::error("Error in DirtySockClient::Run(): {}", ec.what());
}
}

View File

@ -1,5 +1,7 @@
#include "DirtySockServer.hpp"
#include <spdlog/spdlog.h>
#include "DirtySockClient.hpp"
namespace ls {
@ -32,7 +34,7 @@ namespace ls {
acceptor.bind(endpoint);
acceptor.listen(asio::socket_base::max_listen_connections);
logger.Info("DirtySockServer listening on {}:{}", endpoint.address().to_string(), endpoint.port());
spdlog::info("DirtySockServer listening on {}:{}", endpoint.address().to_string(), endpoint.port());
while(true) {
auto socket = co_await acceptor.async_accept(asio::deferred);
@ -42,7 +44,7 @@ namespace ls {
}
} catch(bsys::system_error& ec) {
if(ec.code() != asio::error::operation_aborted)
logger.Error("Error in DirtySockServer::Listener(): {}", ec.what());
spdlog::error("Error in DirtySockServer::Listener(): {}", ec.what());
}
co_return;

View File

@ -1,7 +1,6 @@
#pragma once
#include <base/fourcc.hpp>
#include <base/logger.hpp>
#include <impl/asio_config.hpp>
#include <memory>
#include <set>
@ -40,7 +39,7 @@ namespace ls {
std::set<base::Ref<DirtySockClient>> clientSet;
// i'm moving to spdlog fuck this
base::Logger logger { base::MakeChannelId(base::MessageSource::Server, base::MessageComponentSource::Server_Server) };
};
} // namespace ls

View File

@ -1,6 +1,6 @@
#include "IMessage.hpp"
#include <base/logger.hpp>
#include <spdlog/spdlog.h>
#include <impl/asio_config.hpp>
// So debug message can just reply
@ -153,11 +153,11 @@ namespace ls {
base::Awaitable<void> Process(base::Ref<ls::DirtySockClient> client) override {
auto* fccbytes = std::bit_cast<u8*>(&header.typeCode);
base::LogInfo("Debug Message FourCC lo: \"{:c}{:c}{:c}{:c}\"", fccbytes[0], fccbytes[1], fccbytes[2], fccbytes[3]);
base::LogInfo("Debug Message Properties:");
spdlog::info("Debug Message FourCC lo: \"{:c}{:c}{:c}{:c}\"", fccbytes[0], fccbytes[1], fccbytes[2], fccbytes[3]);
spdlog::info("Debug Message Properties:");
for(auto [key, value] : properties)
base::LogInfo("{}: {}", key, value);
spdlog::info("{}: {}", key, value);
// :( but it works to just replay the message.
co_await client->WriteMessage(std::make_shared<DebugMessage>(*this));

View File

@ -1,5 +1,7 @@
#include "Server.hpp"
#include <spdlog/spdlog.h>
#include "DirtySockServer.hpp"
#include "impl/asio_config.hpp"
@ -20,7 +22,7 @@ namespace ls {
if(!lobbyServer->Listening()) {
// uh oh worm..
logger.Error("for some reason lobby server isnt listening..");
spdlog::error("for some reason lobby server isnt listening..");
co_return;
}

View File

@ -4,9 +4,6 @@
#include <impl/asio_config.hpp>
#include <set>
#include "base/logger.hpp"
namespace ls {
struct DirtySockServer;
@ -35,7 +32,7 @@ namespace ls {
Config config;
base::Logger logger { base::MakeChannelId(base::MessageSource::Server, base::MessageComponentSource::Server_Server) };
};

View File

@ -1,11 +1,12 @@
#include <base/assert.hpp>
#include <base/stdout_sink.hpp>
#include <base/types.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/asio/thread_pool.hpp>
#include <thread>
#include <toml++/toml.hpp>
#include <spdlog/spdlog.h>
#include "Server.hpp"
asio::io_context ioc(1);
@ -18,10 +19,10 @@ base::Awaitable<void> CoWaitForSignal() {
try {
co_await interruptSignal.async_wait(asio::deferred);
} catch(bsys::system_error& ec) {
base::LogError("Error waiting for signal? {}", ec.what());
spdlog::error("Error waiting for signal? {}", ec.what());
}
base::LogInfo("SIGINT/SIGTERM recieved, stopping server...");
spdlog::info("SIGINT/SIGTERM recieved, stopping server...");
// After this the main coroutine will handle cleanly shutting down
co_await server->Stop();
@ -35,8 +36,6 @@ base::Awaitable<void> CoMain(const ls::Server::Config& config) {
}
int main() {
base::LoggerAttachStdout();
auto config = ls::Server::Config {};
try {
@ -48,29 +47,29 @@ int main() {
auto buddy_port_ptr = table["lobbyserver"]["buddy_listen_port"].as_integer();
if(!addr_ptr || !lobby_port_ptr || !buddy_port_ptr) {
base::LogError("Invalid configuration file \"{}\".", CONFIG_FILE);
spdlog::error("Invalid configuration file \"{}\".", CONFIG_FILE);
return 1;
}
if(lobby_port_ptr->get() > 65535) {
base::LogError("Invalid lobby listen port \"{}\", should be 65535 or less", lobby_port_ptr->get());
spdlog::error("Invalid lobby listen port \"{}\", should be 65535 or less", lobby_port_ptr->get());
return 1;
}
if(buddy_port_ptr->get() > 65535) {
base::LogError("Invalid buddy listen port \"{}\", should be 65535 or less", buddy_port_ptr->get());
spdlog::error("Invalid buddy listen port \"{}\", should be 65535 or less", buddy_port_ptr->get());
return 1;
}
config.buddyListenEndpoint = { asio::ip::make_address(addr_ptr->get()), static_cast<u16>(buddy_port_ptr->get()) };
config.lobbyListenEndpoint = { asio::ip::make_address(addr_ptr->get()), static_cast<u16>(lobby_port_ptr->get()) };
} else {
base::LogError("Invalid configuration file \"{}\"", CONFIG_FILE);
spdlog::error("Invalid configuration file \"{}\"", CONFIG_FILE);
return 1;
}
} catch(toml::parse_error& err) {
base::LogError("Error parsing configuration file \"{}\": {}", CONFIG_FILE, err.what());
spdlog::error("Error parsing configuration file \"{}\": {}", CONFIG_FILE, err.what());
return 1;
}
@ -92,7 +91,7 @@ int main() {
BASE_CHECK(false, "Unhandled exception in server main loop: {}", e.what());
}
} else {
base::LogInfo("Server returned, exiting process\n");
spdlog::info("Server returned, exiting process\n");
// done
ioc.stop();
}

View File

@ -1,13 +1,13 @@
#include <impl/asio_config.hpp>
#include <spdlog/spdlog.h>
#include "base/logger.hpp"
#include "../IMessage.hpp"
LS_MESSAGE(PingMessage, "~png") {
LS_MESSAGE_CTOR(PingMessage, "~png")
base::Awaitable<void> Process(base::Ref<ls::DirtySockClient> client) override {
base::LogInfo("Got ping message!");
spdlog::info("Got ping message!");
co_return;
}
};

View File

@ -1,2 +1,5 @@
add_subdirectory(boost)
add_subdirectory(tomlplusplus)
#set(SPDLOG_USE_STD_FORMAT ON)
add_subdirectory(spdlog)

1
third_party/spdlog vendored Submodule

@ -0,0 +1 @@
Subproject commit ae525b75c31adaad130dd4501d37ff632ec5eade