Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat-logger-update #1173

Merged
merged 9 commits into from
Sep 10, 2024
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
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 + "/" +
nguyenhoangthuan99 marked this conversation as resolved.
Show resolved Hide resolved
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) {
nguyenhoangthuan99 marked this conversation as resolved.
Show resolved Hide resolved
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 {
nguyenhoangthuan99 marked this conversation as resolved.
Show resolved Hide resolved
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
Loading