Skip to content
Merged
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
6 changes: 3 additions & 3 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignEscapedNewlines: Left
AlignTrailingComments: false
AlignConsecutiveAssignments: None
AlignTrailingComments: true
AlignConsecutiveAssignments: true
AlignOperands: Align
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
Expand Down Expand Up @@ -46,7 +46,7 @@ SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
Expand Down
2 changes: 1 addition & 1 deletion examples/standard/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ int main() {
std::cout << "Version: " << LOGVERSION_MAJOR << "." << LOGVERSION_MINOR << "." << LOGVERSION_PATCH << std::endl;

static Logging::LogConfig config;
auto mock = std::make_shared<Logging::LogOutputMock>();
auto mock = std::make_shared<Logging::LogOutputMock>();
auto logFile = std::make_shared<Logging::LogOutputFile>("Filename.txt");

config.AddLogOutput(std::make_shared<Logging::LogOutputConsole>());
Expand Down
2 changes: 1 addition & 1 deletion src/LogConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ void LogConfig::SetMinLogLevel(const LogLevel logLevel) {
m_minLogLevel = logLevel;
}

} // namespace Logging
} // namespace Logging
2 changes: 1 addition & 1 deletion src/LogEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ std::string LogEntry::OutputText() const {
return std::format("{} {} {}", m_time, LevelToText(m_level), m_text);
}

} // namespace Logging
} // namespace Logging
2 changes: 1 addition & 1 deletion src/LogLevel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ std::string LevelToText(LogLevel level) {
return "";
}

} // namespace Logging
} // namespace Logging
2 changes: 1 addition & 1 deletion src/LogOutputConsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ void LogOutputConsole::Write(const LogEntry& entry) {
std::clog << entry.OutputText() << "\n";
}

} // namespace Logging
} // namespace Logging
95 changes: 64 additions & 31 deletions src/LogOutputFile.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
#include "Logger/LogOutputFile.hpp"

#include <filesystem>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <system_error>

#ifdef _WIN32
#include <shlobj.h>
#include <windows.h>
#endif

