Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ project(cpp-logger VERSION 0.1.0 LANGUAGES C CXX)
# include_directories(logger)
set(CMAKE_CXX_STANDARD 20)
add_executable(cpplogger main.cpp
logger.h
manager.h)
logger.h)
33 changes: 27 additions & 6 deletions logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
#include <iostream>
#include <fstream>
#include <chrono>
#include "manager.h"
#include <map>
#include <stdexcept> // Required for std::runtime_error

// Handle file system for specific platform
#ifdef _WIN32
Expand Down Expand Up @@ -91,7 +91,7 @@ class Logger {

public:
Logger(const std::string name, const std::string &root_dir, const std::string &file_name, const bool debug = false) {
this->name = name;
this->name = name;
this->root_dir = root_dir;
this->file_name = file_name;
this->debug = debug;
Expand Down Expand Up @@ -120,12 +120,22 @@ class Logger {
this->log_file.open(this->root_dir + "/" + file_name);
}

// Check if the log file was opened successfully
if (!this->log_file.is_open()) {
throw std::runtime_error("Failed to open log file at: " + (this->root_dir[this->root_dir.size() - 1] == '/' || this->root_dir[this->root_dir.size() - 1] == '\\' ? this->root_dir : this->root_dir + "/") + file_name);
}

// update the status of logger
this->log_file << ">>> Logger " << this->name << " initiated at " << std::chrono::system_clock::now() << " <<<\n";
std::cout << LOGGER::COLOR::CYAN << ">>> Logger " << this->name << " initiated at " << std::chrono::system_clock::now() << " <<<" << LOGGER::COLOR::RESET << "\n";

// Register the logger to manager buffer
BUF_MANAGER<Logger>::register_buf(this);
}

// Destructor to ensure exit_logger is called
~Logger() {
if (is_active()) {
exit_logger();
}
}

// Check if the logger is active or running
Expand Down Expand Up @@ -183,8 +193,20 @@ class Logger {
print_log(message, level);
}

// Check for invalid log level before accessing handler
if (this->handler.find(level) == this->handler.end()) {
// To prevent recursive error logging if this itself is part of an error log,
// we print to cerr and throw a different, more specific error.
// Or, simply throw, assuming this method won't be called with invalid levels internally.
// For now, let's throw a runtime_error.
// A more advanced strategy might log this specific error to a default/emergency logger
// or use a predefined "UNKNOWN" level if we want to record the attempt.
// However, throwing is safest to indicate misuse of the API.
throw std::runtime_error("Invalid log level used: " + level);
}

this->log_file << std::chrono::system_clock::now() << " " << level << " " << message << "\n";
this->handler.at(level).count++;
this->handler.at(level).count++; // Now safe to use .at() due to the check above, or use find result.
this->log_count++;
}

Expand All @@ -198,7 +220,6 @@ class Logger {
this->end_time = std::chrono::system_clock::now();
this->log_file << ">>> Logger " << this->name << " exited at " << this->end_time << " <<<\n";
this->log_file.close();
BUF_MANAGER<Logger>::unregister_buf(this); // Unregister the logger from buffer manager
std::cout << LOGGER::COLOR::CYAN << ">>> Exited Logger " << this->name << " at " << this->end_time << " <<<" << LOGGER::COLOR::RESET << "\n";
}

Expand Down
70 changes: 47 additions & 23 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,58 @@
*/

#include "logger.h"
#include <filesystem>
#include <filesystem> // For std::filesystem::path and std::filesystem::current_path()
#include <stdexcept> // For std::runtime_error
#include <iostream> // For std::cerr and std::endl

// Handle file system for specific platform
#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif
// Handle file system for specific platform (getcwd is no longer used)
// #ifdef _WIN32
// #include <direct.h>
// #else
// #include <unistd.h>
// #endif

int main() {
const std::string name = "main";
const std::string root_dir = std::string(getcwd(nullptr, 100)) + std::string("/cache"); // Insert absolute path of log file root
// Use std::filesystem for robust path construction
const std::string root_dir = (std::filesystem::current_path() / "cache").string();
const std::string log_file = "test_logger.log"; // Insert log file name
const bool debug = true;

// Initiated logger instance
auto logger = Logger(name, root_dir, log_file, debug);

// add some logs
logger.log("Debug log!", LOGGER::LEVEL::DEBUG);
logger.log("Info log!", LOGGER::LEVEL::INFO);
logger.log("Warning log!", LOGGER::LEVEL::WARNING);
logger.log("Error log!", LOGGER::LEVEL::ERROR);
logger.log("Fatal log!", LOGGER::LEVEL::FATAL);
logger.log("Unknown log!", LOGGER::LEVEL::UNKNOWN);
logger.log("Message log!", LOGGER::LEVEL::MESSAGE);

// close logger
logger.exit_logger();
return 0;
try {
// Initiated logger instance
auto logger = Logger(name, root_dir, log_file, debug);

// add some logs
logger.log("Debug log!", LOGGER::LEVEL::DEBUG);
logger.log("Info log!", LOGGER::LEVEL::INFO);
logger.log("Warning log!", LOGGER::LEVEL::WARNING);
logger.log("Error log!", LOGGER::LEVEL::ERROR);
logger.log("Fatal log!", LOGGER::LEVEL::FATAL);
// logger.log("Unknown log!", LOGGER::LEVEL::UNKNOWN); // This level is valid
logger.log("Message log!", LOGGER::LEVEL::MESSAGE);

// Example of logging an invalid level to test error handling in logger.log()
// Note: This will throw std::runtime_error due to recent changes in Logger::log()
// logger.log("This is an invalid level!", "INVALID_LEVEL");


// The destructor of logger will call exit_logger() automatically.
// Explicitly calling logger.exit_logger(); is no longer strictly necessary
// if logger is the last thing to be used in this scope.
// However, if you need to ensure logs are flushed before further operations
// not shown here, or before a crash might prevent destructor from running,
// calling it explicitly can still be useful.
// For this example, we'll rely on the destructor.
// logger.exit_logger();

} catch (const std::runtime_error& e) {
std::cerr << "Runtime Error: " << e.what() << std::endl;
return 1; // Indicate failure
} catch (...) {
std::cerr << "An unexpected error occurred." << std::endl;
return 1; // Indicate failure
}

return 0; // Indicate success
}
58 changes: 0 additions & 58 deletions manager.h

This file was deleted.