JuniorКодРедкоЕщё не отвечали
Напишите класс Logger, который логирует в консоль или файл
Реализуйте Logger, который пишет строки с меткой времени и уровнем в консоль или в файл.
Требования:
- принимайте
std::ostream&по ссылке в конструкторе, чтобы вызывающий мог передатьstd::cout,std::ofstreamили любойostream— не храните по значению - поддержите уровни
INFO,WARN,ERRORи добавляйте метку времени к каждой строке - сделайте класс некопируемым (ссылку на поток нельзя копировать/переназначить)
- сбрасывайте буфер после каждой строки, чтобы сообщения не терялись при крэше
enum class LogLevel { INFO, WARN, ERROR };
class Logger {
public:
explicit Logger(std::ostream& out);
void log(LogLevel level, std::string_view msg);
void info(std::string_view msg);
void warn(std::string_view msg);
void error(std::string_view msg);
// ваш код здесь
};
Допишите реализацию.
Logger хранит std::ostream& и пишет строки с timestamp и уровнем. Принимать поток по ссылке позволяет передать std::cout, std::ofstream или любой ostream. Класс должен быть некопируемым, поскольку потоки не копируются.
- ✗Хранить поток по значению вместо ссылки — потоки не копируются
- ✗Не сбрасывать буфер после каждой строки — последние сообщения могут быть потеряны при крэше
- ✗Игнорировать потокобезопасность — два потока, пишущих одновременно, дают перемешанный вывод; используйте
std::mutex
- →Как добавить уровни логирования, чтобы
DEBUG-сообщения фильтровались в production? - →Как сделать Logger потокобезопасным с минимальной конкуренцией за блокировку?
Оглавление
Задача
Реализуйте класс Logger, который:
- принимает
std::ostream&в конструкторе (std::coutили открытыйstd::ofstream) - поддерживает уровни
INFO,WARN,ERROR - добавляет метку времени к каждой строке
- является некопируемым
Решение
#include <chrono>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string_view>
#include <cassert>
enum class LogLevel { INFO, WARN, ERROR };
class Logger {
public:
explicit Logger(std::ostream& out) : out_(out) {}
// Non-copyable (stream reference cannot be reseated)
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
void log(LogLevel level, std::string_view msg) {
out_ << timestamp() << " [" << levelStr(level) << "] " << msg << '\n';
out_.flush(); // ensure nothing is lost on crash
}
void info (std::string_view msg) { log(LogLevel::INFO, msg); }
void warn (std::string_view msg) { log(LogLevel::WARN, msg); }
void error(std::string_view msg) { log(LogLevel::ERROR, msg); }
private:
std::ostream& out_;
static std::string timestamp() {
using namespace std::chrono;
auto now = system_clock::now();
auto time = system_clock::to_time_t(now);
std::ostringstream ss;
ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S");
return ss.str();
}
static const char* levelStr(LogLevel l) {
switch (l) {
case LogLevel::INFO: return "INFO ";
case LogLevel::WARN: return "WARN ";
case LogLevel::ERROR: return "ERROR";
}
return "?????";
}
};
// --- usage ---
int main() {
// Log to console
Logger consoleLog(std::cout);
consoleLog.info("server started");
consoleLog.warn("high memory usage");
consoleLog.error("connection refused");
// Log to file
std::ofstream f("app.log");
assert(f.is_open());
Logger fileLog(f);
fileLog.info("writing to file");
return 0;
}
Ключевые моменты
| Аспект | Решение |
|---|---|
| Хранение потока | std::ostream& — работает и с cout, и с ofstream |
| Запрет копирования | = delete у copy ctor и copy assign |
| Сброс буфера | flush() после каждой строки |
| Временная метка | std::put_time + std::localtime |
| Потокобезопасность | В данном решении отсутствует; для многопоточного кода добавьте std::mutex |
Оглавление