namespace Logging {

LogOutputFile::LogOutputFile(const std::string& filePath, std::size_t maxFileSize)
Expand All @@ -12,42 +18,38 @@ LogOutputFile::LogOutputFile(const std::string& filePath, std::size_t maxFileSiz

void LogOutputFile::RotateFile() {
const std::filesystem::path originalPath(m_filePath);
const auto parent = originalPath.parent_path();
const auto stem = originalPath.stem().string();
const auto parent = originalPath.parent_path();
const auto stem = originalPath.stem().string();
const auto extension = originalPath.extension().string();

const auto baseName = extension.empty() ? originalPath.filename().string() : stem;

std::error_code ec;
constexpr unsigned kMaxRotations = 10000;
unsigned count = 1u;
constexpr unsigned kMaxRotations = 10000;
unsigned count = 1u;
std::filesystem::path newFilePath;
do {
if (count > kMaxRotations) {
return;
}

auto rotatedName = baseName + "(" + std::to_string(count) + ")" + extension;
newFilePath = parent.empty() ? std::filesystem::path(rotatedName) : parent / rotatedName;
newFilePath = parent.empty() ? std::filesystem::path(rotatedName) : parent / rotatedName;
++count;
} while (std::filesystem::exists(newFilePath, ec));
ec.clear(); // // Any errors during probing are ignored by design

std::filesystem::rename(originalPath, newFilePath, ec);
if (ec == std::errc::cross_device_link) {
// Best-effort fallback
std::filesystem::copy_file(
originalPath,
newFilePath,
std::filesystem::copy_options::overwrite_existing,
ec);

if (!ec) {
std::filesystem::remove(originalPath, ec);
}
}

// Any failure beyond this point is intentionally ignored.
if (ec == std::errc::cross_device_link) {
// Best-effort fallback
std::filesystem::copy_file(originalPath, newFilePath, std::filesystem::copy_options::overwrite_existing, ec);

if (!ec) {
std::filesystem::remove(originalPath, ec);
}
}

// Any failure beyond this point is intentionally ignored.
}

void LogOutputFile::Write(const std::vector<LogEntry>& logEntries) {
Expand All @@ -64,11 +66,11 @@ void LogOutputFile::Write(const std::vector<LogEntry>& logEntries) {
outfile.close();

// Check max file size reached
std::error_code ec;
const auto fileSize = std::filesystem::file_size(m_filePath, ec);
if (!ec && fileSize >= m_maxFileSize) {
RotateFile();
}
std::error_code ec;
const auto fileSize = std::filesystem::file_size(m_filePath, ec);
if (!ec && fileSize >= m_maxFileSize) {
RotateFile();
}
}

void LogOutputFile::Write(const LogEntry& entry) {
Expand All @@ -83,15 +85,46 @@ void LogOutputFile::Write(const LogEntry& entry) {
outfile.close();

// Check max filesize reached
std::error_code ec;
const auto fileSize = std::filesystem::file_size(m_filePath, ec);
if (!ec && fileSize >= m_maxFileSize) {
RotateFile();
}
std::error_code ec;
const auto fileSize = std::filesystem::file_size(m_filePath, ec);
if (!ec && fileSize >= m_maxFileSize) {
RotateFile();
}
}

std::string LogOutputFile::FilePath() const {
return m_filePath;
}

} // namespace Logging
std::filesystem::path GetDefaultLogDir(const std::string& appName) {
#if defined(_WIN32)
// 1) Windows: %LOCALAPPDATA%/<AppName>/logs
PWSTR path = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &path))) {
std::filesystem::path p(path);
CoTaskMemFree(path);
return p / appName / "logs";
}
#elif defined(__APPLE__)
// 2) macOS: ~/Library/Logs/<AppName>
const char* home = std::getenv("HOME");
if (home && std::strlen(home) > 0) {
return std::filesystem::path(home) / "Library/Logs" / appName;
}
#else
// 3) Linux/Unix: XDG_STATE_HOME/<AppName>/logs or ~/.local/state/<AppName>/logs
const char* state = std::getenv("XDG_STATE_HOME");
if (state && std::strlen(state) > 0) {
return std::filesystem::path(state) / appName / "logs";
}
const char* home = std::getenv("HOME");
if (home && std::strlen(home) > 0) {
return std::filesystem::path(home) / ".local/state" / appName / "logs";
}
#endif

// 4) Fallback
return std::filesystem::current_path() / "logs";
}

} // namespace Logging
2 changes: 1 addition & 1 deletion src/LogOutputMock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ void LogOutputMock::Write(const LogEntry& entry) {
m_logEntries.emplace_back(entry);
}

} // namespace Logging
} // namespace Logging
2 changes: 1 addition & 1 deletion src/Logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ void Logger::Log(const LogLevel level, const std::string& text) {
m_entries.emplace_back(entry);
}

} // namespace Logging
} // namespace Logging
14 changes: 7 additions & 7 deletions src/Profiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@ namespace Logging {
Profiler::Profiler(Logger logger, std::string identifier)
: m_logger(std::move(logger)), m_identifier(std::move(identifier)) {
m_startTime = std::chrono::steady_clock::now();
m_lastTime = m_startTime;
m_lastTime = m_startTime;

m_logger.Log(Logging::LogLevel::Info, std::format("--> {} START", m_identifier));
}

Profiler::~Profiler() {
const auto now = std::chrono::steady_clock::now();
const auto timeMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_startTime).count(); // t in ms
const auto now = std::chrono::steady_clock::now();
const auto timeMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_startTime).count(); // t in ms
m_logger.Log(Logging::LogLevel::Info, std::format("<-- {} END: {}ms", m_identifier, timeMs));
}

