I did an internship test project (source: https://github.com/SynI20N/VKInfo). I'm lookingLooking for some middle or senior devs to rate it and point out potential problems with my code. Follow up: How would you test my code like people do it in production?
metrics_logger.h:
#ifndef METRICS_LOGGER_H_
#define METRICS_LOGGER_H_
#include <string>
#include <atomic>
#include <thread>
#include "metrics_registry.h"
namespace VkInfo {
/**
* @brief Periodically logs metric values to a file.
*
* MetricsLogger runs in a background thread, collecting metric values from a MetricsRegistry
* at fixed intervals and writing them to a log file with timestamps. After logging, each metric
* is reset. This logger is thread-safe and non-blocking for metric producers.
*/
class VKINFO_API MetricsLogger {
public:
/**
* @brief Constructs a MetricsLogger instance.
*
* @param registry Reference to the MetricsRegistry containing all metrics to log.
* @param filename Name of the file to write log entries to.
* @param interval Logging interval (e.g., every second).
*/
MetricsLogger(MetricsRegistry& registry, const std::string& filename, std::chrono::milliseconds interval);
/**
* @brief Destructor for MetricsLogger.
*
* Ensures the background thread is stopped before destruction.
*/
~MetricsLogger();
/**
* @brief Starts the background logging thread.
*
* Logs metric data to the file at the specified interval.
*/
void start();
/**
* @brief Stops the background logging thread safely.
*/
void stop();
/**
* @brief Retrieves all currently registered metrics from the registry.
*
* @return A vector of shared pointers to IMetric instances.
*/
std::vector<std::shared_ptr<IMetric>> get_all_metrics();
private:
MetricsRegistry& registry_; ///< Reference to the metric registry.
std::string filename_; ///< Output log file name.
std::chrono::milliseconds interval_; ///< Logging frequency.
std::atomic<bool> running_; ///< Indicates if the logger is running.
std::thread worker_; ///< Background thread for logging.
/**
* @brief Main logging loop executed in a background thread.
*
* Gathers metrics, writes them to the file, and resets them.
*/
void run();
/**
* @brief Gets the current system time as a formatted timestamp string.
*
* @return Timestamp in the format "YYYY-MM-DD HH:MM:SS.mmm".
*/
std::string get_current_timestamp() const;
};
} // namespace VkInfo
#endif // METRICS_LOGGER_H_
#include <iostream>
#include <fstream>
#include <sstream>
#include <chrono>
#include <iomanip>
#include "../include/metrics_logger.h"
namespace VkInfo {
MetricsLogger::MetricsLogger(MetricsRegistry& registry,
const std::string& filename,
std::chrono::milliseconds interval)
: registry_(registry),
filename_(filename),
interval_(interval),
running_(false) {}
MetricsLogger::~MetricsLogger() {
stop();
}
void MetricsLogger::start() {
if (running_) return;
running_ = true;
worker_ = std::thread(&MetricsLogger::run, this);
}
void MetricsLogger::stop() {
if (!running_) return;
running_ = false;
if (worker_.joinable()) {
worker_.join();
}
}
std::vector<std::shared_ptr<IMetric>> MetricsLogger::get_all_metrics() {
return registry_.get_all_metrics();
}
std::string MetricsLogger::get_current_timestamp() const {
using namespace std::chrono;
auto now = system_clock::now();
auto time = system_clock::to_time_t(now);
auto ms = duration_cast<milliseconds>(now.time_since_epoch()) % 1000;
std::ostringstream oss;
oss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S")
<< "." << std::setw(3) << std::setfill('0') << ms.count();
return oss.str();
}
void MetricsLogger::run() {
std::ofstream out(filename_, std::ios::app);
while (running_) {
auto now = get_current_timestamp();
std::ostringstream line;
line << now;
for (auto& metric : registry_.get_all_metrics()) {
line << " \"" << metric->get_name() << "\" " << metric->get_value_and_reset();
}
out << line.str() << std::endl;
out.flush();
std::this_thread::sleep_for(interval_);
}
}
} // namespace VkInfo
metrics_registry.h:
#ifndef METRICS_REGISTRY_H_
#define METRICS_REGISTRY_H_
#include <vector>
#include <memory>
#include <mutex>
#include "metric.h"
namespace VkInfo {
/**
* @brief Registry for managing and storing metrics.
*
* MetricsRegistry maintains a thread-safe collection of metrics.
* It allows registration of new metrics and provides access to all registered metrics.
*/
class VKINFO_API MetricsRegistry {
public:
/**
* @brief Registers a new metric.
*
* Thread-safe method to add a metric to the registry.
*
* @param metric Shared pointer to the metric to register.
*/
void register_metric(std::shared_ptr<IMetric> metric);
/**
* @brief Retrieves all registered metrics.
*
* Thread-safe method to get a snapshot of all metrics currently registered.
*
* @return Vector of shared pointers to all registered metrics.
*/
std::vector<std::shared_ptr<IMetric>> get_all_metrics();
private:
std::vector<std::shared_ptr<IMetric>> metrics_; ///< Container holding registered metrics.
std::mutex mutex_; ///< Mutex to protect access to metrics_.
};
} // namespace VkInfo
#endif // METRICS_REGISTRY_H_
#include "../include/metrics_registry.h"
namespace VkInfo {
void MetricsRegistry::register_metric(std::shared_ptr<IMetric> metric) {
std::lock_guard<std::mutex> lock(mutex_);
metrics_.push_back(std::move(metric));
}
std::vector<std::shared_ptr<IMetric>> MetricsRegistry::get_all_metrics() {
std::lock_guard<std::mutex> lock(mutex_);
return metrics_;
}
} // namespace VkInfo