18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "logger.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <cstdarg>
198bf80f4bSopenharmony_ci#include <mutex>
208bf80f4bSopenharmony_ci#include <securec.h>
218bf80f4bSopenharmony_ci#include <set>
228bf80f4bSopenharmony_ci
238bf80f4bSopenharmony_ci#include <base/containers/iterator.h>
248bf80f4bSopenharmony_ci#include <base/containers/string.h>
258bf80f4bSopenharmony_ci#include <base/containers/string_view.h>
268bf80f4bSopenharmony_ci#include <base/containers/type_traits.h>
278bf80f4bSopenharmony_ci#include <base/containers/unique_ptr.h>
288bf80f4bSopenharmony_ci#include <base/containers/vector.h>
298bf80f4bSopenharmony_ci#include <base/namespace.h>
308bf80f4bSopenharmony_ci#include <base/util/uid.h>
318bf80f4bSopenharmony_ci#include <core/intf_logger.h>
328bf80f4bSopenharmony_ci#include <core/log.h>
338bf80f4bSopenharmony_ci#include <core/namespace.h>
348bf80f4bSopenharmony_ci
358bf80f4bSopenharmony_ci#ifdef PLATFORM_HAS_JAVA
368bf80f4bSopenharmony_ci#include <os/java/java_internal.h>
378bf80f4bSopenharmony_ci#endif
388bf80f4bSopenharmony_ci
398bf80f4bSopenharmony_ci#include "log/logger_output.h"
408bf80f4bSopenharmony_ci
418bf80f4bSopenharmony_ciCORE_BEGIN_NAMESPACE()
428bf80f4bSopenharmony_ciusing BASE_NS::string;
438bf80f4bSopenharmony_ciusing BASE_NS::string_view;
448bf80f4bSopenharmony_ciusing BASE_NS::Uid;
458bf80f4bSopenharmony_ci
468bf80f4bSopenharmony_cinamespace {
478bf80f4bSopenharmony_ci// Note: these must match the LogLevel enum.
488bf80f4bSopenharmony_ciconstexpr int LOG_LEVEL_COUNT = 7;
498bf80f4bSopenharmony_ciconstexpr const char* LOG_LEVEL_NAMES[LOG_LEVEL_COUNT] = {
508bf80f4bSopenharmony_ci    "Verbose",
518bf80f4bSopenharmony_ci    "Debug",
528bf80f4bSopenharmony_ci    "Info",
538bf80f4bSopenharmony_ci    "Warning",
548bf80f4bSopenharmony_ci    "Error",
558bf80f4bSopenharmony_ci    "Fatal",
568bf80f4bSopenharmony_ci    "None",
578bf80f4bSopenharmony_ci};
588bf80f4bSopenharmony_ci
598bf80f4bSopenharmony_ciconstexpr const char* LOG_LEVEL_NAMES_SHORT[LOG_LEVEL_COUNT] = {
608bf80f4bSopenharmony_ci    "V",
618bf80f4bSopenharmony_ci    "D",
628bf80f4bSopenharmony_ci    "I",
638bf80f4bSopenharmony_ci    "W",
648bf80f4bSopenharmony_ci    "E",
658bf80f4bSopenharmony_ci    "F",
668bf80f4bSopenharmony_ci    "N",
678bf80f4bSopenharmony_ci};
688bf80f4bSopenharmony_ciconstexpr const size_t MAX_BUFFER_SIZE = 1024;
698bf80f4bSopenharmony_ci} // namespace
708bf80f4bSopenharmony_ci
718bf80f4bSopenharmony_cistring_view Logger::GetLogLevelName(LogLevel logLevel, bool shortName)
728bf80f4bSopenharmony_ci{
738bf80f4bSopenharmony_ci    const int level = static_cast<int>(logLevel);
748bf80f4bSopenharmony_ci    CORE_ASSERT(level >= 0 && level < LOG_LEVEL_COUNT);
758bf80f4bSopenharmony_ci
768bf80f4bSopenharmony_ci    return shortName ? LOG_LEVEL_NAMES_SHORT[level] : LOG_LEVEL_NAMES[level];
778bf80f4bSopenharmony_ci}
788bf80f4bSopenharmony_ci
798bf80f4bSopenharmony_ciLogger::Logger(bool defaultOutputs)
808bf80f4bSopenharmony_ci#ifdef NDEBUG
818bf80f4bSopenharmony_ci    : logLevel_(LogLevel::LOG_ERROR)
828bf80f4bSopenharmony_ci#endif
838bf80f4bSopenharmony_ci{
848bf80f4bSopenharmony_ci    if (defaultOutputs) {
858bf80f4bSopenharmony_ci#if CORE_LOG_TO_CONSOLE == 1
868bf80f4bSopenharmony_ci        AddOutput(CreateLoggerConsoleOutput());
878bf80f4bSopenharmony_ci#endif
888bf80f4bSopenharmony_ci
898bf80f4bSopenharmony_ci#if CORE_LOG_TO_DEBUG_OUTPUT == 1
908bf80f4bSopenharmony_ci        AddOutput(CreateLoggerDebugOutput());
918bf80f4bSopenharmony_ci#endif
928bf80f4bSopenharmony_ci
938bf80f4bSopenharmony_ci#if CORE_LOG_TO_FILE == 1
948bf80f4bSopenharmony_ci        AddOutput(CreateLoggerFileOutput("./logfile.txt"));
958bf80f4bSopenharmony_ci#endif
968bf80f4bSopenharmony_ci    }
978bf80f4bSopenharmony_ci}
988bf80f4bSopenharmony_ci
998bf80f4bSopenharmony_civoid Logger::VLog(
1008bf80f4bSopenharmony_ci    LogLevel logLevel, const string_view filename, int lineNumber, const string_view format, std::va_list args)
1018bf80f4bSopenharmony_ci{
1028bf80f4bSopenharmony_ci    CORE_ASSERT_MSG(logLevel != LogLevel::LOG_NONE, "'None' is not a valid log level for writing to the log.");
1038bf80f4bSopenharmony_ci
1048bf80f4bSopenharmony_ci    if (logLevel_ > logLevel) {
1058bf80f4bSopenharmony_ci        return;
1068bf80f4bSopenharmony_ci    }
1078bf80f4bSopenharmony_ci
1088bf80f4bSopenharmony_ci    // we need to make a copy of the args, since the va_list can be in an undefined state after use.
1098bf80f4bSopenharmony_ci    std::va_list tmp;
1108bf80f4bSopenharmony_ci    va_copy(tmp, args);
1118bf80f4bSopenharmony_ci
1128bf80f4bSopenharmony_ci    // use vsnprintf to calculate the required size (not supported by the _s variant)
1138bf80f4bSopenharmony_ci    const int sizeNeeded = vsnprintf(nullptr, 0, format.data(), args) + 1;
1148bf80f4bSopenharmony_ci
1158bf80f4bSopenharmony_ci    std::lock_guard guard(loggerMutex_);
1168bf80f4bSopenharmony_ci
1178bf80f4bSopenharmony_ci    if (sizeNeeded > 0 && static_cast<size_t>(sizeNeeded) > buffer_.size()) {
1188bf80f4bSopenharmony_ci        buffer_.resize(static_cast<size_t>(sizeNeeded));
1198bf80f4bSopenharmony_ci    }
1208bf80f4bSopenharmony_ci
1218bf80f4bSopenharmony_ci    int ret = vsnprintf_s(buffer_.data(), buffer_.size(), buffer_.size() - 1, format.data(), tmp);
1228bf80f4bSopenharmony_ci    va_end(tmp);
1238bf80f4bSopenharmony_ci    if (ret < 0) {
1248bf80f4bSopenharmony_ci        return;
1258bf80f4bSopenharmony_ci    }
1268bf80f4bSopenharmony_ci
1278bf80f4bSopenharmony_ci    for (auto& output : outputs_) {
1288bf80f4bSopenharmony_ci        output->Write(logLevel, filename, lineNumber, buffer_.data());
1298bf80f4bSopenharmony_ci    }
1308bf80f4bSopenharmony_ci}
1318bf80f4bSopenharmony_ci
1328bf80f4bSopenharmony_civoid Logger::VLogOnce(const string_view id, LogLevel logLevel, const string_view filename, int lineNumber,
1338bf80f4bSopenharmony_ci    const string_view format, std::va_list args)
1348bf80f4bSopenharmony_ci{
1358bf80f4bSopenharmony_ci    std::lock_guard<std::mutex> guard(onceMutex_);
1368bf80f4bSopenharmony_ci
1378bf80f4bSopenharmony_ci    auto const [pos, inserted] = registeredOnce_.insert(string(id));
1388bf80f4bSopenharmony_ci    if (inserted) {
1398bf80f4bSopenharmony_ci        VLog(logLevel, filename, lineNumber, format, args);
1408bf80f4bSopenharmony_ci    }
1418bf80f4bSopenharmony_ci}
1428bf80f4bSopenharmony_ci
1438bf80f4bSopenharmony_cibool Logger::VLogAssert(const string_view filename, int lineNumber, bool expression, const string_view expressionString,
1448bf80f4bSopenharmony_ci    const string_view format, std::va_list args)
1458bf80f4bSopenharmony_ci{
1468bf80f4bSopenharmony_ci    if (!expression) {
1478bf80f4bSopenharmony_ci        char buffer[MAX_BUFFER_SIZE];
1488bf80f4bSopenharmony_ci        const int numWritten = vsnprintf_s(buffer, MAX_BUFFER_SIZE, MAX_BUFFER_SIZE - 1, format.data(), args);
1498bf80f4bSopenharmony_ci        if (numWritten >= 0) {
1508bf80f4bSopenharmony_ci            buffer[numWritten] = '\0';
1518bf80f4bSopenharmony_ci        } else {
1528bf80f4bSopenharmony_ci            buffer[0] = '\0';
1538bf80f4bSopenharmony_ci        }
1548bf80f4bSopenharmony_ci
1558bf80f4bSopenharmony_ci        Log(LogLevel::LOG_FATAL, filename, lineNumber, "Assert failed (%s). %s", expressionString.data(), buffer);
1568bf80f4bSopenharmony_ci
1578bf80f4bSopenharmony_ci#ifdef PLATFORM_HAS_JAVA
1588bf80f4bSopenharmony_ci        // Print also a java trace if available
1598bf80f4bSopenharmony_ci        Log(LogLevel::LOG_FATAL, filename, lineNumber, "Java trace:");
1608bf80f4bSopenharmony_ci        JNIEnv* env = java_internal::GetJavaEnv();
1618bf80f4bSopenharmony_ci        if (env) {
1628bf80f4bSopenharmony_ci            jclass cls = env->FindClass("java/lang/Exception");
1638bf80f4bSopenharmony_ci            if (cls) {
1648bf80f4bSopenharmony_ci                jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");
1658bf80f4bSopenharmony_ci                jobject exception = env->NewObject(cls, constructor);
1668bf80f4bSopenharmony_ci                jmethodID printStackTrace = env->GetMethodID(cls, "printStackTrace", "()V");
1678bf80f4bSopenharmony_ci                env->CallVoidMethod(exception, printStackTrace);
1688bf80f4bSopenharmony_ci                env->DeleteLocalRef(exception);
1698bf80f4bSopenharmony_ci            }
1708bf80f4bSopenharmony_ci        }
1718bf80f4bSopenharmony_ci#endif
1728bf80f4bSopenharmony_ci    }
1738bf80f4bSopenharmony_ci
1748bf80f4bSopenharmony_ci    return expression;
1758bf80f4bSopenharmony_ci}
1768bf80f4bSopenharmony_ci
1778bf80f4bSopenharmony_civoid Logger::CheckOnceReset()
1788bf80f4bSopenharmony_ci{
1798bf80f4bSopenharmony_ci    std::lock_guard<std::mutex> guard(onceMutex_);
1808bf80f4bSopenharmony_ci    registeredOnce_.clear();
1818bf80f4bSopenharmony_ci}
1828bf80f4bSopenharmony_ci
1838bf80f4bSopenharmony_ciFORMAT_FUNC(5, 6)
1848bf80f4bSopenharmony_civoid Logger::Log(
1858bf80f4bSopenharmony_ci    LogLevel logLevel, const string_view filename, int lineNumber, FORMAT_ATTRIBUTE const char* format, ...)
1868bf80f4bSopenharmony_ci{
1878bf80f4bSopenharmony_ci    std::va_list vl;
1888bf80f4bSopenharmony_ci    va_start(vl, format);
1898bf80f4bSopenharmony_ci    VLog(logLevel, filename, lineNumber, format, vl);
1908bf80f4bSopenharmony_ci    va_end(vl);
1918bf80f4bSopenharmony_ci}
1928bf80f4bSopenharmony_ci
1938bf80f4bSopenharmony_ciFORMAT_FUNC(6, 7)
1948bf80f4bSopenharmony_cibool Logger::LogAssert(const string_view filename, int lineNumber, bool expression, const string_view expressionString,
1958bf80f4bSopenharmony_ci    FORMAT_ATTRIBUTE const char* format, ...)
1968bf80f4bSopenharmony_ci{
1978bf80f4bSopenharmony_ci    if (!expression) {
1988bf80f4bSopenharmony_ci        std::va_list vl;
1998bf80f4bSopenharmony_ci        va_start(vl, format);
2008bf80f4bSopenharmony_ci        VLogAssert(filename, lineNumber, expression, expressionString, format, vl);
2018bf80f4bSopenharmony_ci        va_end(vl);
2028bf80f4bSopenharmony_ci    }
2038bf80f4bSopenharmony_ci    return expression;
2048bf80f4bSopenharmony_ci}
2058bf80f4bSopenharmony_ci
2068bf80f4bSopenharmony_ciILogger::LogLevel Logger::GetLogLevel() const
2078bf80f4bSopenharmony_ci{
2088bf80f4bSopenharmony_ci    return logLevel_;
2098bf80f4bSopenharmony_ci}
2108bf80f4bSopenharmony_ci
2118bf80f4bSopenharmony_civoid Logger::SetLogLevel(LogLevel logLevel)
2128bf80f4bSopenharmony_ci{
2138bf80f4bSopenharmony_ci    logLevel_ = logLevel;
2148bf80f4bSopenharmony_ci}
2158bf80f4bSopenharmony_ci
2168bf80f4bSopenharmony_civoid Logger::AddOutput(IOutput::Ptr output)
2178bf80f4bSopenharmony_ci{
2188bf80f4bSopenharmony_ci    if (output) {
2198bf80f4bSopenharmony_ci        std::lock_guard<std::mutex> guard(loggerMutex_);
2208bf80f4bSopenharmony_ci        outputs_.push_back(move(output));
2218bf80f4bSopenharmony_ci    }
2228bf80f4bSopenharmony_ci}
2238bf80f4bSopenharmony_ci
2248bf80f4bSopenharmony_ciconst IInterface* Logger::GetInterface(const Uid& uid) const
2258bf80f4bSopenharmony_ci{
2268bf80f4bSopenharmony_ci    if ((uid == ILogger::UID) || (uid == IInterface::UID)) {
2278bf80f4bSopenharmony_ci        return this;
2288bf80f4bSopenharmony_ci    }
2298bf80f4bSopenharmony_ci    return nullptr;
2308bf80f4bSopenharmony_ci}
2318bf80f4bSopenharmony_ci
2328bf80f4bSopenharmony_ciIInterface* Logger::GetInterface(const Uid& uid)
2338bf80f4bSopenharmony_ci{
2348bf80f4bSopenharmony_ci    if ((uid == ILogger::UID) || (uid == IInterface::UID)) {
2358bf80f4bSopenharmony_ci        return this;
2368bf80f4bSopenharmony_ci    }
2378bf80f4bSopenharmony_ci    return nullptr;
2388bf80f4bSopenharmony_ci}
2398bf80f4bSopenharmony_ci
2408bf80f4bSopenharmony_civoid Logger::Ref() {}
2418bf80f4bSopenharmony_ci
2428bf80f4bSopenharmony_civoid Logger::Unref() {}
2438bf80f4bSopenharmony_ciCORE_END_NAMESPACE()
244