void Profiler::LogStep(const std::string& stepName) {
const auto now = std::chrono::steady_clock::now();
const auto stepMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastTime).count(); // t in ms
const auto totalMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_startTime).count(); // t in ms
const auto now = std::chrono::steady_clock::now();
const auto stepMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastTime).count(); // t in ms
const auto totalMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_startTime).count(); // t in ms
m_logger.Log(Logging::LogLevel::Info,
std::format("--- {} STEP {}: +{}ms ({}ms total)", m_identifier, stepName, stepMs, totalMs));
m_lastTime = now;
}


} // namespace Logging
} // namespace Logging
8 changes: 4 additions & 4 deletions src/include/Logger/ILogOutput.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ namespace Logging {
//! Defines what functionality a log output has to define.
class ILogOutput {
protected:
ILogOutput() = default;
ILogOutput(ILogOutput&& other) = default;
ILogOutput() = default;
ILogOutput(ILogOutput&& other) = default;
ILogOutput(const ILogOutput& other) = default;

ILogOutput& operator=(ILogOutput&& other) = default;
ILogOutput& operator=(ILogOutput&& other) = default;
ILogOutput& operator=(ILogOutput const& other) = default;

public:
Expand All @@ -26,4 +26,4 @@ class ILogOutput {
virtual void Write(const LogEntry& entry) = 0;
};

} // namespace Logging
} // namespace Logging
8 changes: 4 additions & 4 deletions src/include/Logger/LogConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ class LogConfig {
LogLevel MinLogLevel() const;

private:
bool m_logEnabled = true; //!< Enable/Disable logging.
LogLevel m_minLogLevel = LogLevel::Any; //!< Only log messages with severity above this.
std::vector<std::shared_ptr<ILogOutput>> m_logOutputs; //!< Where to write the log data to.
bool m_logEnabled = true; //!< Enable/Disable logging.
LogLevel m_minLogLevel = LogLevel::Any; //!< Only log messages with severity above this.
std::vector<std::shared_ptr<ILogOutput>> m_logOutputs; //!< Where to write the log data to.
};

} // namespace Logging
} // namespace Logging
8 changes: 4 additions & 4 deletions src/include/Logger/LogEntry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ struct LogEntry {
//! Returns the formatted log entry data.
std::string OutputText() const;

LogLevel m_level; //!< Log level of this one entry.
std::string m_text; //!< All log entries.
std::string m_time; //!< Timestamp of the log entry.
LogLevel m_level; //!< Log level of this one entry.
std::string m_text; //!< All log entries.
std::string m_time; //!< Timestamp of the log entry.
};

} // namespace Logging
} // namespace Logging
2 changes: 1 addition & 1 deletion src/include/Logger/LogLevel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ enum class LogLevel { Any = 000, Info = 100, Debug = 200, Warning = 300, Error =

std::string LevelToText(LogLevel level);

} // namespace Logging
} // namespace Logging
2 changes: 1 addition & 1 deletion src/include/Logger/LogOutputConsole.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ class LogOutputConsole : public ILogOutput {
void Write(const LogEntry& entry) override;
};

} // namespace Logging
} // namespace Logging
19 changes: 15 additions & 4 deletions src/include/Logger/LogOutputFile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,23 @@
#include "Logger/ILogOutput.hpp"
#include "Logger/LogEntry.hpp"

#include <filesystem>
#include <mutex>
#include <string>
#include <vector>

namespace Logging {

//! Get the default logfile output directory. Including a subdirectory for the application.
/*! \returns
* Windows: "%FOLDERID_LocalAppData%/<appName>/logs"
* MacOS: "%HOME%/Library/Logs/<appName>"
* Linux/Unix: "%XDG_STATE_HOME%/<appName>/logs" else "%HOME%/.local/state/<appName>/logs"
* Fallback: "<CurrentAppPath>/logs"
*/
std::filesystem::path GetDefaultLogDir(const std::string& appName);


class LogOutputFile : public ILogOutput {
public:
//! The current log file is always the one mentioned in 'filePath'.
Expand All @@ -32,9 +43,9 @@ class LogOutputFile : public ILogOutput {
void RotateFile();

private:
std::string m_filePath; //!< Path to the log file.
std::uintmax_t m_maxFileSize; //!< Maximum size of a logfile before starting a new file.
std::mutex m_writeLock; //!< Lock so file is only opened on one thread.
std::string m_filePath; //!< Path to the log file.
std::uintmax_t m_maxFileSize; //!< Maximum size of a logfile before starting a new file.
std::mutex m_writeLock; //!< Lock so file is only opened on one thread.
};

} // namespace Logging
} // namespace Logging
2 changes: 1 addition & 1 deletion src/include/Logger/LogOutputMock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ class LogOutputMock : public ILogOutput {
std::vector<LogEntry> m_logEntries;
};

} // namespace Logging
} // namespace Logging
6 changes: 3 additions & 3 deletions src/include/Logger/Logger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class Logger {
void Log(LogLevel level, const std::string& text);

private:
LogConfig& m_config; //!< Configuration by which this logger object should adhere.
std::vector<LogEntry> m_entries; //!< List of log entries received.
LogConfig& m_config; //!< Configuration by which this logger object should adhere.
std::vector<LogEntry> m_entries; //!< List of log entries received.
};

} // namespace Logging
} // namespace Logging
2 changes: 1 addition & 1 deletion src/include/Logger/Profiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ class Profiler {
std::chrono::time_point<std::chrono::steady_clock> m_lastTime;
};

} // namespace Logging
} // namespace Logging
Loading
Loading