* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include <fstream>
#include <iostream>
#include <mutex>
#include <nlohmann/json.hpp>
#include <sstream>
#include <exception>
#include <securec.h>
#include "mmpa/mmpa_api.h"
#include "dlog_pub.h"
#include "base/err_msg.h"
#include "base/err_mgr.h"
#include "error_manager.h"
#define GE_MODULE_NAME static_cast<int32_t>(GE)
template <typename TI, typename TO>
inline TO* PtrToPtr(TI* const ptr)
{
return reinterpret_cast<TO*>(ptr);
}
template <typename TI, typename TO>
inline const TO* PtrToPtr(const TI* const ptr)
{
return reinterpret_cast<const TO*>(ptr);
}
namespace {
const std::string kParamCheckErrorSuffix = "8888";
class GeLog {
public:
static uint64_t GetTid()
{
#ifdef __GNUC__
thread_local static const uint64_t tid = static_cast<uint64_t>(syscall(__NR_gettid));
#else
thread_local static const uint64_t tid = static_cast<uint64_t>(GetCurrentThreadId());
#endif
return tid;
}
};
inline bool IsLogEnable(const int32_t module_name, const int32_t log_level)
{
const int32_t enable = CheckLogLevel(module_name, log_level);
return (enable == 1);
}
std::string CurrentTimeFormatStr()
{
std::string time_str;
auto now = std::chrono::system_clock::now();
auto milli_seconds = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
auto micro_seconds = std::chrono::time_point_cast<std::chrono::microseconds>(now);
const auto now_t = std::chrono::system_clock::to_time_t(now);
const std::tm* tm_now = std::localtime(&now_t);
if (tm_now == nullptr) {
return time_str;
}
constexpr int32_t year_base = 1900;
constexpr size_t kMaxTimeLen = 128U;
constexpr int64_t kOneThousandMs = 1000L;
error_message::char_t format_time[kMaxTimeLen] = {};
(void)snprintf_s(
format_time, kMaxTimeLen, kMaxTimeLen - 1U, "%04d-%02d-%02d-%02d:%02d:%02d.%03ld.%03ld",
tm_now->tm_year + year_base, tm_now->tm_mon + 1, tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min,
tm_now->tm_sec, milli_seconds.time_since_epoch().count() % kOneThousandMs,
micro_seconds.time_since_epoch().count() % kOneThousandMs);
time_str = format_time;
return time_str;
}
}
#define GELOGE(fmt, ...) \
do { \
dlog_error( \
GE_MODULE_NAME, "%" PRIu64 " %s: %s" fmt, GeLog::GetTid(), &__FUNCTION__[0], \
ErrorManager::GetInstance().GetLogHeader().c_str(), ##__VA_ARGS__); \
} while (false)
#define GELOGW(fmt, ...) \
do { \
if (IsLogEnable(GE_MODULE_NAME, DLOG_WARN)) { \
dlog_warn(GE_MODULE_NAME, "%" PRIu64 " %s:" fmt, GeLog::GetTid(), &__FUNCTION__[0], ##__VA_ARGS__); \
} \
} while (false)
#define GELOGI(fmt, ...) \
do { \
if (IsLogEnable(GE_MODULE_NAME, DLOG_INFO)) { \
dlog_info(GE_MODULE_NAME, "%" PRIu64 " %s:" fmt, GeLog::GetTid(), &__FUNCTION__[0], ##__VA_ARGS__); \
} \
} while (false)
#define GELOGD(fmt, ...) \
do { \
if (IsLogEnable(GE_MODULE_NAME, DLOG_DEBUG)) { \
dlog_debug(GE_MODULE_NAME, "%" PRIu64 " %s:" fmt, GeLog::GetTid(), &__FUNCTION__[0], ##__VA_ARGS__); \
} \
} while (false)
namespace {
int32_t ReportInnerErrorMessage(
const char* file_name, const char* func, uint32_t line, const char* error_code, const char* format,
va_list arg_list)
{
std::vector<char> buf(LIMIT_PER_MESSAGE, '\0');
auto ret = vsprintf_s(buf.data(), LIMIT_PER_MESSAGE, format, arg_list);
if (ret < 0) {
GELOGE("[Check][Param] FormatErrorMessage failed, ret:%d, file:%s, line:%u", ret, file_name, line);
return -1;
}
ret = sprintf_s(
buf.data() + ret, LIMIT_PER_MESSAGE - static_cast<size_t>(ret), "[FUNC:%s][FILE:%s][LINE:%u]", func,
error_message::TrimPath(std::string(file_name)).c_str(), line);
if (ret < 0) {
GELOGE("[Check][Param] FormatErrorMessage failed, ret:%d, file:%s, line:%u", ret, file_name, line);
return -1;
}
return ErrorManager::GetInstance().ReportInterErrMessage(error_code, std::string(buf.data()));
}
std::unique_ptr<error_message::char_t[]> CreateUniquePtrFromString(const std::string& str)
{
const size_t buf_size = str.empty() ? 1U : (str.size() + 1U);
auto uni_ptr = std::make_unique<error_message::char_t[]>(buf_size);
if (uni_ptr == nullptr) {
return nullptr;
}
if (str.empty()) {
uni_ptr[0U] = '\0';
} else {
if (strncpy_s(uni_ptr.get(), str.size() + 1, str.c_str(), str.size()) != EOK) {
return nullptr;
}
}
return uni_ptr;
}
void ClearMessageContainerByWorkId(
std::map<uint64_t, std::vector<ErrorManager::ErrorItem>>& message_container, const uint64_t work_stream_id)
{
const std::map<uint64_t, std::vector<ErrorManager::ErrorItem>>::const_iterator err_iter =
message_container.find(work_stream_id);
if (err_iter != message_container.cend()) {
(void)message_container.erase(err_iter);
}
}
std::vector<ErrorManager::ErrorItem>& GetOrCreateMessageContainerByWorkId(
std::map<uint64_t, std::vector<ErrorManager::ErrorItem>>& message_container, uint64_t work_id)
{
auto iter = message_container.find(work_id);
if (iter == message_container.end()) {
(void)message_container.emplace(work_id, std::vector<ErrorManager::ErrorItem>());
iter = message_container.find(work_id);
}
return iter->second;
}
}
namespace error_message {
const std::string kInitialize = "INIT";
const std::string kModelCompile = "COMP";
const std::string kModelLoad = "LOAD";
const std::string kModelExecute = "EXEC";
const std::string kFinalize = "FINAL";
const std::string kParser = "PARSER";
const std::string kOpsProtoInit = "OPS_PRO";
const std::string kSystemInit = "SYS";
const std::string kEngineInit = "ENGINE";
const std::string kOpsKernelInit = "OPS_KER";
const std::string kOpsKernelBuilderInit = "OPS_KER_BLD";
const std::string kPrepareOptimize = "PRE_OPT";
const std::string kOriginOptimize = "ORI_OPT";
const std::string kSubGraphOptimize = "SUB_OPT";
const std::string kMergeGraphOptimize = "MERGE_OPT";
const std::string kPreBuild = "PRE_BLD";
const std::string kStreamAlloc = "STM_ALLOC";
const std::string kMemoryAlloc = "MEM_ALLOC";
const std::string kTaskGenerate = "TASK_GEN";
const std::string kOther = "DEFAULT";
#ifdef __GNUC__
std::string TrimPath(const std::string& str)
{
if (str.find_last_of('/') != std::string::npos) {
return str.substr(str.find_last_of('/') + 1U);
}
return str;
}
#else
std::string TrimPath(const std::string& str)
{
if (str.find_last_of('\\') != std::string::npos) {
return str.substr(str.find_last_of('\\') + 1U);
}
return str;
}
#endif
int32_t FormatErrorMessage(char_t* str_dst, size_t dst_max, const char_t* format, ...)
{
int32_t ret;
va_list arg_list;
va_start(arg_list, format);
ret = vsprintf_s(str_dst, dst_max, format, arg_list);
(void)arg_list;
va_end(arg_list);
if (ret < 0) {
GELOGE("[Check][Param] FormatErrorMessage failed, ret:%d, pattern:%s", ret, format);
}
return ret;
}
void ReportInnerError(
const char_t* file_name, const char_t* func, uint32_t line, const std::string error_code, const char_t* format, ...)
{
va_list arg_list;
va_start(arg_list, format);
(void)ReportInnerErrorMessage(file_name, func, line, error_code.c_str(), format, arg_list);
va_end(arg_list);
return;
}
}
namespace {
#ifdef __GNUC__
constexpr const error_message::char_t* const kErrorCodePath = "../conf/error_manager/error_code.json";
constexpr const error_message::char_t* const kSeparator = "/";
#else
const error_message::char_t* const kErrorCodePath = "..\\conf\\error_manager\\error_code.json";
const error_message::char_t* const kSeparator = "\\";
#endif
constexpr uint64_t kLength = 2UL;
void Ltrim(std::string& s)
{
(void)s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](const error_message::char_t c) -> bool {
return static_cast<bool>(std::isspace(static_cast<uint8_t>(c)) == 0);
}));
}
void Rtrim(std::string& s)
{
(void)s.erase(
std::find_if(
s.rbegin(), s.rend(),
[](const error_message::char_t c) -> bool {
return static_cast<bool>(std::isspace(static_cast<uint8_t>(c)) == 0);
})
.base(),
s.end());
}
void Trim(std::string& s)
{
Rtrim(s);
Ltrim(s);
}
std::string GetSelfLibraryDir(void)
{
mmDlInfo dl_info{nullptr, nullptr, nullptr, nullptr, 0, 0, 0};
if (mmDladdr(reinterpret_cast<void*>(GetSelfLibraryDir), &dl_info) != EN_OK) {
const error_message::char_t* error = mmDlerror();
error = (error == nullptr) ? "" : error;
GELOGW("Failed to read the shared library file path! reason:%s", error);
return std::string();
} else {
std::string so_path = dl_info.dli_fname;
error_message::char_t path[MMPA_MAX_PATH] = {};
if (so_path.length() >= static_cast<size_t>(MMPA_MAX_PATH)) {
GELOGW("The shared library file path is too long!");
return std::string();
}
if (mmRealPath(so_path.c_str(), &(path[0]), MMPA_MAX_PATH) != EN_OK) {
GELOGW("Failed to get realpath of %s, reason:%s", so_path.c_str(), strerror(errno));
return std::string();
}
so_path = &(path[0]);
so_path = so_path.substr(0U, so_path.rfind(kSeparator) + 1U);
return so_path;
}
}
std::vector<std::string> SplitByDelim(const std::string& str, const error_message::char_t delim)
{
std::vector<std::string> elems;
if (str.empty()) {
elems.emplace_back("");
return elems;
}
std::stringstream ss(str);
std::string item;
while (getline(ss, item, delim)) {
Trim(item);
elems.push_back(item);
}
const auto str_size = str.size();
if ((str_size > 0U) && (str[str_size - 1U] == delim)) {
elems.emplace_back("");
}
return elems;
}
}
thread_local error_message::Context ErrorManager::error_context_ = {0UL, "", "", ""};
ErrorManager& ErrorManager::GetInstance()
{
static ErrorManager instance;
return instance;
}
int32_t ErrorManager::Init(const std::string path)
{
const std::string file_path = path + kErrorCodePath;
GELOGI("Begin to init, path is %s", path.c_str());
const int32_t ret = ParseJsonFile(file_path);
if (ret != 0) {
GELOGW("[Parse][File]Parse config file:%s failed", file_path.c_str());
return -1;
}
is_init_.store(true, std::memory_order_release);
return 0;
}
int32_t ErrorManager::Init() { return Init(GetSelfLibraryDir()); }
int32_t ErrorManager::EnsureInitialized()
{
if (is_init_.load(std::memory_order_acquire)) {
return 0;
}
const std::unique_lock<std::mutex> lck(init_mutex_);
if (is_init_.load(std::memory_order_relaxed)) {
return 0;
}
return Init(GetSelfLibraryDir());
}
int32_t ErrorManager::Init(error_message::ErrorMsgMode error_mode)
{
if (error_mode >= error_message::ErrorMsgMode::ERR_MSG_MODE_MAX) {
GELOGE("[Init][Error]error mode is invalid %u", error_mode);
return -1;
}
const int32_t ret = Init(GetSelfLibraryDir());
if (ret != 0) {
return -1;
}
error_mode_.store(error_mode, std::memory_order_release);
return 0;
}
int32_t ErrorManager::ReportInterErrMessage(const std::string error_code, const std::string& error_msg)
{
std::string report_time = CurrentTimeFormatStr();
constexpr uint64_t kMaxWorkSize = 1000UL;
if (EnsureInitialized() != 0) {
GELOGI("ErrorManager has not been initialized, can't report error_message.");
return -1;
}
if (!IsInnerErrorCode(error_code)) {
GELOGE("[Report][Error]error_code %s is not internal error code", error_code.c_str());
return -1;
}
const std::unique_lock<std::mutex> lck(mutex_);
if (error_context_.work_stream_id == 0UL) {
if (error_message_per_work_id_.size() > kMaxWorkSize) {
GELOGW(
"[Report][Error]error_code %s, error work_stream total size exceed %lu, skip record",
error_code.c_str(), kMaxWorkSize);
return -1;
}
GenWorkStreamIdDefault();
}
GELOGI(
"report error_message, error_code:%s, work_stream_id:%lu, error_mode:%u", error_code.c_str(),
error_context_.work_stream_id, static_cast<uint32_t>(error_mode_.load(std::memory_order_relaxed)));
auto& error_messages = GetErrorMsgContainer(error_context_.work_stream_id);
auto& warning_messages = GetWarningMsgContainer(error_context_.work_stream_id);
if (error_messages.size() > kMaxWorkSize) {
GELOGW(
"[Report][Error]error_code %s, error work_stream_id:%lu item size exceed %lu, skip record",
error_code.c_str(), error_context_.work_stream_id, kMaxWorkSize);
return -1;
}
std::string tmp = error_msg;
if (error_mode_.load(std::memory_order_acquire) == error_message::ErrorMsgMode::PROCESS_MODE) {
tmp += "[THREAD:" + std::to_string(mmGetTid()) + "]";
}
ErrorManager::ErrorItem item = {error_code, "", tmp, "", "", {}, report_time};
if (error_code[0UL] == 'W') {
const auto it = find(warning_messages.begin(), warning_messages.end(), item);
if (it == warning_messages.end()) {
warning_messages.emplace_back(item);
}
} else {
const auto it = find(error_messages.begin(), error_messages.end(), item);
if (it == error_messages.end()) {
error_messages.emplace_back(item);
}
}
return 0;
}
int32_t ErrorManager::ReportErrMessage(const std::string error_code, const std::map<std::string, std::string>& args_map)
{
std::string report_time = CurrentTimeFormatStr();
if (EnsureInitialized() != 0) {
GELOGI("ErrorManager has not been initialized, can't report error_message.");
return 0;
}
if (error_context_.work_stream_id == 0UL) {
GenWorkStreamIdDefault();
}
GELOGI(
"report error_message, error_code:%s, work_stream_id:%lu, error_mode:%u.", error_code.c_str(),
error_context_.work_stream_id, static_cast<uint32_t>(error_mode_.load(std::memory_order_relaxed)));
ErrorInfoConfig error_info;
{
const std::unique_lock<std::mutex> lock(mutex_);
const std::map<std::string, ErrorManager::ErrorInfoConfig>::const_iterator iter = error_map_.find(error_code);
if (iter == error_map_.cend()) {
GELOGW("[Report][Warning]error_code %s is not registered", error_code.c_str());
return -1;
}
error_info = iter->second;
}
std::string error_message = error_info.error_message;
for (const std::string& arg : error_info.arg_list) {
if (arg.empty()) {
GELOGI("arg is null");
break;
}
const auto arg_it = args_map.find(arg);
if (arg_it == args_map.end()) {
GELOGE("[Report][Error]error_code: %s, arg %s does not exist in map", error_code.c_str(), arg.c_str());
return -1;
}
const std::string& arg_value = arg_it->second;
const auto index = error_message.find("%s");
if (index == std::string::npos) {
GELOGE(
"[Report][Error]error_code: %s, %s location in error_message is not found", error_code.c_str(),
arg.c_str());
return -1;
}
(void)error_message.replace(index, kLength, arg_value);
}
const std::unique_lock<std::mutex> lock(mutex_);
auto& error_messages = GetErrorMsgContainer(error_context_.work_stream_id);
auto& warning_messages = GetWarningMsgContainer(error_context_.work_stream_id);
if (error_mode_.load(std::memory_order_acquire) == error_message::ErrorMsgMode::PROCESS_MODE) {
error_message += "[THREAD:" + std::to_string(mmGetTid()) + "]";
}
ErrorManager::ErrorItem error_item = {
error_code, error_info.error_title, error_message, error_info.possible_cause, error_info.solution, args_map,
report_time};
if (error_code[0UL] == 'W') {
const auto it = find(warning_messages.begin(), warning_messages.end(), error_item);
if (it == warning_messages.end()) {
warning_messages.emplace_back(error_item);
}
} else {
const auto it = find(error_messages.begin(), error_messages.end(), error_item);
if (it == error_messages.end()) {
error_messages.emplace_back(error_item);
}
}
return 0;
}
int32_t ErrorManager::ReportErrMsgWithoutTpl(const std::string& error_code, const std::string& errmsg)
{
std::string report_time = CurrentTimeFormatStr();
if (EnsureInitialized() != 0) {
GELOGI("ErrorManager has not been initialized, can't report error_message.");
return -1;
}
if (error_context_.work_stream_id == 0UL) {
GenWorkStreamIdDefault();
}
auto final_error_code = error_code;
if (!IsUserDefinedErrorCode(final_error_code)) {
GELOGW(
"[Report] Current error code is [%s], suggest using the recommended U segment. "
"The error code EU0000 is reported!",
final_error_code.c_str());
final_error_code = "EU0000";
}
GELOGI(
"report error_message, error_code:%s, work_stream_id:%lu, error_mode:%u.", error_code.c_str(),
error_context_.work_stream_id, static_cast<uint32_t>(error_mode_.load(std::memory_order_relaxed)));
const std::unique_lock<std::mutex> lock(mutex_);
auto& error_messages = GetErrorMsgContainer(error_context_.work_stream_id);
ErrorItem error_item{final_error_code, "", errmsg, "", "", {}, report_time};
const auto it = find(error_messages.begin(), error_messages.end(), error_item);
if (it == error_messages.end()) {
error_messages.emplace_back(error_item);
}
return 0;
}
void ErrorManager::AssembleInnerErrorMessage(
const std::vector<ErrorItem>& error_messages, const std::string& first_code, std::stringstream& err_stream) const
{
std::string current_code_print = first_code;
const bool IsErrorId = IsParamCheckErrorId(first_code);
for (auto& item : error_messages) {
if (!IsParamCheckErrorId(item.error_id)) {
current_code_print = item.error_id;
break;
}
}
err_stream << current_code_print << ": Internal error!" << std::endl;
bool print_traceback_once = false;
for (auto& item : error_messages) {
if (IsParamCheckErrorId(item.error_id) && IsErrorId) {
err_stream << " " << item.error_message << std::endl;
continue;
}
current_code_print == " " ?
(err_stream << current_code_print << " " << item.error_message << std::endl) :
(err_stream << current_code_print << "[PID: " << std::to_string(mmGetPid()) << "] " << item.report_time
<< " " << item.error_title << "(" << item.error_id << "): "
<< " " << item.error_message << std::endl);
current_code_print = " ";
if (!print_traceback_once) {
err_stream << "TraceBack (most recent call last):" << std::endl;
print_traceback_once = true;
}
}
}
std::string ErrorManager::GetErrorMessage()
{
const auto& error_messages = GetRawErrorMessages();
if (error_messages.empty()) {
return "";
}
std::stringstream err_stream;
std::string first_code = error_messages[0UL].error_id;
for (const auto& item : error_messages) {
if (!IsInnerErrorCode(item.error_id)) {
first_code = item.error_id;
err_stream << "[PID: " << std::to_string(mmGetPid()) << "] " << item.report_time << " " << item.error_title
<< "(" << first_code << "): " << item.error_message << std::endl;
if (!item.possible_cause.empty() && item.possible_cause != "N/A") {
err_stream << " Possible Cause: " << item.possible_cause << std::endl;
}
if (!item.solution.empty() && item.solution != "N/A") {
err_stream << " Solution: " << item.solution << std::endl;
}
break;
}
}
if (IsInnerErrorCode(first_code)) {
AssembleInnerErrorMessage(error_messages, first_code, err_stream);
} else {
bool print_traceback_once = false;
for (const auto& item : error_messages) {
if (first_code == item.error_id && error_messages[0].error_message == item.error_message) {
continue;
}
if (!print_traceback_once) {
err_stream << "TraceBack (most recent call last):" << std::endl;
print_traceback_once = true;
}
err_stream << " " << item.error_message << std::endl;
}
}
const std::unique_lock<std::mutex> lck(mutex_);
ClearErrorMsgContainer(error_context_.work_stream_id);
return err_stream.str();
}
std::string ErrorManager::GetWarningMessage()
{
GELOGI(
"current work_stream_id:%lu, error_mode:%u", error_context_.work_stream_id,
static_cast<uint32_t>(error_mode_.load(std::memory_order_relaxed)));
const std::unique_lock<std::mutex> lck(mutex_);
auto& warning_messages = GetWarningMsgContainer(error_context_.work_stream_id);
std::stringstream warning_stream;
for (auto& item : warning_messages) {
warning_stream << "[PID: " << std::to_string(mmGetPid()) << "] " << item.report_time << " " << item.error_title
<< "(" << item.error_id << "): " << item.error_message << std::endl;
}
ClearWarningMsgContainer(error_context_.work_stream_id);
return warning_stream.str();
}
int32_t ErrorManager::OutputErrMessage(int32_t handle)
{
std::string err_msg = GetErrorMessage();
if (err_msg.empty()) {
std::stringstream err_stream;
err_stream << "E19999: Internal error!" << std::endl;
err_stream << " "
<< "Unknown error occurred. Please check the log." << std::endl;
err_msg = err_stream.str();
}
if (handle <= fileno(stderr)) {
std::cout << err_msg << std::endl;
} else {
const mmSsize_t ret = mmWrite(
handle, const_cast<error_message::char_t*>(err_msg.c_str()), static_cast<uint32_t>(err_msg.length()));
if (ret == -1) {
GELOGE("[Write][File]fail, reason:%s", strerror(errno));
return -1;
}
}
return 0;
}
int32_t ErrorManager::OutputMessage(int32_t handle)
{
const std::string warning_msg = GetWarningMessage();
std::cout << warning_msg << std::endl;
handle = 0;
return handle;
}
int32_t ErrorManager::ParseJsonFile(const std::string path)
{
GELOGD("Begin to parse json file, path is %s", path.c_str());
nlohmann::json json_file;
const int32_t status = ReadJsonFile(path, &json_file);
if (status != 0) {
GELOGW("[Read][JsonFile]file path is %s", path.c_str());
return -1;
}
return ParseJsonFormatString(PtrToPtr<nlohmann::json, void>(&json_file));
}
int32_t ErrorManager::ParseJsonFormatString(const void* const handle, uint32_t priority)
{
GELOGD("Begin to parse json string");
const std::unique_lock<std::mutex> lck(mutex_);
try {
const nlohmann::json* const json_file = PtrToPtr<void, nlohmann::json>(handle);
if (json_file->find("error_info_list") == json_file->end()) {
GELOGW("[Check][Config]The message of error_info_list is not found");
return -1;
}
const nlohmann::json& error_list_json = json_file->at("error_info_list");
if (error_list_json.is_null() || !error_list_json.is_array()) {
GELOGW("[Check][Config]The message of error_info_list is not found or "
"the message of error_info_list is not array");
return -1;
}
for (const auto& error_json : error_list_json) {
ErrorInfoConfig error_info;
error_info.error_id = error_json["ErrCode"];
error_info.error_message = error_json["ErrMessage"];
if (error_json.contains("errTitle")) {
error_info.error_title = error_json["errTitle"];
}
if (error_json.contains("suggestion")) {
error_info.possible_cause = error_json["suggestion"]["Possible Cause"];
error_info.solution = error_json["suggestion"]["Solution"];
}
error_info.arg_list = SplitByDelim(error_json["Arglist"], ',');
error_info.priority = priority;
auto it = error_map_.find(error_info.error_id);
if (it == error_map_.cend()) {
(void)error_map_.emplace(error_info.error_id, error_info);
GELOGD("add error_code %s success", error_info.error_id.c_str());
} else {
if (it->second.priority < error_info.priority) {
it->second = error_info;
GELOGD(
"Update error_code %s success, current priority[%u] is greater than saved priority[%u]",
error_info.error_id.c_str(), priority, it->second.priority);
} else {
GELOGD(
"No need update error_code %s, due to current priority[%u] is less than "
"or equal to saved priority[%u]",
error_info.error_id.c_str(), priority, it->second.priority);
}
}
}
} catch (const nlohmann::json::exception& e) {
GELOGW("[Parse][JsonFile]exception message: %s", e.what());
return -1;
}
return 0;
}
int32_t ErrorManager::ReadJsonFile(const std::string& file_path, void* const handle)
{
if (file_path.empty()) {
GELOGW("[Read][JsonFile]path %s is not valid", file_path.c_str());
return -1;
}
nlohmann::json* const json_file = PtrToPtr<void, nlohmann::json>(handle);
if (json_file == nullptr) {
GELOGW("[Check][Param]JsonFile is nullptr");
return -1;
}
const error_message::char_t* const file = file_path.data();
if ((mmAccess2(file, M_F_OK)) != EN_OK) {
GELOGW("[Read][JsonFile] %s does not exist, error %s", file_path.c_str(), strerror(errno));
return -1;
}
std::ifstream ifs(file_path);
if (!ifs.is_open()) {
GELOGW("[Read][JsonFile]Open %s failed", file_path.c_str());
return -1;
}
const std::string content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
try {
*json_file = nlohmann::json::parse(content.c_str(), content.c_str() + content.size());
} catch (const nlohmann::json::exception& e) {
GELOGW("[Read][JsonFile]Parse json fail. path: %s, exception message: %s.", file_path.c_str(), e.what());
ifs.close();
return -1;
}
ifs.close();
GELOGD("Read json file success");
return 0;
}
void ErrorManager::ATCReportErrMessage(
const std::string error_code, const std::vector<std::string>& key, const std::vector<std::string>& value)
{
if (EnsureInitialized() != 0) {
GELOGI("ErrorManager has not been initialized, can't report error_message.");
return;
}
std::map<std::string, std::string> args_map;
if (key.empty()) {
(void)ErrorManager::GetInstance().ReportErrMessage(error_code, args_map);
} else if (key.size() == value.size()) {
for (size_t i = 0UL; i < key.size(); ++i) {
(void)args_map.insert(std::make_pair(key[i], value[i]));
}
(void)ErrorManager::GetInstance().ReportErrMessage(error_code, args_map);
} else {
GELOGW("ATCReportErrMessage wrong, vector key and value size is not equal");
}
}
void ErrorManager::ClassifyCompileFailedMsg(
const std::map<std::string, std::string>& msg, std::map<std::string, std::vector<std::string>>& classified_msg)
{
for (const auto& itr : msg) {
GELOGD("msg is error_code:%s, op_name:%s", itr.first.c_str(), itr.second.c_str());
const auto err_code_itr = classified_msg.find(itr.first);
if (err_code_itr == classified_msg.end()) {
(void)classified_msg.emplace(itr.first, std::vector<std::string>{itr.second});
} else {
std::vector<std::string>& op_name_list = err_code_itr->second;
op_name_list.emplace_back(itr.second);
}
}
}
int32_t ErrorManager::ReportMstuneCompileFailedMsg(
const std::string& root_graph_name, const std::map<std::string, std::string>& msg)
{
if (EnsureInitialized() != 0) {
GELOGI("ErrorManager has not been initialized, can't report error_message.");
return 0;
}
if (msg.empty() || root_graph_name.empty()) {
GELOGW(
"Msg or root graph name is empty, msg size is %zu, root graph name is %s", msg.size(),
root_graph_name.c_str());
return -1;
}
GELOGD("Report graph:%s compile failed msg", root_graph_name.c_str());
const std::unique_lock<std::mutex> lock(mutex_);
const auto itr = compile_failed_msg_map_.find(root_graph_name);
if (itr != compile_failed_msg_map_.end()) {
std::map<std::string, std::vector<std::string>>& classified_msg = itr->second;
ClassifyCompileFailedMsg(msg, classified_msg);
} else {
std::map<std::string, std::vector<std::string>> classified_msg;
ClassifyCompileFailedMsg(msg, classified_msg);
(void)compile_failed_msg_map_.emplace(root_graph_name, classified_msg);
}
return 0;
}
int32_t ErrorManager::GetMstuneCompileFailedMsg(
const std::string& graph_name, std::map<std::string, std::vector<std::string>>& msg_map)
{
if (EnsureInitialized() != 0) {
GELOGI("ErrorManager has not been initialized, can't report error_message.");
return 0;
}
if (!msg_map.empty()) {
GELOGW("msg_map is not empty, exist msg");
return -1;
}
const std::unique_lock<std::mutex> lock(mutex_);
const auto iter = compile_failed_msg_map_.find(graph_name);
if (iter == compile_failed_msg_map_.end()) {
GELOGW("can not find graph, name is:%s", graph_name.c_str());
return -1;
} else {
auto& compile_failed_msg = iter->second;
msg_map.swap(compile_failed_msg);
(void)compile_failed_msg_map_.erase(graph_name);
}
GELOGI("get graph:%s compile result msg success", graph_name.c_str());
return 0;
}
std::vector<ErrorManager::ErrorItem>& ErrorManager::GetErrorMsgContainerByWorkId(uint64_t work_id)
{
return GetOrCreateMessageContainerByWorkId(error_message_per_work_id_, work_id);
}
std::vector<ErrorManager::ErrorItem>& ErrorManager::GetWarningMsgContainerByWorkId(uint64_t work_id)
{
return GetOrCreateMessageContainerByWorkId(warning_messages_per_work_id_, work_id);
}
std::vector<ErrorManager::ErrorItem>& ErrorManager::GetErrorMsgContainer(uint64_t work_stream_id)
{
return (error_mode_.load(std::memory_order_acquire) == error_message::ErrorMsgMode::INTERNAL_MODE) ?
GetErrorMsgContainerByWorkId(work_stream_id) :
error_message_process_;
}
std::vector<ErrorManager::ErrorItem>& ErrorManager::GetWarningMsgContainer(uint64_t work_stream_id)
{
return (error_mode_.load(std::memory_order_acquire) == error_message::ErrorMsgMode::INTERNAL_MODE) ?
GetWarningMsgContainerByWorkId(work_stream_id) :
warning_messages_process_;
}
void ErrorManager::GenWorkStreamIdDefault()
{
const int32_t pid = mmGetPid();
const int32_t tid = mmGetTid();
constexpr uint64_t kPidOffset = 100000UL;
const uint64_t work_stream_id =
static_cast<uint64_t>(static_cast<uint32_t>(pid) * kPidOffset) + static_cast<uint64_t>(tid);
error_context_.work_stream_id = work_stream_id;
}
void ErrorManager::GenWorkStreamIdBySessionGraph(const uint64_t session_id, const uint64_t graph_id)
{
constexpr uint64_t kSessionIdOffset = 100000UL;
const uint64_t work_stream_id = (session_id * kSessionIdOffset) + graph_id;
error_context_.work_stream_id = work_stream_id;
const std::unique_lock<std::mutex> lck(mutex_);
ClearErrorMsgContainerByWorkId(work_stream_id);
ClearWarningMsgContainerByWorkId(work_stream_id);
}
void ErrorManager::GenWorkStreamIdWithSessionIdGraphId(const uint64_t session_id, const uint64_t graph_id)
{
constexpr uint64_t kSessionIdOffset = 100000UL;
const uint64_t work_stream_id = (session_id * kSessionIdOffset) + graph_id;
error_context_.work_stream_id = work_stream_id;
}
void ErrorManager::ClearErrorMsgContainerByWorkId(const uint64_t work_stream_id)
{
return ClearMessageContainerByWorkId(error_message_per_work_id_, work_stream_id);
}
void ErrorManager::ClearWarningMsgContainerByWorkId(const uint64_t work_stream_id)
{
return ClearMessageContainerByWorkId(warning_messages_per_work_id_, work_stream_id);
}
void ErrorManager::ClearErrorMsgContainer(const uint64_t work_stream_id)
{
if (error_mode_.load(std::memory_order_acquire) == error_message::ErrorMsgMode::PROCESS_MODE) {
error_message_process_.clear();
} else {
ClearErrorMsgContainerByWorkId(work_stream_id);
}
}
void ErrorManager::ClearWarningMsgContainer(const uint64_t work_stream_id)
{
if (error_mode_.load(std::memory_order_acquire) == error_message::ErrorMsgMode::PROCESS_MODE) {
warning_messages_process_.clear();
} else {
ClearWarningMsgContainerByWorkId(work_stream_id);
}
}
const std::string& ErrorManager::GetLogHeader()
{
if ((error_context_.first_stage == "") && (error_context_.second_stage == "")) {
error_context_.log_header = "";
} else {
error_context_.log_header = "[" + error_context_.first_stage + "][" + error_context_.second_stage + "]";
}
return error_context_.log_header;
}
error_message::Context& ErrorManager::GetErrorManagerContext()
{
if (error_context_.work_stream_id == 0UL) {
GenWorkStreamIdDefault();
}
return error_context_;
}
void ErrorManager::SetErrorContext(error_message::Context error_context)
{
error_context_.work_stream_id = error_context.work_stream_id;
error_context_.first_stage = std::move(error_context.first_stage);
error_context_.second_stage = std::move(error_context.second_stage);
error_context_.log_header = std::move(error_context.log_header);
}
void ErrorManager::SetStage(const std::string& first_stage, const std::string& second_stage)
{
error_context_.first_stage = first_stage;
error_context_.second_stage = second_stage;
}
bool ErrorManager::IsInnerErrorCode(const std::string& error_code) const
{
const std::string kInterErrorCodePrefix = "9999";
if (!IsValidErrorCode(error_code)) {
return false;
} else {
return (error_code.substr(2U, 4U) == kInterErrorCodePrefix) || IsParamCheckErrorId(error_code);
}
}
bool ErrorManager::IsUserDefinedErrorCode(const std::string& error_code)
{
if (!IsValidErrorCode(error_code) || IsInnerErrorCode(error_code)) {
return false;
}
if (EnsureInitialized() != 0) {
GELOGI("ErrorManager has not been initialized, can't verify error code.");
return false;
}
const std::unique_lock<std::mutex> lck(mutex_);
if (error_map_.find(error_code) != error_map_.end()) {
GELOGW("Report error_code:[%s] is predefined error code, suggested use U error code", error_code.c_str());
return false;
}
return true;
}
bool ErrorManager::IsParamCheckErrorId(const std::string& error_code) const
{
return (error_code.substr(2U, 4U) == kParamCheckErrorSuffix);
}
int32_t ErrorManager::SetRawErrorMessages(const std::vector<ErrorItem>& items)
{
const std::unique_lock<std::mutex> lck(mutex_);
if (error_context_.work_stream_id == 0UL) {
GenWorkStreamIdDefault();
}
GELOGI("Set error_message, work_stream_id:%lu.", error_context_.work_stream_id);
auto& error_messages = GetErrorMsgContainer(error_context_.work_stream_id);
(void)error_messages.insert(error_messages.end(), items.begin(), items.end());
return 0;
}
std::vector<error_message::ErrorItem> ErrorManager::GetRawErrorMessages()
{
GELOGI("current work_stream_id:%lu", error_context_.work_stream_id);
const std::unique_lock<std::mutex> lck(mutex_);
auto error_items = GetErrorMsgContainer(error_context_.work_stream_id);
ClearErrorMsgContainer(error_context_.work_stream_id);
return error_items;
}
namespace error_message {
int32_t RegisterFormatErrorMessage(const char_t* error_msg, size_t error_msg_len)
{
nlohmann::json j;
try {
j = nlohmann::json::parse(error_msg, error_msg + error_msg_len);
} catch (const nlohmann::json::parse_error& e) {
return -1;
}
GELOGI("RegisterFormatErrorMessage, try to register error message");
return ErrorManager::GetInstance().ParseJsonFormatString(PtrToPtr<nlohmann::json, void>(&j), 1);
}
int32_t ReportInnerErrMsg(
const char* file_name, const char* func, uint32_t line, const char* error_code, const char* format, ...)
{
va_list arg_list;
va_start(arg_list, format);
const auto ret = ReportInnerErrorMessage(file_name, func, line, error_code, format, arg_list);
va_end(arg_list);
return ret;
}
int32_t ReportUserDefinedErrMsg(const char* error_code, const char* format, ...)
{
va_list arg_list;
std::vector<char> buf(LIMIT_PER_MESSAGE, '\0');
va_start(arg_list, format);
const auto ret = vsprintf_s(buf.data(), LIMIT_PER_MESSAGE, format, arg_list);
if (ret < 0) {
GELOGE("[Check][Param] Format error message failed, ret:%d", ret);
return -1;
}
return ErrorManager::GetInstance().ReportErrMsgWithoutTpl(error_code, std::string(buf.data()));
}
int32_t ReportPredefinedErrMsg(
const char* error_code, const std::vector<const char*>& key, const std::vector<const char*>& value)
{
if (key.size() != value.size()) {
GELOGE(
"[Check][Param] ReportPredefinedErrMsg failed, vector key size:[%zu] and value size:[%zu] is not equal",
key.size(), value.size());
return -1;
}
std::map<std::string, std::string> args_map;
for (size_t i = 0UL; i < key.size(); ++i) {
(void)args_map.insert(std::make_pair(key[i], value[i]));
}
return ErrorManager::GetInstance().ReportErrMessage(error_code, args_map);
}
int32_t ReportPredefinedErrMsg(const char* error_code) { return ReportPredefinedErrMsg(error_code, {}, {}); }
int32_t ErrMgrInit(ErrorMessageMode error_mode)
{
return ErrorManager::GetInstance().Init(static_cast<error_message::ErrorMsgMode>(error_mode));
}
ErrorManagerContext GetErrMgrContext()
{
auto ctx = ErrorManager::GetInstance().GetErrorManagerContext();
ErrorManagerContext error_context{};
error_context.work_stream_id = ctx.work_stream_id;
return error_context;
}
void SetErrMgrContext(ErrorManagerContext error_context)
{
Context ctx;
ctx.work_stream_id = error_context.work_stream_id;
return ErrorManager::GetInstance().SetErrorContext(ctx);
}
unique_const_char_array GetErrMgrErrorMessage()
{
return CreateUniquePtrFromString(ErrorManager::GetInstance().GetErrorMessage());
}
unique_const_char_array GetErrMgrWarningMessage()
{
return CreateUniquePtrFromString(ErrorManager::GetInstance().GetWarningMessage());
}
std::vector<ErrMsgRawItem> GetErrMgrRawErrorMessages()
{
std::vector<ErrMsgRawItem> raw_items;
auto error_items = ErrorManager::GetInstance().GetRawErrorMessages();
for (const auto& item : error_items) {
ErrMsgRawItem raw_item;
raw_item.error_id = CreateUniquePtrFromString(item.error_id);
raw_item.error_title = CreateUniquePtrFromString(item.error_title);
raw_item.error_message = CreateUniquePtrFromString(item.error_message);
raw_item.possible_cause = CreateUniquePtrFromString(item.possible_cause);
raw_item.solution = CreateUniquePtrFromString(item.solution);
for (const auto& arg : item.args_map) {
raw_item.args_key.emplace_back(CreateUniquePtrFromString(arg.first));
raw_item.args_value.emplace_back(CreateUniquePtrFromString(arg.second));
}
raw_item.report_time = CreateUniquePtrFromString(item.report_time);
raw_items.emplace_back(std::move(raw_item));
}
return raw_items;
}
}
extern "C" {
int32_t RegisterFormatErrorMessageForC(const char* error_msg, unsigned long error_msg_len)
{
if (error_msg == nullptr) {
GELOGE("[Check][Param] error_msg is null");
return -1;
}
try {
return error_message::RegisterFormatErrorMessage(error_msg, error_msg_len);
} catch (const std::exception& e) {
GELOGE("[Check][Exception] RegisterFormatErrorMessageForC caught exception: %s", e.what());
return -1;
} catch (...) {
GELOGE("[Check][Exception] RegisterFormatErrorMessageForC caught unknown exception");
return -1;
}
}
int32_t ReportPredefinedErrMsgForC(const char* error_code, const char** key, const char** value, unsigned long arg_num)
{
if (error_code == nullptr) {
GELOGE("[Check][Param] error_code is null");
return -1;
}
if ((arg_num != 0U) && ((key == nullptr) || (value == nullptr))) {
GELOGE("[Check][Param] Argument arrays are null when arg_num:[%lu]", arg_num);
return -1;
}
for (size_t i = 0U; i < arg_num; ++i) {
if ((key[i] == nullptr) || (value[i] == nullptr)) {
GELOGE("[Check][Param] Argument array contains null entry at index:[%zu]", i);
return -1;
}
}
try {
std::vector<const char*> key_vec;
std::vector<const char*> value_vec;
key_vec.reserve(arg_num);
value_vec.reserve(arg_num);
for (size_t i = 0U; i < arg_num; ++i) {
key_vec.push_back(key[i]);
value_vec.push_back(value[i]);
}
return error_message::ReportPredefinedErrMsg(error_code, key_vec, value_vec);
} catch (const std::exception& e) {
GELOGE("[Check][Exception] ReportPredefinedErrMsgForC caught exception: %s", e.what());
return -1;
} catch (...) {
GELOGE("[Check][Exception] ReportPredefinedErrMsgForC caught unknown exception");
return -1;
}
}
int32_t ReportInnerErrMsgForC(
const char* file_name, const char* func, uint32_t line, const char* error_code, const char* format, ...)
{
if ((file_name == nullptr) || (func == nullptr) || (error_code == nullptr) || (format == nullptr)) {
GELOGE("[Check][Param] file_name or func or error_code or format is null");
return -1;
}
va_list arg_list;
va_start(arg_list, format);
int32_t ret = -1;
try {
ret = ReportInnerErrorMessage(file_name, func, line, error_code, format, arg_list);
} catch (const std::exception& e) {
GELOGE("[Check][Exception] ReportInnerErrMsgForC caught exception: %s", e.what());
} catch (...) {
GELOGE("[Check][Exception] ReportInnerErrMsgForC caught unknown exception");
}
va_end(arg_list);
return ret;
}
}