Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ac9373c2c9 | |||
| f610505e90 | |||
| 6247442253 |
@@ -17,8 +17,8 @@ RESULT_TEST_BIN := $(BUILD_DIR)/result_test
|
|||||||
LOGGER_TEST_BIN := $(BUILD_DIR)/logger_test
|
LOGGER_TEST_BIN := $(BUILD_DIR)/logger_test
|
||||||
SCOPED_FILE_TEST_BIN := $(BUILD_DIR)/scoped_file_test
|
SCOPED_FILE_TEST_BIN := $(BUILD_DIR)/scoped_file_test
|
||||||
|
|
||||||
RESULT_TEST_SRC := tests/app/core/result_test.cpp
|
RESULT_TEST_SRC := tests/core/result_test.cpp
|
||||||
LOGGER_TEST_SRC := tests/app/core/logger_test.cpp
|
LOGGER_TEST_SRC := tests/core/logger_test.cpp
|
||||||
SCOPED_FILE_TEST_SRC := tests/helpers/scoped_file_test.cpp
|
SCOPED_FILE_TEST_SRC := tests/helpers/scoped_file_test.cpp
|
||||||
|
|
||||||
LOGGER_SRC := logger/src/logger.cpp
|
LOGGER_SRC := logger/src/logger.cpp
|
||||||
|
|||||||
@@ -1,7 +1,75 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace logger {
|
namespace logger {
|
||||||
|
|
||||||
enum class LogLevel { Debug = 0, Info = 1, Error = 2 };
|
/**
|
||||||
|
* @brief Представляет уровень логирования.
|
||||||
|
*
|
||||||
|
* Экземпляры класса создаются только через статические фабричные методы.
|
||||||
|
*/
|
||||||
|
class LogLevel {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Создает уровень Debug.
|
||||||
|
*/
|
||||||
|
static LogLevel debug() { return LogLevel(Type::Debug); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Создает уровень Info.
|
||||||
|
*/
|
||||||
|
static LogLevel info() { return LogLevel(Type::Info); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Создает уровень Error.
|
||||||
|
*/
|
||||||
|
static LogLevel error() { return LogLevel(Type::Error); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Возвращает строковое представление уровня.
|
||||||
|
*
|
||||||
|
* @return "DEBUG", "INFO" или "ERROR".
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
std::string_view toString() const {
|
||||||
|
switch (type_) {
|
||||||
|
case Type::Debug:
|
||||||
|
return "DEBUG";
|
||||||
|
|
||||||
|
case Type::Info:
|
||||||
|
return "INFO";
|
||||||
|
|
||||||
|
case Type::Error:
|
||||||
|
return "ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Сравнивает два уровня логирования.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool operator==(const LogLevel &other) const {
|
||||||
|
return type_ == other.type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Сравнивает два уровня логирования.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool operator!=(const LogLevel &other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class Type { Debug, Info, Error };
|
||||||
|
|
||||||
|
explicit LogLevel(Type type) : type_(type) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type type_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace logger
|
} // namespace logger
|
||||||
|
|||||||
@@ -58,18 +58,33 @@ public:
|
|||||||
Logger &operator=(Logger &&) = delete;
|
Logger &operator=(Logger &&) = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Записывает сообщение в журнал.
|
* @brief Записывает сообщение в журнал с указанным уровнем логирования.
|
||||||
*
|
*
|
||||||
* В случае успешной записи возвращается успешный Status.
|
* В случае успешной записи возвращается успешный Status.
|
||||||
* При ошибке открытия файла или записи возвращается Status
|
* При ошибке открытия файла или записи возвращается Status
|
||||||
* с описанием ошибки.
|
* с описанием ошибки.
|
||||||
*
|
*
|
||||||
* @param level Уровень важности сообщения.
|
* @param level Уровень логирования сообщения.
|
||||||
* @param message Текст сообщения.
|
* @param message Текст сообщения.
|
||||||
*
|
*
|
||||||
* @return Статус выполнения операции.
|
* @return Статус выполнения операции.
|
||||||
*/
|
*/
|
||||||
core::Status writeLog(LogLevel level, const std::string &message);
|
core::Status writeMessage(LogLevel level, const std::string &message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Записывает сообщение в журнал с уровнем логирования по умолчанию.
|
||||||
|
*
|
||||||
|
* Метод является удобной перегрузкой и эквивалентен вызову:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* writeMessage(getLogLevel(), message);
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @param message Текст сообщения.
|
||||||
|
*
|
||||||
|
* @return Статус выполнения операции.
|
||||||
|
*/
|
||||||
|
core::Status writeMessage(const std::string &message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Создаёт новый Logger с изменённым уровнем логирования.
|
* @brief Создаёт новый Logger с изменённым уровнем логирования.
|
||||||
@@ -96,14 +111,14 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Возвращает текущий уровень логирования.
|
* @brief Возвращает текущий уровень логирования.
|
||||||
*
|
*
|
||||||
* @return Уровень логирования.
|
* @return Уровень логирования по умолчанию.
|
||||||
*/
|
*/
|
||||||
LogLevel getLogLevel() const;
|
LogLevel getLogLevel() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Возвращает имя файла журнала.
|
* @brief Возвращает имя файла журнала.
|
||||||
*
|
*
|
||||||
* @return Имя файла.
|
* @return Имя файла журнала.
|
||||||
*/
|
*/
|
||||||
const std::string &getFileName() const;
|
const std::string &getFileName() const;
|
||||||
|
|
||||||
|
|||||||
+19
-4
@@ -1,7 +1,7 @@
|
|||||||
// logger.cpp
|
|
||||||
|
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
namespace logger {
|
namespace logger {
|
||||||
|
|
||||||
Logger::Logger(const std::string &fileName, LogLevel defaultLevel)
|
Logger::Logger(const std::string &fileName, LogLevel defaultLevel)
|
||||||
@@ -9,11 +9,26 @@ Logger::Logger(const std::string &fileName, LogLevel defaultLevel)
|
|||||||
|
|
||||||
Logger::~Logger() = default;
|
Logger::~Logger() = default;
|
||||||
|
|
||||||
core::Status Logger::writeLog(LogLevel /*level*/,
|
core::Status Logger::writeMessage(LogLevel level, const std::string &message) {
|
||||||
const std::string & /*message*/) {
|
std::ofstream stream(fileName_, std::ios::app);
|
||||||
|
|
||||||
|
if (!stream.is_open()) {
|
||||||
|
return core::Status::Failure("Unable to open log file: " + fileName_);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream << "[" << level.toString() << "] " << message << '\n';
|
||||||
|
|
||||||
|
if (!stream.good()) {
|
||||||
|
return core::Status::Failure("Failed to write to log file: " + fileName_);
|
||||||
|
}
|
||||||
|
|
||||||
return core::Status::Success(true);
|
return core::Status::Success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core::Status Logger::writeMessage(const std::string &message) {
|
||||||
|
return writeMessage(defaultLevel_, message);
|
||||||
|
}
|
||||||
|
|
||||||
Logger Logger::withLogLevel(LogLevel level) const {
|
Logger Logger::withLogLevel(LogLevel level) const {
|
||||||
return Logger(fileName_, level);
|
return Logger(fileName_, level);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,30 +6,32 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using namespace logger;
|
||||||
|
|
||||||
void testLoggerCreation() {
|
void testLoggerCreation() {
|
||||||
logger::Logger logger("test.log", logger::LogLevel::Info);
|
Logger logger("test.log", LogLevel::info());
|
||||||
|
|
||||||
assert(logger.getFileName() == "test.log");
|
assert(logger.getFileName() == "test.log");
|
||||||
assert(logger.getLogLevel() == logger::LogLevel::Info);
|
assert(logger.getLogLevel() == LogLevel::info());
|
||||||
}
|
}
|
||||||
|
|
||||||
void testWithLogLevel() {
|
void testWithLogLevel() {
|
||||||
logger::Logger logger("test.log", logger::LogLevel::Info);
|
Logger logger("test.log", LogLevel::info());
|
||||||
|
|
||||||
auto debugLogger = logger.withLogLevel(logger::LogLevel::Debug);
|
auto debugLogger = logger.withLogLevel(LogLevel::debug());
|
||||||
|
|
||||||
// Исходный объект не изменился
|
// Исходный объект не изменился
|
||||||
assert(logger.getLogLevel() == logger::LogLevel::Info);
|
assert(logger.getLogLevel() == LogLevel::info());
|
||||||
|
|
||||||
// Новый объект получил новый уровень
|
// Новый объект получил новый уровень
|
||||||
assert(debugLogger.getLogLevel() == logger::LogLevel::Debug);
|
assert(debugLogger.getLogLevel() == LogLevel::debug());
|
||||||
|
|
||||||
// Имя файла сохранилось
|
// Имя файла сохранилось
|
||||||
assert(debugLogger.getFileName() == "test.log");
|
assert(debugLogger.getFileName() == "test.log");
|
||||||
}
|
}
|
||||||
|
|
||||||
void testWithFileName() {
|
void testWithFileName() {
|
||||||
logger::Logger logger("old.log", logger::LogLevel::Info);
|
Logger logger("old.log", LogLevel::info());
|
||||||
|
|
||||||
auto newLogger = logger.withFileName("new.log");
|
auto newLogger = logger.withFileName("new.log");
|
||||||
|
|
||||||
@@ -40,15 +42,15 @@ void testWithFileName() {
|
|||||||
assert(newLogger.getFileName() == "new.log");
|
assert(newLogger.getFileName() == "new.log");
|
||||||
|
|
||||||
// Уровень сохранился
|
// Уровень сохранился
|
||||||
assert(newLogger.getLogLevel() == logger::LogLevel::Info);
|
assert(newLogger.getLogLevel() == LogLevel::info());
|
||||||
}
|
}
|
||||||
|
|
||||||
void testWriteLogSuccess() {
|
void testWriteLogSuccess() {
|
||||||
const std::string fileName = "logger_test.log";
|
const std::string fileName = "logger_test.log";
|
||||||
|
|
||||||
logger::Logger logger(fileName, logger::LogLevel::Info);
|
Logger logger(fileName, LogLevel::info());
|
||||||
|
|
||||||
auto result = logger.writeLog(logger::LogLevel::Info, "Application started");
|
auto result = logger.writeMessage(LogLevel::info(), "Application started");
|
||||||
|
|
||||||
assert(result.isSuccess());
|
assert(result.isSuccess());
|
||||||
assert(result.getValue());
|
assert(result.getValue());
|
||||||
@@ -68,9 +70,9 @@ void testWriteLogSuccess() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void testWriteLogFailure() {
|
void testWriteLogFailure() {
|
||||||
logger::Logger logger("/invalid/path/logger.log", logger::LogLevel::Info);
|
Logger logger("/invalid/path/logger.log", LogLevel::info());
|
||||||
|
|
||||||
auto result = logger.writeLog(logger::LogLevel::Info, "message");
|
auto result = logger.writeMessage(LogLevel::info(), "message");
|
||||||
|
|
||||||
assert(result.isFailure());
|
assert(result.isFailure());
|
||||||
assert(!result.getError().empty());
|
assert(!result.getError().empty());
|
||||||
@@ -79,11 +81,11 @@ void testWriteLogFailure() {
|
|||||||
void testMultipleWrites() {
|
void testMultipleWrites() {
|
||||||
const std::string fileName = "multiple.log";
|
const std::string fileName = "multiple.log";
|
||||||
|
|
||||||
logger::Logger logger(fileName, logger::LogLevel::Info);
|
Logger logger(fileName, LogLevel::info());
|
||||||
|
|
||||||
assert(logger.writeLog(logger::LogLevel::Info, "first").isSuccess());
|
assert(logger.writeMessage(LogLevel::info(), "first").isSuccess());
|
||||||
|
|
||||||
assert(logger.writeLog(logger::LogLevel::Error, "second").isSuccess());
|
assert(logger.writeMessage(LogLevel::error(), "second").isSuccess());
|
||||||
|
|
||||||
std::ifstream file(fileName);
|
std::ifstream file(fileName);
|
||||||
|
|
||||||
@@ -6,36 +6,38 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using namespace core;
|
||||||
|
|
||||||
void testSuccessCreation() {
|
void testSuccessCreation() {
|
||||||
auto result = core::Result<int>::Success(42);
|
auto result = Result<int>::Success(42);
|
||||||
|
|
||||||
assert(result.isSuccess());
|
assert(result.isSuccess());
|
||||||
assert(result.getValue() == 42);
|
assert(result.getValue() == 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testFailureCreation() {
|
void testFailureCreation() {
|
||||||
auto result = core::Result<int>::Failure("Invalid value");
|
auto result = Result<int>::Failure("Invalid value");
|
||||||
|
|
||||||
assert(result.isFailure());
|
assert(result.isFailure());
|
||||||
assert(result.getError() == "Invalid value");
|
assert(result.getError() == "Invalid value");
|
||||||
}
|
}
|
||||||
|
|
||||||
void testStatusSuccess() {
|
void testStatusSuccess() {
|
||||||
auto status = core::Status::Success(true);
|
auto status = Status::Success(true);
|
||||||
|
|
||||||
assert(status.isSuccess());
|
assert(status.isSuccess());
|
||||||
assert(status.getValue());
|
assert(status.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
void testStatusFailure() {
|
void testStatusFailure() {
|
||||||
auto status = core::Status::Failure("File not found");
|
auto status = Status::Failure("File not found");
|
||||||
|
|
||||||
assert(status.isFailure());
|
assert(status.isFailure());
|
||||||
assert(status.getError() == "File not found");
|
assert(status.getError() == "File not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
void testMoveConstruction() {
|
void testMoveConstruction() {
|
||||||
auto source = core::Result<std::string>::Success("hello");
|
auto source = Result<std::string>::Success("hello");
|
||||||
|
|
||||||
auto moved = std::move(source);
|
auto moved = std::move(source);
|
||||||
|
|
||||||
@@ -44,8 +46,8 @@ void testMoveConstruction() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void testMoveAssignment() {
|
void testMoveAssignment() {
|
||||||
auto first = core::Result<int>::Success(10);
|
auto first = Result<int>::Success(10);
|
||||||
auto second = core::Result<int>::Failure("error");
|
auto second = Result<int>::Failure("error");
|
||||||
|
|
||||||
second = std::move(first);
|
second = std::move(first);
|
||||||
|
|
||||||
@@ -59,7 +61,7 @@ void testDifferentTypes() {
|
|||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto result = core::Result<User>::Success(User{1, "Alex"});
|
auto result = Result<User>::Success(User{1, "Alex"});
|
||||||
|
|
||||||
assert(result.isSuccess());
|
assert(result.isSuccess());
|
||||||
assert(result.getValue().id == 1);
|
assert(result.getValue().id == 1);
|
||||||
@@ -67,7 +69,7 @@ void testDifferentTypes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void testValueModification() {
|
void testValueModification() {
|
||||||
auto result = core::Result<int>::Success(10);
|
auto result = Result<int>::Success(10);
|
||||||
|
|
||||||
result.getValue() = 20;
|
result.getValue() = 20;
|
||||||
|
|
||||||
@@ -75,7 +77,7 @@ void testValueModification() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void testErrorModification() {
|
void testErrorModification() {
|
||||||
auto result = core::Result<int>::Failure("old error");
|
auto result = Result<int>::Failure("old error");
|
||||||
|
|
||||||
result.getError() = "new error";
|
result.getError() = "new error";
|
||||||
|
|
||||||
@@ -85,7 +87,7 @@ void testErrorModification() {
|
|||||||
void testBasicResultWithCustomError() {
|
void testBasicResultWithCustomError() {
|
||||||
enum class ErrorCode { NotFound, PermissionDenied };
|
enum class ErrorCode { NotFound, PermissionDenied };
|
||||||
|
|
||||||
using CustomResult = core::BasicResult<int, ErrorCode>;
|
using CustomResult = BasicResult<int, ErrorCode>;
|
||||||
|
|
||||||
auto result = CustomResult::Failure(ErrorCode::PermissionDenied);
|
auto result = CustomResult::Failure(ErrorCode::PermissionDenied);
|
||||||
|
|
||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
namespace helpers {
|
||||||
|
|
||||||
class ScopedFile {
|
class ScopedFile {
|
||||||
public:
|
public:
|
||||||
explicit ScopedFile(std::string fileName) : fileName_(std::move(fileName)) {}
|
explicit ScopedFile(std::string fileName) : fileName_(std::move(fileName)) {}
|
||||||
@@ -25,3 +27,5 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::string fileName_;
|
std::string fileName_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace helpers
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using namespace helpers;
|
||||||
|
|
||||||
void testFileRemovedAfterScope() {
|
void testFileRemovedAfterScope() {
|
||||||
const std::string fileName = "scoped_file_test.log";
|
const std::string fileName = "scoped_file_test.log";
|
||||||
|
|
||||||
|
|||||||
@@ -8,33 +8,35 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using namespace logger;
|
||||||
|
|
||||||
void testLoggerCreation() {
|
void testLoggerCreation() {
|
||||||
logger::Logger logger("test.log", logger::LogLevel::Info);
|
Logger logger("test.log", LogLevel::info());
|
||||||
|
|
||||||
assert(logger.getFileName() == "test.log");
|
assert(logger.getFileName() == "test.log");
|
||||||
assert(logger.getLogLevel() == logger::LogLevel::Info);
|
assert(logger.getLogLevel() == LogLevel::info());
|
||||||
}
|
}
|
||||||
|
|
||||||
void testWithLogLevel() {
|
void testWithLogLevel() {
|
||||||
logger::Logger logger("test.log", logger::LogLevel::Info);
|
Logger logger("test.log", LogLevel::info());
|
||||||
|
|
||||||
auto debugLogger = logger.withLogLevel(logger::LogLevel::Debug);
|
auto debugLogger = logger.withLogLevel(LogLevel::debug());
|
||||||
|
|
||||||
assert(logger.getLogLevel() == logger::LogLevel::Info);
|
assert(logger.getLogLevel() == LogLevel::info());
|
||||||
assert(debugLogger.getLogLevel() == logger::LogLevel::Debug);
|
assert(debugLogger.getLogLevel() == LogLevel::debug());
|
||||||
|
|
||||||
assert(debugLogger.getFileName() == "test.log");
|
assert(debugLogger.getFileName() == "test.log");
|
||||||
}
|
}
|
||||||
|
|
||||||
void testWithFileName() {
|
void testWithFileName() {
|
||||||
logger::Logger logger("old.log", logger::LogLevel::Info);
|
Logger logger("old.log", LogLevel::info());
|
||||||
|
|
||||||
auto newLogger = logger.withFileName("new.log");
|
auto newLogger = logger.withFileName("new.log");
|
||||||
|
|
||||||
assert(logger.getFileName() == "old.log");
|
assert(logger.getFileName() == "old.log");
|
||||||
assert(newLogger.getFileName() == "new.log");
|
assert(newLogger.getFileName() == "new.log");
|
||||||
|
|
||||||
assert(newLogger.getLogLevel() == logger::LogLevel::Info);
|
assert(newLogger.getLogLevel() == LogLevel::info());
|
||||||
}
|
}
|
||||||
|
|
||||||
void testWriteLogSuccess() {
|
void testWriteLogSuccess() {
|
||||||
@@ -42,9 +44,9 @@ void testWriteLogSuccess() {
|
|||||||
|
|
||||||
file.throwIfExists();
|
file.throwIfExists();
|
||||||
|
|
||||||
logger::Logger logger(file.getFileName(), logger::LogLevel::Info);
|
Logger logger(file.getFileName(), LogLevel::info());
|
||||||
|
|
||||||
auto result = logger.writeLog(logger::LogLevel::Info, "Application started");
|
auto result = logger.writeMessage(LogLevel::info(), "Application started");
|
||||||
|
|
||||||
assert(result.isSuccess());
|
assert(result.isSuccess());
|
||||||
assert(result.getValue());
|
assert(result.getValue());
|
||||||
@@ -66,9 +68,9 @@ void testWriteLogFailure() {
|
|||||||
|
|
||||||
std::filesystem::create_directory(file.getFileName());
|
std::filesystem::create_directory(file.getFileName());
|
||||||
|
|
||||||
logger::Logger logger(file.getFileName(), logger::LogLevel::Info);
|
Logger logger(file.getFileName(), LogLevel::info());
|
||||||
|
|
||||||
auto result = logger.writeLog(logger::LogLevel::Info, "message");
|
auto result = logger.writeMessage(LogLevel::info(), "message");
|
||||||
|
|
||||||
assert(result.isFailure());
|
assert(result.isFailure());
|
||||||
assert(!result.getError().empty());
|
assert(!result.getError().empty());
|
||||||
@@ -81,11 +83,11 @@ void testMultipleWrites() {
|
|||||||
|
|
||||||
file.throwIfExists();
|
file.throwIfExists();
|
||||||
|
|
||||||
logger::Logger logger(file.getFileName(), logger::LogLevel::Info);
|
Logger logger(file.getFileName(), LogLevel::info());
|
||||||
|
|
||||||
auto first = logger.writeLog(logger::LogLevel::Info, "first message");
|
auto first = logger.writeMessage(LogLevel::info(), "first message");
|
||||||
|
|
||||||
auto second = logger.writeLog(logger::LogLevel::Error, "second message");
|
auto second = logger.writeMessage(LogLevel::error(), "second message");
|
||||||
|
|
||||||
assert(first.isSuccess());
|
assert(first.isSuccess());
|
||||||
assert(second.isSuccess());
|
assert(second.isSuccess());
|
||||||
|
|||||||
Reference in New Issue
Block a user