* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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.
*/
#include "log/log.h"
#include <atomic>
#include <chrono>
#include <cstdarg>
#include <memory>
#include <unordered_map>
#include <vector>
#include <sys/time.h>
#include <unistd.h>
#include <mutex>
#ifndef DIFF_PATCH_SDK
#include <log_base.h>
#endif
#include "securec.h"
namespace Updater {
static std::mutex& GetUpdaterLogLock()
{
static std::mutex updaterLogLock;
return updaterLogLock;
}
static std::ofstream g_updaterLog;
static std::ofstream g_updaterStage;
static std::ofstream g_errorCode;
static std::ofstream g_nullStream;
static std::string g_logTag;
static ReplaceLogType g_replaceMap;
static std::atomic<int> g_logLevel{ static_cast<int>(INFO) };
namespace {
void OpenLogStream(std::ofstream &ofs, const std::string &file)
{
if (ofs.is_open()) {
ofs.close();
ofs.clear();
}
ofs.open(file.c_str(), std::ios::app | std::ios::out);
}
std::string ExtractFileName(const std::string &fullPath)
{
const std::string fileSeparator = "/\\";
const auto pos = fullPath.find_last_of(fileSeparator);
return (pos == std::string::npos) ? fullPath : fullPath.substr(pos + 1);
}
}
void SetReplaceMap(const ReplaceLogType &replaceMap)
{
std::lock_guard<std::mutex> lock(GetUpdaterLogLock());
g_replaceMap = replaceMap;
}
void ReplaceLog(std::string &str)
{
if (str.empty() || g_replaceMap.empty()) {
return;
}
for (const auto& [key, value] : g_replaceMap) {
size_t pos = 0;
if ((pos = str.find(key, pos)) != std::string::npos) {
str.replace(pos, key.length(), value);
}
}
}
void InitUpdaterLogger(const std::string &tag, const std::string &logFile, const std::string &stageFile,
const std::string &errorCodeFile)
{
{
std::lock_guard<std::mutex> lock(GetUpdaterLogLock());
g_logTag = tag;
OpenLogStream(g_updaterLog, logFile);
OpenLogStream(g_updaterStage, stageFile);
OpenLogStream(g_errorCode, errorCodeFile);
}
LOG(INFO) << "updater logger init success. tag: " << tag << ", logFile: " << ExtractFileName(logFile) <<
", stageFile: " << ExtractFileName(stageFile) << ", errorCodeFile: " << ExtractFileName(errorCodeFile);
}
UpdaterLogger::~UpdaterLogger()
{
std::string str = oss_.str();
if (g_logLevel > level_ || replaceFunc_ == nullptr) {
return;
}
pid_t tid = 0;
int cpu_id = 0;
#ifndef DIFF_PATCH_SDK
{
std::lock_guard<std::mutex> lock(GetUpdaterLogLock());
HiLogBasePrint(LOG_CORE, (LogLevel)level_, UPDATER_DOMAIN, g_logTag.c_str(), "%{public}s", str.c_str());
}
tid = gettid();
cpu_id = sched_getcpu();
#endif
oss_.str("");
oss_ << std::endl << std::flush;
std::lock_guard<std::mutex> lock(GetUpdaterLogLock());
if (g_updaterLog.is_open()) {
replaceFunc_(str);
std::string cpu_id_tag = "[" + std::to_string(cpu_id) + "]";
g_updaterLog << realTime_ << " " << g_logTag << cpu_id_tag << tid
<< " " << logLevelMap_[level_] << " " << str << std::endl << std::flush;
}
}
StageLogger::~StageLogger()
{
std::lock_guard<std::mutex> lock(GetUpdaterLogLock());
if (g_updaterStage.is_open()) {
g_updaterStage << std::endl << std::flush;
} else {
std::cout << std::endl << std::flush;
}
}
void SetLogLevel(int level)
{
g_logLevel = level;
}
int GetLogLevel()
{
return g_logLevel;
}
void GetFormatTime(char time[], int size)
{
#ifndef DIFF_PATCH_SDK
struct timeval tv {};
struct tm tm {};
gettimeofday(&tv, nullptr);
localtime_r(&tv.tv_sec, &tm);
snprintf_s(time, size, size - 1, "%02d-%02d %02d:%02d:%02d.%03d",
tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
static_cast<int>(tv.tv_usec / 1000));
#endif
}
std::ostream& UpdaterLogger::OutputUpdaterLog(const std::string &path, int line)
{
GetFormatTime(realTime_, sizeof(realTime_));
if (g_logLevel <= level_) {
return oss_ << path << " " << line << " : ";
}
return g_nullStream;
}
std::ostream& UpdaterLoggerLite::OutputUpdaterLog()
{
GetFormatTime(realTime_, sizeof(realTime_));
if (g_logLevel <= level_) {
return oss_;
}
return g_nullStream;
}
std::ostream& StageLogger::OutputUpdaterStage()
{
std::unordered_map<int, std::string> updaterStageMap = {
{ UPDATE_STAGE_BEGIN, "BEGIN" },
{ UPDATE_STAGE_SUCCESS, "SUCCESS" },
{ UPDATE_STAGE_FAIL, "FAIL" },
{ UPDATE_STAGE_OUT, "OUT" }
};
char realTime[MAX_TIME_SIZE] = {0};
GetFormatTime(realTime, sizeof(realTime));
std::lock_guard<std::mutex> lock(GetUpdaterLogLock());
if (g_updaterLog.is_open()) {
if (stage_ == UPDATE_STAGE_OUT) {
return g_updaterStage << realTime << " " << g_logTag << " ";
}
return g_updaterStage << realTime << " " << g_logTag << " status is : " <<
updaterStageMap[stage_] << ", stage is ";
}
return std::cout;
}
void Logger(int level, const char* fileName, int32_t line, const char* format, ...)
{
char buff[1024] = {0};
va_list list;
va_start(list, format);
int size = vsnprintf_s(buff, sizeof(buff), sizeof(buff) - 1, format, list);
va_end(list);
if (size < EOK) {
UpdaterLogger(level).OutputUpdaterLog(fileName, line) << "vsnprintf_s failed";
return;
}
UpdaterLogger(level).OutputUpdaterLog(fileName, line) << buff;
}
std::ostream& ErrorCode::OutputErrorCode(const std::string &path, int line, UpdaterErrorCode code)
{
char realTime[MAX_TIME_SIZE] = {0};
GetFormatTime(realTime, sizeof(realTime));
std::lock_guard<std::mutex> lock(GetUpdaterLogLock());
if (g_errorCode.is_open()) {
return g_errorCode << realTime << " " << path << " " << line << " , error code is : " << code << std::endl;
}
return std::cout;
}
}