| 254 | } |
| 255 | |
| 256 | bool ServerApplication::CreateServerConsole() |
| 257 | { |
| 258 | try |
| 259 | { |
| 260 | std::shared_ptr<spdlog::sinks::stdout_color_sink_mt> console_sink; |
| 261 | console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); |
| 262 | console_sink->set_level(spdlog::level::info); |
| 263 | console_sink->set_pattern("[%H:%M:%S] [%^%l%$] %v"); |
| 264 | |
| 265 | std::vector<spdlog::sink_ptr> sinks{console_sink}; |
| 266 | |
| 267 | try |
| 268 | { |
| 269 | auto now = std::chrono::system_clock::now(); |
| 270 | auto tt = std::chrono::system_clock::to_time_t(now); |
| 271 | std::tm tm{}; |
| 272 | #ifdef _WIN32 |
| 273 | localtime_s(&tm, &tt); |
| 274 | #else |
| 275 | localtime_r(&tt, &tm); |
| 276 | #endif |
| 277 | char timestamp[32]; |
| 278 | std::snprintf(timestamp, sizeof(timestamp), "%04d%02d%02d_%02d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, |
| 279 | tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); |
| 280 | |
| 281 | int port = AppConfig::Instance().GetNetworkPort(); |
| 282 | std::string logPath = |
| 283 | GamePaths::Instance().UserDir() + "server_" + timestamp + "_" + std::to_string(port) + ".log"; |
| 284 | |
| 285 | auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(logPath, true); |
| 286 | file_sink->set_level(spdlog::level::debug); |
| 287 | file_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v"); |
| 288 | sinks.push_back(file_sink); |
| 289 | LOG_INFO(Core, "Server log: {}", logPath); |
| 290 | } |
| 291 | catch (const spdlog::spdlog_ex& ex) |
| 292 | { |
| 293 | LOG_WARN(Core, "File logging not available: {}", ex.what()); |
| 294 | } |
| 295 | |
| 296 | auto server_logger = std::make_shared<spdlog::logger>("Server", sinks.begin(), sinks.end()); |
| 297 | server_logger->set_level(spdlog::level::debug); |
| 298 | try |
| 299 | { |
| 300 | spdlog::register_logger(server_logger); |
| 301 | } |
| 302 | catch (const spdlog::spdlog_ex& ex) |
| 303 | { |
| 304 | LOG_WARN(Core, "Failed to register Server logger: {}", ex.what()); |
| 305 | } |
| 306 | |
| 307 | // AppServerLoop requires the app to be active before it processes simulation. |
| 308 | m_appActive = true; |
| 309 | |
| 310 | if (!AppConfig::Instance().NoBanner()) |
| 311 | { |
| 312 | LOG_INFO(Core, R"BANNER( |
| 313 | _ ____ __ __ _ |
nothing calls this directly
no test coverage detected