* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
* Description: Logger context.
*/
#include "datasystem/common/log/spdlog/logger_context.h"
#include <cstdlib>
#include <exception>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <limits.h>
#include <unistd.h>
#include <spdlog/async.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include "datasystem/common/log/spdlog/log_severity.h"
namespace datasystem {
constexpr auto LOG_LEVEL_OFF = ds_spdlog::level::off;
static std::vector<std::string> GetLogFiles(const LogParam &logParam)
{
std::vector<std::string> logFiles;
char resolvedPath[PATH_MAX + 1] = { 0 };
if (realpath(logParam.logDir.c_str(), resolvedPath) == nullptr) {
return logFiles;
}
logFiles.reserve(logParam.fileNamePatterns.size());
std::string absoluteLogDir(resolvedPath);
for (const auto &pattern : logParam.fileNamePatterns) {
logFiles.emplace_back(absoluteLogDir + "/" + pattern + ".log");
}
return logFiles;
}
static void FlushLogger(DsLogger logger)
{
if (logger) {
logger->flush();
}
}
static const std::map<std::string, ds_spdlog::level::level_enum> &GetLogLevelMap()
{
static const std::map<std::string, ds_spdlog::level::level_enum> LOG_LEVEL_MAP = {
{ "INFO", ds_spdlog::level::info },
{ "WARNING", ds_spdlog::level::warn },
{ "ERROR", ds_spdlog::level::err },
{ "FATAL", ds_spdlog::level::critical }
};
return LOG_LEVEL_MAP;
}
static ds_spdlog::level::level_enum GetLogLevel(const std::string &level)
{
auto iter = GetLogLevelMap().find(level);
return iter == GetLogLevelMap().end() ? ds_spdlog::level::info : iter->second;
}
LoggerContext::LoggerContext(const GlobalLogParam &globalLogParam) noexcept : globalLogParam_(globalLogParam)
{
ds_spdlog::drop_all();
if (!ds_spdlog::thread_pool()) {
ds_spdlog::init_thread_pool(static_cast<size_t>(globalLogParam_.maxAsyncQueueSize),
static_cast<size_t>(globalLogParam_.asyncThreadCount));
}
ds_spdlog::flush_every(std::chrono::seconds(globalLogParam_.logBufSecs));
}
DsLogger LoggerContext::CreateLogger(const LogParam &logParam)
{
try {
std::vector<ds_spdlog::sink_ptr> sinks{};
std::vector<std::string> logFiles = GetLogFiles(logParam);
for (size_t i = 0; i < logFiles.size(); ++i) {
auto rotatingSink = std::make_shared<ds_spdlog::sinks::rotating_file_sink_mt>(
logFiles[i], logParam.maxSize * log_param::SIZE_MEGA_BYTES, logParam.maxFiles);
const auto log2FileLevel = ToSpdlogLevel(LogSeverity(i % (NUM_SEVERITIES - 1)));
rotatingSink->set_level(log2FileLevel);
(void)sinks.emplace_back(rotatingSink);
}
const auto stderrLogLevel = (logParam.stderrLogLevel != "FATAL")
? GetLogLevel(logParam.stderrLogLevel)
: (logParam.alsoLog2Stderr ? GetLogLevel(logParam.logLevel) : LOG_LEVEL_OFF);
if (stderrLogLevel != LOG_LEVEL_OFF) {
auto errSink = std::make_shared<ds_spdlog::sinks::stderr_color_sink_mt>();
errSink->set_level(stderrLogLevel);
sinks.emplace_back(errSink);
}
std::shared_ptr<ds_spdlog::logger> logger;
if (logParam.logAsync) {
logger = std::make_shared<ds_spdlog::async_logger>(DS_LOGGER_NAME, sinks.begin(), sinks.end(),
ds_spdlog::thread_pool(),
ds_spdlog::async_overflow_policy::overrun_oldest);
} else {
logger = std::make_shared<ds_spdlog::logger>(DS_LOGGER_NAME, sinks.begin(), sinks.end());
}
ds_spdlog::initialize_logger(logger);
logger->set_pattern(logParam.pattern, ds_spdlog::pattern_time_type::local);
const auto logLevel = GetLogLevel(logParam.logLevel);
logger->set_level(logLevel);
if (!logParam.logAsync) {
logger->flush_on(logLevel);
}
return logger;
} catch (std::exception &e) {
std::cerr << "Failed to init logger, error: " << e.what() << std::endl;
return nullptr;
}
}
DsLogger LoggerContext::GetLogger(const std::string &loggerName) const noexcept
{
return ds_spdlog::get(loggerName);
}
DsLogger LoggerContext::GetDefaultLogger() noexcept
{
return ds_spdlog::default_logger();
}
void LoggerContext::DropLogger(const std::string &loggerName) const noexcept
{
ds_spdlog::drop(loggerName);
}
bool LoggerContext::ForceFlush(std::chrono::microseconds) const noexcept
{
ds_spdlog::apply_all(FlushLogger);
return true;
}
}