config: Add 1 and update 10 files
All checks were successful
Build-Test-Publish / build (linux/amd64) (push) Successful in 1m33s
Build-Test-Publish / build (linux/arm64) (push) Successful in 2m45s
Build-Test-Publish / create-manifest (push) Successful in 13s

This commit is contained in:
j842
2025-08-16 13:08:05 +12:00
parent baa215e762
commit 38a3a7a478
11 changed files with 156 additions and 35 deletions

View File

@@ -42,10 +42,11 @@ target_include_directories(${PROJECT_NAME} PRIVATE
find_package(OpenSSL REQUIRED)
find_package(Drogon CONFIG REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(spdlog REQUIRED)
# Link libraries for main executable
target_link_libraries(${PROJECT_NAME} PRIVATE
nlohmann_json::nlohmann_json Drogon::Drogon
nlohmann_json::nlohmann_json Drogon::Drogon spdlog::spdlog
/usr/local/lib/libpgcommon.a /usr/local/lib/libpgport.a
lzma dl)

View File

@@ -1,4 +1,5 @@
#include "config.hpp"
#include "logger.hpp"
#include <fstream>
#include <sstream>
#include <iostream>
@@ -11,17 +12,17 @@ namespace simple_object_storage {
bool load_config(const std::string& config_path, ServerConfig& config) {
try {
if (config_path.empty()) {
std::cerr << "Config path is empty" << std::endl;
LOG_ERROR("Config path is empty");
return false;
}
if (!std::filesystem::exists(config_path)) {
std::cerr << "Config file does not exist: " << config_path << std::endl;
LOG_ERROR("Config file does not exist: {}", config_path);
return false;
}
std::ifstream file(config_path);
if (!file.is_open()) {
std::cerr << "Failed to open config file: " << config_path << std::endl;
LOG_ERROR("Failed to open config file: {}", config_path);
return false;
}
@@ -78,11 +79,22 @@ bool load_config(const std::string& config_path, ServerConfig& config) {
}
}
// Parse logging configuration
if (j.contains("logging")) {
const auto& logging = j["logging"];
if (logging.contains("log_file_path")) {
config.log_file_path = logging["log_file_path"].get<std::string>();
}
if (logging.contains("log_level")) {
config.log_level = logging["log_level"].get<std::string>();
}
}
// Line number accuracy improved
return true;
} catch (const std::exception& e) {
std::cerr << "Error parsing config file: " << e.what() << std::endl;
LOG_ERROR("Error parsing config file: {}", e.what());
return false;
}
}

View File

@@ -22,6 +22,10 @@ struct ServerConfig {
// Rate limiting configuration
int auth_rate_limit = 5; // Maximum number of auth attempts
int auth_window_seconds = 300; // Time window in seconds (5 minutes)
// Logging configuration
std::filesystem::path log_file_path = "/data/sos.log"; // Path to log file (empty string disables file logging)
std::string log_level = "info"; // Log level: trace, debug, info, warn, error, critical
};
bool load_config(const std::string& config_path, ServerConfig& config);

81
src/logger.hpp Normal file
View File

@@ -0,0 +1,81 @@
#pragma once
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <memory>
namespace simple_object_storage {
class Logger {
public:
static void init(const std::string& log_level = "info",
const std::string& log_file = "",
size_t max_file_size = 10 * 1024 * 1024,
size_t max_files = 3) {
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_level(spdlog::level::trace);
std::vector<spdlog::sink_ptr> sinks{console_sink};
if (!log_file.empty()) {
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
log_file, max_file_size, max_files);
file_sink->set_level(spdlog::level::trace);
sinks.push_back(file_sink);
}
auto logger = std::make_shared<spdlog::logger>("sos", sinks.begin(), sinks.end());
if (log_level == "trace") {
logger->set_level(spdlog::level::trace);
} else if (log_level == "debug") {
logger->set_level(spdlog::level::debug);
} else if (log_level == "info") {
logger->set_level(spdlog::level::info);
} else if (log_level == "warn" || log_level == "warning") {
logger->set_level(spdlog::level::warn);
} else if (log_level == "error") {
logger->set_level(spdlog::level::err);
} else if (log_level == "critical") {
logger->set_level(spdlog::level::critical);
} else {
logger->set_level(spdlog::level::info);
}
logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v");
spdlog::set_default_logger(logger);
spdlog::flush_every(std::chrono::seconds(3));
}
static std::shared_ptr<spdlog::logger> get() {
return spdlog::default_logger();
}
};
#ifdef LOG_TRACE
#undef LOG_TRACE
#endif
#ifdef LOG_DEBUG
#undef LOG_DEBUG
#endif
#ifdef LOG_INFO
#undef LOG_INFO
#endif
#ifdef LOG_WARN
#undef LOG_WARN
#endif
#ifdef LOG_ERROR
#undef LOG_ERROR
#endif
#define LOG_TRACE(...) SPDLOG_TRACE(__VA_ARGS__)
#define LOG_DEBUG(...) SPDLOG_DEBUG(__VA_ARGS__)
#define LOG_INFO(...) SPDLOG_INFO(__VA_ARGS__)
#define LOG_WARN(...) SPDLOG_WARN(__VA_ARGS__)
#define LOG_ERROR(...) SPDLOG_ERROR(__VA_ARGS__)
#define LOG_CRITICAL(...) SPDLOG_CRITICAL(__VA_ARGS__)
}

View File

@@ -1,5 +1,6 @@
#include "server.hpp"
#include "config.hpp"
#include "logger.hpp"
#include <iostream>
#include <fstream>
#include <string>
@@ -40,9 +41,9 @@ std::filesystem::path get_config_path() {
return path;
}
}
std::cout << "No config file found. Checked: " << std::endl;
LOG_ERROR("No config file found. Checked:");
for (const auto& path : config_paths) {
std::cout << " " << path << std::endl;
LOG_ERROR(" {}", path.string());
}
return std::filesystem::path();
}
@@ -52,19 +53,25 @@ bool initialize_server() {
if (config_path.empty()) {
return false;
}
std::cout << "Config file: " << config_path << std::endl;
ServerConfig config;
if (!simple_object_storage::load_config(config_path, config)) {
std::cout << "Config file at " << config_path << " is not valid." << std::endl;
LOG_ERROR("Config file at {} is not valid.", config_path.string());
return false;
}
std::cout << "Starting server at " << config.host << ":" << config.port << std::endl;
std::cout << "Object store path: " << config.object_store_path << std::endl;
// Reinitialize logger with config settings
Logger::init(config.log_level, config.log_file_path.string());
LOG_INFO("Config file: {}", config_path.string());
LOG_INFO("Starting server at {}:{}", config.host, config.port);
LOG_INFO("Object store path: {}", config.object_store_path.string());
if (!config.log_file_path.empty()) {
LOG_INFO("Log file: {}", config.log_file_path.string());
}
if (!std::filesystem::exists(config.object_store_path)) {
std::cout << "Object store path does not exist: " << config.object_store_path << std::endl;
LOG_ERROR("Object store path does not exist: {}", config.object_store_path.string());
return false;
}
@@ -74,7 +81,7 @@ bool initialize_server() {
void stop_server() {
if (g_server) {
std::cout << "Stopping server..." << std::endl;
LOG_INFO("Stopping server...");
g_server->stop();
if (g_server_thread.joinable()) {
g_server_thread.join();
@@ -86,28 +93,30 @@ void stop_server() {
void signal_handler(int signal) {
switch (signal) {
case SIGHUP:
std::cout << "Received SIGHUP signal - reloading configuration" << std::endl;
LOG_INFO("Received SIGHUP signal - reloading configuration");
stop_server();
if (!initialize_server()) {
std::cerr << "Failed to restart server with new configuration" << std::endl;
LOG_ERROR("Failed to restart server with new configuration");
g_running = false;
}
break;
case SIGTERM:
case SIGINT:
std::cout << "Received termination signal" << std::endl;
LOG_INFO("Received termination signal");
g_running = false;
break;
}
}
int main(int argc, char* argv[]) {
// Initialize logger with defaults (will be reconfigured after loading config)
Logger::init("info", "");
if (argc > 1) {
if (std::string(argv[1]) == "version") {
std::cout << dropshell::VERSION << std::endl;
return 0;
}
std::cout << "Simple Object Storage version: " << dropshell::VERSION << std::endl;
}
// Set up signal handlers
@@ -117,15 +126,15 @@ int main(int argc, char* argv[]) {
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, nullptr) == -1) {
std::cerr << "Failed to set up SIGHUP handler" << std::endl;
LOG_ERROR("Failed to set up SIGHUP handler");
return 1;
}
if (sigaction(SIGTERM, &sa, nullptr) == -1) {
std::cerr << "Failed to set up SIGTERM handler" << std::endl;
LOG_ERROR("Failed to set up SIGTERM handler");
return 1;
}
if (sigaction(SIGINT, &sa, nullptr) == -1) {
std::cerr << "Failed to set up SIGINT handler" << std::endl;
LOG_ERROR("Failed to set up SIGINT handler");
return 1;
}
@@ -133,10 +142,12 @@ int main(int argc, char* argv[]) {
if (!initialize_server()) {
return 1;
}
LOG_INFO("Simple Object Storage version: {}", dropshell::VERSION);
// Start server in main thread
if (!g_server->start()) {
std::cerr << "Failed to start server" << std::endl;
LOG_ERROR("Failed to start server");
return 1;
}

View File

@@ -1,4 +1,5 @@
#include "put_handler.hpp"
#include "logger.hpp"
#include "hash.hpp"
#include "compress.hpp"
#include "string_utils.hpp"
@@ -279,7 +280,7 @@ void PutHandler::handle_upload_object(const drogon::HttpRequestPtr& req, std::fu
std::filesystem::rename(temp_path, final_path);
temp_file_deleter.release();
} catch (const std::filesystem::filesystem_error& e) {
std::cerr << "Error renaming temp file: " << e.what() << std::endl;
LOG_ERROR("Error renaming temp file: {}", e.what());
resp->setStatusCode(drogon::k500InternalServerError);
nlohmann::json response = {{"result", "error"}, {"error", "Failed to store object file"}};
resp->setBody(response.dump());

View File

@@ -10,6 +10,7 @@
#include <sstream>
#include "server.hpp"
#include "logger.hpp"
#include "hash.hpp"
#include "compress.hpp"
#include "string_utils.hpp" // Include the new utility header
@@ -34,7 +35,7 @@ bool Server::init_db() {
db_ = std::make_unique<Database>(db_path);
return true;
} catch (const std::runtime_error& e) {
std::cerr << "Database initialization error: " << e.what() << std::endl;
LOG_ERROR("Database initialization error: {}", e.what());
return false;
}
}
@@ -114,7 +115,7 @@ Server::Server(const ServerConfig& config)
Server::setInstance(this);
if (!std::filesystem::exists(config_.object_store_path)) {
std::cerr << "Object store directory does not exist: " << config_.object_store_path << std::endl;
LOG_ERROR("Object store directory does not exist: {}", config_.object_store_path.string());
return;
}
@@ -146,7 +147,7 @@ Server::~Server() {
bool Server::start() {
if (!db_) { // Check if DB initialization failed
std::cerr << "Database is not initialized. Cannot start server." << std::endl;
LOG_ERROR("Database is not initialized. Cannot start server.");
return false;
}
setup_routes();
@@ -167,7 +168,7 @@ bool Server::start() {
drogon::app().run();
} catch (const std::exception& e) {
running_ = false;
std::cerr << "Failed to start server: " << e.what() << std::endl;
LOG_ERROR("Failed to start server: {}", e.what());
return false;
}
return true;
@@ -177,7 +178,7 @@ void Server::stop() {
if (running_) {
drogon::app().quit();
running_ = false;
std::cout << "Server stopped." << std::endl;
LOG_INFO("Server stopped.");
}
}
@@ -379,7 +380,7 @@ void Server::handle_get_metadata(const drogon::HttpRequestPtr& req, std::functio
response = {{"result", "success"}, {"metadata", entry.metadata}};
resp->setBody(response.dump());
} catch (const nlohmann::json::exception& e) {
std::cerr << "Error serializing metadata for hash " << hash_str << ": " << e.what() << std::endl;
LOG_ERROR("Error serializing metadata for hash {}: {}", hash_str, e.what());
resp->setStatusCode(drogon::k500InternalServerError);
response = {{"result", "error"}, {"error", "Internal server error: Failed to serialize metadata"}};
resp->setBody(response.dump());
@@ -455,7 +456,7 @@ void Server::handle_delete_object(const drogon::HttpRequestPtr& req, std::functi
try {
std::filesystem::remove(file_path);
} catch (const std::filesystem::filesystem_error& e) {
std::cerr << "Error deleting object file: " << e.what() << std::endl;
LOG_ERROR("Error deleting object file: {}", e.what());
resp->setStatusCode(drogon::k500InternalServerError);
nlohmann::json response = {{"result", "error"}, {"error", "Failed to delete object file: " + std::string(e.what())}};
resp->setBody(response.dump());

View File

@@ -1,4 +1,5 @@
#include "temp_directory.hpp"
#include "logger.hpp"
#include <filesystem>
#include <string>
@@ -42,13 +43,13 @@ TempDirectory::~TempDirectory() {
std::error_code ec; // Use error code to avoid exceptions in destructor
std::filesystem::remove_all(path_, ec);
if (ec) {
std::cerr << "Error removing temporary directory " << path_.string() << ": " << ec.message() << std::endl;
LOG_ERROR("Error removing temporary directory {}: {}", path_.string(), ec.message());
}
}
} catch (const std::exception& e) { // Catch potential exceptions from exists() though unlikely
std::cerr << "Error during temporary directory cleanup for " << path_.string() << ": " << e.what() << std::endl;
LOG_ERROR("Error during temporary directory cleanup for {}: {}", path_.string(), e.what());
} catch (...) {
std::cerr << "Unknown error during temporary directory cleanup for " << path_.string() << std::endl;
LOG_ERROR("Unknown error during temporary directory cleanup for {}", path_.string());
}
}

View File

@@ -1,4 +1,5 @@
#include "utils.hpp"
#include "logger.hpp"
namespace simple_object_storage
{
@@ -18,7 +19,7 @@ namespace simple_object_storage
}
catch (const std::filesystem::filesystem_error &e)
{
std::cerr << "Error deleting temp file: " << path_ << " - " << e.what() << std::endl;
LOG_ERROR("Error deleting temp file: {} - {}", path_.string(), e.what());
}
}
}

View File

@@ -8,6 +8,10 @@
"auth_rate_limit": 5,
"auth_window_seconds": 2
},
"logging": {
"log_file_path": "/data/test.log",
"log_level": "info"
},
"port": 7703,
"host": "127.0.0.1"
}

View File

@@ -8,6 +8,10 @@
"auth_rate_limit": 5,
"auth_window_seconds": 2
},
"logging": {
"log_file_path": "/data/test.log",
"log_level": "info"
},
"port": 7703,
"host": "127.0.0.1"
}