Skip to content

Commit

Permalink
feat-logger-update (#1173)
Browse files Browse the repository at this point in the history
  • Loading branch information
nguyenhoangthuan99 authored Sep 10, 2024
1 parent e180fc6 commit f25f6dd
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 8 deletions.
2 changes: 2 additions & 0 deletions engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ if(DEFINED CMAKE_JS_INC)

add_library(${PROJECT_NAME} SHARED addon.cc
${CMAKE_CURRENT_SOURCE_DIR}/utils/cpuid/cpu_info.cc
${CMAKE_CURRENT_SOURCE_DIR}/utils/file_logger.cc
${CMAKE_JS_SRC}
)

Expand All @@ -131,6 +132,7 @@ if(DEFINED CMAKE_JS_INC)
else() # Official build
add_executable(${PROJECT_NAME} main.cc
${CMAKE_CURRENT_SOURCE_DIR}/utils/cpuid/cpu_info.cc
${CMAKE_CURRENT_SOURCE_DIR}/utils/file_logger.cc
)
endif()

Expand Down
25 changes: 20 additions & 5 deletions engine/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "utils/archive_utils.h"
#include "utils/cortex_utils.h"
#include "utils/dylib.h"
#include "utils/file_logger.h"
#include "utils/file_manager_utils.h"
#include "utils/logging_utils.h"

Expand All @@ -29,16 +30,18 @@ void RunServer() {
LOG_INFO << "Host: " << config.apiServerHost << " Port: " << config.apiServerPort << "\n";

// Create logs/ folder and setup log to file
std::filesystem::create_directory(cortex_utils::logs_folder);
trantor::AsyncFileLogger asyncFileLogger;
asyncFileLogger.setFileName(cortex_utils::logs_base_name);
std::filesystem::create_directory(config.logFolderPath + "/" +
cortex_utils::logs_folder);
trantor::FileLogger asyncFileLogger;
asyncFileLogger.setFileName(config.logFolderPath + "/" +
cortex_utils::logs_base_name);
asyncFileLogger.setMaxLines(config.maxLogLines); // Keep last 100000 lines
asyncFileLogger.startLogging();
trantor::Logger::setOutputFunction(
[&](const char* msg, const uint64_t len) {
asyncFileLogger.output(msg, len);
asyncFileLogger.output_(msg, len);
},
[&]() { asyncFileLogger.flush(); });
asyncFileLogger.setFileSizeLimit(cortex_utils::log_file_size_limit);
// Number of cortex.cpp threads
// if (argc > 1) {
// thread_num = std::atoi(argv[1]);
Expand Down Expand Up @@ -154,6 +157,18 @@ int main(int argc, char* argv[]) {
RunServer();
return 0;
} else {
auto config = file_manager_utils::GetCortexConfig();
trantor::FileLogger asyncFileLogger;
asyncFileLogger.setFileName(config.logFolderPath + "/" +
cortex_utils::logs_cli_base_name);
asyncFileLogger.setMaxLines(
config.maxLogLines); // Keep last 100000 lines
asyncFileLogger.startLogging();
trantor::Logger::setOutputFunction(
[&](const char* msg, const uint64_t len) {
asyncFileLogger.output_(msg, len);
},
[&]() { asyncFileLogger.flush(); });
CommandLineParser clp;
clp.SetupCommand(argc, argv);
return 0;
Expand Down
13 changes: 13 additions & 0 deletions engine/utils/config_yaml_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@

namespace config_yaml_utils {
struct CortexConfig {
std::string logFolderPath;
std::string dataFolderPath;
int maxLogLines;
std::string apiServerHost;
std::string apiServerPort;
};

const std::string kCortexFolderName = "cortexcpp";
const std::string kDefaultHost{"127.0.0.1"};
const std::string kDefaultPort{"3928"};
const int kDefaultMaxLines{100000};

inline void DumpYamlConfig(const CortexConfig& config,
const std::string& path) {
Expand All @@ -27,7 +30,9 @@ inline void DumpYamlConfig(const CortexConfig& config,
throw std::runtime_error("Failed to open output file.");
}
YAML::Node node;
node["logFolderPath"] = config.logFolderPath;
node["dataFolderPath"] = config.dataFolderPath;
node["maxLogLines"] = config.maxLogLines;
node["apiServerHost"] = config.apiServerHost;
node["apiServerPort"] = config.apiServerPort;

Expand All @@ -48,8 +53,16 @@ inline CortexConfig FromYaml(const std::string& path,

try {
auto node = YAML::LoadFile(config_file_path.string());
int max_lines;
if (!node["maxLogLines"]) {
max_lines = kDefaultMaxLines;
} else {
max_lines = node["maxLogLines"].as<int>();
}
CortexConfig config = {
.logFolderPath = node["logFolderPath"].as<std::string>(),
.dataFolderPath = node["dataFolderPath"].as<std::string>(),
.maxLogLines = max_lines,
.apiServerHost = node["apiServerHost"].as<std::string>(),
.apiServerPort = node["apiServerPort"].as<std::string>(),
};
Expand Down
4 changes: 2 additions & 2 deletions engine/utils/cortex_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ constexpr static auto kTensorrtLlmPath = "/engines/cortex.tensorrt-llm";

inline std::string models_folder = "./models";
inline std::string logs_folder = "./logs";
inline std::string logs_base_name = "./logs/cortex";
inline size_t log_file_size_limit = 20000000; // ~20 mb
inline std::string logs_base_name = "./logs/cortex.log";
inline std::string logs_cli_base_name = "./logs/cortex-cli.log";

inline std::string extractBase64(const std::string& input) {
std::regex pattern("base64,(.*)");
Expand Down
175 changes: 175 additions & 0 deletions engine/utils/file_logger.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
#include "file_logger.h"
#include <algorithm>
#include <iostream>
#include <sstream>

#ifdef _WIN32
#include <io.h>
#define ftruncate _chsize
#else
#include <unistd.h>
#endif
#include <string.h>

using namespace trantor;

FileLogger::FileLogger() : AsyncFileLogger() {}

FileLogger::~FileLogger() = default;

void FileLogger::output_(const char* msg, const uint64_t len) {
if (!circular_log_file_ptr_) {
circular_log_file_ptr_ =
std::make_unique<CircularLogFile>(fileBaseName_, max_lines_);
}
circular_log_file_ptr_->writeLog(msg, len);
}

FileLogger::CircularLogFile::CircularLogFile(const std::string& fileName,
uint64_t maxLines)
: max_lines_(maxLines), file_name_(fileName) {
std::lock_guard<std::mutex> lock(mutex_);
OpenFile();
LoadExistingLines();
TruncateFileIfNeeded();
}

FileLogger::CircularLogFile::~CircularLogFile() {
std::lock_guard<std::mutex> lock(mutex_);
CloseFile();
}
void FileLogger::CircularLogFile::writeLog(const char* logLine,
const uint64_t len) {
std::lock_guard<std::mutex> lock(mutex_);
if (!fp_)
return;

std::string logString(logLine, len);
std::istringstream iss(logString);
std::string line;
while (std::getline(iss, line)) {
if (lineBuffer_.size() >= max_lines_) {
lineBuffer_.pop_front();
}
lineBuffer_.push_back(line);
AppendToFile(line + "\n");
++linesWrittenSinceLastTruncate_;
if (linesWrittenSinceLastTruncate_.load() >= TRUNCATE_CHECK_INTERVAL) {

TruncateFileIfNeeded();
}
}
}
void FileLogger::CircularLogFile::flush() {
std::lock_guard<std::mutex> lock(mutex_);
if (fp_) {
fflush(fp_);
}
}

void FileLogger::CircularLogFile::TruncateFileIfNeeded() {
// std::cout<<"Truncating file "<< totalLines_ <<std::endl;
if (!fp_ || lineBuffer_.size() < max_lines_)
return;

// Close the current file
fclose(fp_);
fp_ = nullptr;

// Open a temporary file for writing
std::string tempFileName = file_name_ + ".temp";
FILE* tempFile = fopen(tempFileName.c_str(), "w");
if (!tempFile) {

std::cout << "Error opening temporary file for truncation: "
<< strerror(errno) << std::endl;
OpenFile(); // Reopen the original file
return;
}

// Write only the last max_lines_ lines to the temporary file
size_t startIndex =
lineBuffer_.size() > max_lines_ ? lineBuffer_.size() - max_lines_ : 0;

for (size_t i = startIndex; i < lineBuffer_.size(); ++i) {
fprintf(tempFile, "%s\n", lineBuffer_[i].c_str());
}

fclose(tempFile);

// Replace the original file with the temporary file
if (std::rename(tempFileName.c_str(), file_name_.c_str()) != 0) {
std::cout << "Error replacing original file with truncated file: "
<< strerror(errno) << std::endl;
std::remove(tempFileName.c_str()); // Clean up the temporary file
}
// else {
// totalLines_.store(lineBuffer_.size() > max_lines_ ? max_lines_
// : lineBuffer_.size());
// }

// Reopen the file
OpenFile();
// LoadExistingLines();
linesWrittenSinceLastTruncate_.store(0);
}

void FileLogger::CircularLogFile::OpenFile() {
#ifdef _WIN32
auto wFileName = utils::toNativePath(file_name_);
fp_ = _wfopen(wFileName.c_str(), L"r+");
#else
fp_ = fopen(file_name_.c_str(), "r+");
#endif

if (!fp_) {
// If file doesn't exist, create it
#ifdef _WIN32
fp_ = _wfopen(wFileName.c_str(), L"w+");
#else
fp_ = fopen(file_name_.c_str(), "w+");
#endif

if (!fp_) {
std::cerr << "Error opening file: " << strerror(errno) << std::endl;
}
}
}
void FileLogger::CircularLogFile::LoadExistingLines() {
if (!fp_)
return;

// Move to the beginning of the file
fseek(fp_, 0, SEEK_SET);

lineBuffer_.clear();

std::string line;
char buffer[4096];
while (fgets(buffer, sizeof(buffer), fp_) != nullptr) {
line = buffer;
if (!line.empty() && line.back() == '\n') {
line.pop_back(); // Remove trailing newline
}
if (lineBuffer_.size() >= max_lines_) {
lineBuffer_.pop_front();
}
lineBuffer_.push_back(line);
}

// Move back to the end of the file for appending
fseek(fp_, 0, SEEK_END);
}
void FileLogger::CircularLogFile::AppendToFile(const std::string& line) {
if (fp_) {
fwrite(line.c_str(), 1, line.length(), fp_);
fflush(fp_);
}
}

void FileLogger::CircularLogFile::CloseFile() {
if (fp_) {
fclose(fp_);
fp_ = nullptr;
}
}
72 changes: 72 additions & 0 deletions engine/utils/file_logger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#pragma once

#include <trantor/utils/AsyncFileLogger.h>
#include <trantor/utils/Utilities.h>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <deque>
#include <mutex>

#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif

namespace trantor {

class TRANTOR_EXPORT FileLogger : public AsyncFileLogger {
public:
FileLogger();
~FileLogger();

/**
* @brief Set the maximum number of lines to keep in the log file.
*
* @param maxLines
*/
void setMaxLines(uint64_t maxLines) { max_lines_ = maxLines; }

/**
* @brief Set the log file name.
*
* @param fileName The full name of the log file.
*/
void setFileName(const std::string& fileName) {
filePath_ = "./";
fileBaseName_ = fileName;
fileExtName_ = "";
}
void output_(const char* msg, const uint64_t len);

protected:
class CircularLogFile {
public:
CircularLogFile(const std::string& fileName, uint64_t maxLines);
~CircularLogFile();

void writeLog(const char* logLine, const uint64_t len);
void flush();
uint64_t getLength() const { return lineBuffer_.size(); }

private:
FILE* fp_{nullptr};
uint64_t max_lines_;
std::string file_name_;
std::deque<std::string> lineBuffer_;
std::atomic<int> linesWrittenSinceLastTruncate_{0};
static const uint64_t TRUNCATE_CHECK_INTERVAL = 1000;
mutable std::mutex mutex_;

void LoadExistingLines();
void TruncateFileIfNeeded();
void AppendToFile(const std::string& line);
void OpenFile();
void CloseFile();
};
std::unique_ptr<CircularLogFile> circular_log_file_ptr_;
uint64_t max_lines_{100000}; // Default to 100000 lines
};

} // namespace trantor
Loading

0 comments on commit f25f6dd

Please sign in to comment.