diff --git a/frameworks/hilog_ndk/hilog_ndk.c b/frameworks/hilog_ndk/hilog_ndk.c index 1ebdbe06f20b60621cdcb554d9566de4f24abd08..d5d48067264fceea7c14206bd437250d73b1bc64 100644 --- a/frameworks/hilog_ndk/hilog_ndk.c +++ b/frameworks/hilog_ndk/hilog_ndk.c @@ -71,3 +71,8 @@ void OH_LOG_SetCallback(LogCallback callback) { return LOG_SetCallback(callback); } + +void OH_LOG_SetMinLogLevel(LogLevel level) +{ + return HiLogSetAppMinLogLevel(level); +} diff --git a/frameworks/libhilog/hilog_printf.cpp b/frameworks/libhilog/hilog_printf.cpp index 25ba4f761bd9f80ec1936af817c5d059546fd949..39fc65d3d106070101f371d402eb021deb40115e 100644 --- a/frameworks/libhilog/hilog_printf.cpp +++ b/frameworks/libhilog/hilog_printf.cpp @@ -56,6 +56,7 @@ using namespace std; using namespace OHOS::HiviewDFX; static RegisterFunc g_registerFunc = nullptr; static LogCallback g_logCallback = nullptr; +static int g_logLevel = LOG_LEVEL_MIN; static atomic_int g_hiLogGetIdCallCount = 0; // protected by static lock guard static char g_hiLogLastFatalMessage[MAX_LOG_LEN] = { 0 }; // MAX_lOG_LEN : 1024 @@ -94,6 +95,11 @@ void LOG_SetCallback(LogCallback callback) g_logCallback = callback; } +void HiLogSetAppMinLogLevel(LogLevel level) +{ + g_logLevel = level; +} + static uint16_t GetFinalLevel(unsigned int domain, const std::string& tag) { // Priority: TagLevel > DomainLevel > GlobalLevel @@ -375,8 +381,16 @@ int HiLogPrint(LogType type, LogLevel level, unsigned int domain, const char *ta return ret; } +static bool IsAppDomain(const unsigned int domain) +{ + return ((domain >= DOMAIN_APP_MIN) && (domain <= DOMAIN_APP_MAX)); +} + bool HiLogIsLoggable(unsigned int domain, const char *tag, LogLevel level) { + if (IsAppDomain(domain) && level < g_logLevel) { + return false; + } if ((level <= LOG_LEVEL_MIN) || (level >= LOG_LEVEL_MAX) || (tag == nullptr) || (domain >= DOMAIN_OS_MAX)) { return false; } diff --git a/interfaces/js/kits/napi/src/hilog/include/context/hilog_napi_base.h b/interfaces/js/kits/napi/src/hilog/include/context/hilog_napi_base.h index 026bbcb1f832df35f23474f981c888b65fcaef41..5e59f3c00e4db1811f7bf2dc79bfca46b8146d51 100644 --- a/interfaces/js/kits/napi/src/hilog/include/context/hilog_napi_base.h +++ b/interfaces/js/kits/napi/src/hilog/include/context/hilog_napi_base.h @@ -42,6 +42,7 @@ public: static napi_value SysLogError(napi_env env, napi_callback_info info); static napi_value SysLogFatal(napi_env env, napi_callback_info info); static napi_value IsLoggable(napi_env env, napi_callback_info info); + static napi_value SetMinLogLevel(napi_env env, napi_callback_info info); private: static napi_value parseNapiValue(napi_env env, napi_callback_info info, napi_value element, std::vector& params); diff --git a/interfaces/js/kits/napi/src/hilog/src/hilog_napi.cpp b/interfaces/js/kits/napi/src/hilog/src/hilog_napi.cpp index 30c18c1d522e6b010244445f7a6892b47b9cfc12..9349a941f99a4bf25d286cd712ab17e6a6c15af3 100644 --- a/interfaces/js/kits/napi/src/hilog/src/hilog_napi.cpp +++ b/interfaces/js/kits/napi/src/hilog/src/hilog_napi.cpp @@ -83,6 +83,7 @@ bool HilogNapi::Export(napi_env env, napi_value exports) NVal::DeclareNapiFunction("sLogE", HilogNapiBase::SysLogError), NVal::DeclareNapiFunction("sLogF", HilogNapiBase::SysLogFatal), NVal::DeclareNapiFunction("isLoggable", HilogNapiBase::IsLoggable), + NVal::DeclareNapiFunction("setMinLogLevel", HilogNapiBase::SetMinLogLevel), }); } diff --git a/interfaces/js/kits/napi/src/hilog/src/hilog_napi_base.cpp b/interfaces/js/kits/napi/src/hilog/src/hilog_napi_base.cpp index 9202348e650b8fcabfd858c39512ce435a5f8b26..4e5ca26dc7d500b99036fbb29786792bca41c0af 100644 --- a/interfaces/js/kits/napi/src/hilog/src/hilog_napi_base.cpp +++ b/interfaces/js/kits/napi/src/hilog/src/hilog_napi_base.cpp @@ -146,6 +146,22 @@ napi_value HilogNapiBase::IsLoggable(napi_env env, napi_callback_info info) return NVal::CreateBool(env, res).val_; } +napi_value HilogNapiBase::SetMinLogLevel(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE)) { + return nullptr; + } + bool succ = false; + int32_t level = LOG_LEVEL_MIN; + tie(succ, level) = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32(); + if (!succ) { + return nullptr; + } + HiLogSetAppMinLogLevel(static_cast(level)); + return nullptr; +} + napi_value HilogNapiBase::Debug(napi_env env, napi_callback_info info) { return HilogImpl(env, info, LOG_DEBUG, true); diff --git a/interfaces/native/innerkits/include/hilog/log_c.h b/interfaces/native/innerkits/include/hilog/log_c.h index b18641557817f1f6bec48a4c6daea67f7054fae0..2d4729b46d6f1d251ae4a3b52b8c661f98299501 100644 --- a/interfaces/native/innerkits/include/hilog/log_c.h +++ b/interfaces/native/innerkits/include/hilog/log_c.h @@ -151,6 +151,14 @@ typedef void (*LogCallback)(const LogType type, const LogLevel level, const unsi */ void LOG_SetCallback(LogCallback callback); +/** + * @brief Sets the lowest app log level of the current application process. + * + * @param level log level + * @since 16 + */ +void HiLogSetAppMinLogLevel(LogLevel level); + #ifdef __cplusplus } #endif diff --git a/interfaces/native/innerkits/libhilog.map b/interfaces/native/innerkits/libhilog.map index 72e1a8e1215c3f5d2d2d6923a2ebd4021a18b850..4dce8bbc08bf1d67fcfa5d8b68cd3fea89f810f8 100644 --- a/interfaces/native/innerkits/libhilog.map +++ b/interfaces/native/innerkits/libhilog.map @@ -11,6 +11,7 @@ HilogWriteLogMessage; GetLastFatalMessage; LOG_SetCallback; + HiLogSetAppMinLogLevel; }; extern "C++" { "OHOS::HiviewDFX::HiLog::Info(OHOS::HiviewDFX::HiLogLabel const&, char const*, ...)"; diff --git a/interfaces/native/kits/include/hilog/log.h b/interfaces/native/kits/include/hilog/log.h index e8f68ff59b522405a8130026e76e9245b0b92a73..a5764fa5cdf0a856686b5d0f16ad7be7f10360c7 100644 --- a/interfaces/native/kits/include/hilog/log.h +++ b/interfaces/native/kits/include/hilog/log.h @@ -338,6 +338,14 @@ typedef void (*LogCallback)(const LogType type, const LogLevel level, const unsi */ void OH_LOG_SetCallback(LogCallback callback); +/** + * @brief Set the lowest log level of the current application process. + * + * @param level log level + * @since 16 + */ +void OH_LOG_SetMinLogLevel(LogLevel level); + #ifdef __cplusplus } #endif diff --git a/interfaces/native/kits/libhilog.ndk.json b/interfaces/native/kits/libhilog.ndk.json index 2ca6bed2c0d93fcd9fbb3046ff370f17c696ba7e..f91e0e27e2ddc13afc1d0cd5888eb2ec228dbe67 100644 --- a/interfaces/native/kits/libhilog.ndk.json +++ b/interfaces/native/kits/libhilog.ndk.json @@ -7,5 +7,8 @@ }, { "name": "OH_LOG_SetCallback" + }, + { + "name": "OH_LOG_SetMinLogLevel" } ] diff --git a/test/BUILD.gn b/test/BUILD.gn index 87822317a8bdf0e0a880b5b2030b98c6293d8781..74f377c1c6926061f56af91e78177f3b27ab2ccd 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -42,6 +42,21 @@ ohos_moduletest("HiLogNDKTest") { ] } +ohos_moduletest("HiLogNDKZTest") { + module_out_path = module_output_path + + sources = [ "moduletest/common/hilog_ndk_z_test.cpp" ] + + configs = [ ":module_private_config" ] + + external_deps = [ + "hilog:hilog_ndk", + "init:libbegetutil", + ] + + include_dirs = [ "//base/hiviewdfx/hilog/interfaces/native/kits/include" ] +} + ohos_moduletest("HiLogAdapterTest") { module_out_path = module_output_path @@ -63,6 +78,7 @@ group("hilog_moduletest") { deps = [ ":HiLogAdapterTest", ":HiLogNDKTest", + ":HiLogNDKZTest", ] } diff --git a/test/moduletest/common/hilog_ndk_z_test.cpp b/test/moduletest/common/hilog_ndk_z_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3d023389f7358a8b824befcf327118851bb3449 --- /dev/null +++ b/test/moduletest/common/hilog_ndk_z_test.cpp @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2024 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hilog/log.h" +#include "parameters.h" + +#undef LOG_DOMAIN +#define LOG_DOMAIN 0x2D00 + +#undef LOG_TAG +#define LOG_TAG "HILOGTEST_C" + +using namespace testing::ext; + +namespace OHOS { +namespace HiviewDFX { +namespace HiLogTest { +static constexpr uint16_t SOME_LOGS = 10; +static constexpr uint16_t MORE_LOGS = 100; +static constexpr uint16_t OVER_LOGS = 1000; + +enum LogInterfaceType { + DEBUG_METHOD = 0, + INFO_METHOD = 1, + WARN_METHOD = 2, + ERROR_METHOD = 3, + FATAL_METHOD = 4, + METHODS_NUMBER = 5, +}; + +using LogMethodFunc = std::function; + +static const std::array LOG_C_METHODS = { + [] (const std::string &msg) { + OH_LOG_DEBUG(LOG_APP, "%{public}s", msg.c_str()); + }, + [] (const std::string &msg) { + OH_LOG_INFO(LOG_APP, "%{public}s", msg.c_str()); + }, + [] (const std::string &msg) { + OH_LOG_WARN(LOG_APP, "%{public}s", msg.c_str()); + }, + [] (const std::string &msg) { + OH_LOG_ERROR(LOG_APP, "%{public}s", msg.c_str()); + }, + [] (const std::string &msg) { + OH_LOG_FATAL(LOG_APP, "%{public}s", msg.c_str()); + }, +}; + +static std::string PopenToString(const std::string &command) +{ + std::string str; + constexpr int bufferSize = 1024; + FILE *fp = popen(command.c_str(), "re"); + if (fp != nullptr) { + char buf[bufferSize] = {0}; + size_t n = fread(buf, 1, sizeof(buf), fp); + while (n > 0) { + str.append(buf, n); + n = fread(buf, 1, sizeof(buf), fp); + } + pclose(fp); + } + std::cout << "PopenToString res: " << str << std::endl; + return str; +} + +class HiLogNDKZTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase() {} + void SetUp(); + void TearDown() {} +}; + +void HiLogNDKZTest::SetUpTestCase() +{ + (void)PopenToString("hilog -Q pidoff"); + (void)PopenToString("hilog -Q domainoff"); +} + +void HiLogNDKZTest::SetUp() +{ + (void)PopenToString("hilog -r"); +} + + +uint64_t RandomNum() +{ + std::random_device seed; + std::mt19937_64 gen(seed()); + std::uniform_int_distribution dis(0, std::numeric_limits::max()); + return dis(gen); +} + +static std::string RandomStringGenerator() +{ + std::string str; + int logLen = 16; + char index; + for (int i = 0; i < logLen; ++i) { + index = RandomNum() % ('z' - 'a') + 'a'; + str.append(1, index); + } + return str; +} + +static uint16_t HilogPrint(LogInterfaceType methodType, uint16_t count, + const std::array &logMethods) +{ + std::string logMsg(RandomStringGenerator()); + for (uint16_t i = 0; i < count; ++i) { + logMethods.at(methodType)(logMsg + std::to_string(i)); + } + usleep(1000); /* 1000: sleep 1 ms */ + std::string logMsgs = PopenToString("/system/bin/hilog -x"); + uint16_t realCount = 0; + std::stringstream ss(logMsgs); + std::string str; + while (!ss.eof()) { + getline(ss, str); + if (str.find(logMsg) != std::string::npos) { + ++realCount; + } + } + return realCount; +} + +static void HiLogWriteTest(LogInterfaceType methodType, uint16_t count, + const std::array &logMethods) +{ + uint16_t realCount = HilogPrint(methodType, count, logMethods); + uint16_t allowedLeastLogCount = count - count * 1 / 10; /* 1 / 10: loss rate less than 10% */ + if (methodType == DEBUG_METHOD) { + allowedLeastLogCount = 0; /* 0: debug log is allowed to be closed */ + } + EXPECT_GE(realCount, allowedLeastLogCount); +} + +static inline void HiLogWriteFailedTest(LogInterfaceType methodType, uint16_t count, + const std::array &logMethods) +{ + EXPECT_EQ(HilogPrint(methodType, count, logMethods), 0); +} + +static void FlowCtlTest(const std::string keyWord) +{ + const std::string str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + for (uint16_t i = 0; i < OVER_LOGS; ++i) { + OH_LOG_INFO(LOG_APP, "%{public}s:%{public}d", str.c_str(), i); + } + sleep(1); /* 1: sleep 1 s */ + OH_LOG_INFO(LOG_APP, "%{public}s", str.c_str()); + std::string logMsgs = PopenToString("hilog -x -T LOGLIMIT"); + EXPECT_TRUE(logMsgs.find(keyWord) != std::string::npos); +} + +/** + * @tc.name: Dfx_HiLogNDKZTest_PrintDebugLog_001 + * @tc.desc: Call OH_LOG_DEBUG to print logs. + * @tc.type: FUNC + */ +HWTEST_F(HiLogNDKZTest, PrintDebugLog_001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Call OH_LOG_DEBUG to print logs and call hilog to read it + * @tc.expected: step1. Logs can be printed only if hilog.debug is enabled. + */ + HiLogWriteTest(DEBUG_METHOD, SOME_LOGS, LOG_C_METHODS); +} + +/** + * @tc.name: Dfx_HiLogNDKZTest_PrintInfoLog_001 + * @tc.desc: Call OH_LOG_INFO to print logs. + * @tc.type: FUNC + */ +HWTEST_F(HiLogNDKZTest, PrintInfoLog_001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Call OH_LOG_INFO to print logs and call hilog to read it + * @tc.expected: step1. Logs printed without loss. + */ + HiLogWriteTest(INFO_METHOD, SOME_LOGS, LOG_C_METHODS); +} + +/** + * @tc.name: Dfx_HiLogNDKZTest_PrintWarnLog_001 + * @tc.desc: Call OH_LOG_WARN to print logs. + * @tc.type: FUNC + */ +HWTEST_F(HiLogNDKZTest, PrintWarnLog_001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Call OH_LOG_WARN to print logs and call hilog to read it + * @tc.expected: step1. Logs printed without loss. + */ + HiLogWriteTest(WARN_METHOD, SOME_LOGS, LOG_C_METHODS); +} + +/** + * @tc.name: Dfx_HiLogNDKZTest_PrintErrorLog_001 + * @tc.desc: Call OH_LOG_ERROR to print logs. + * @tc.type: FUNC + */ +HWTEST_F(HiLogNDKZTest, PrintErrorLog_001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Call OH_LOG_ERROR to print logs and call hilog to read it + * @tc.expected: step1. Logs printed without loss. + */ + HiLogWriteTest(ERROR_METHOD, SOME_LOGS, LOG_C_METHODS); +} + +/** + * @tc.name: Dfx_HiLogNDKZTest_PrintFatalLog_001 + * @tc.desc: Call OH_LOG_FATAL to print logs. + * @tc.type: FUNC + */ +HWTEST_F(HiLogNDKZTest, PrintFatalLog_001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Call OH_LOG_FATAL to print logs and call hilog to read it + * @tc.expected: step1. Logs printed without loss. + */ + HiLogWriteTest(FATAL_METHOD, SOME_LOGS, LOG_C_METHODS); +} + +/** + * @tc.name: Dfx_HiLogNDKZTest_LogLossCheck_001 + * @tc.desc: HiLog log loss rate must less than 10%. + * @tc.type: FUNC + */ +HWTEST_F(HiLogNDKZTest, LogLossCheck_001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Call OH_LOG_INFO to print logs and call hilog to read it + * @tc.expected: step1. Calculate log loss rate and it should less than 10% + */ + HiLogWriteTest(INFO_METHOD, MORE_LOGS, LOG_C_METHODS); +} + +/** + * @tc.name: Dfx_HiLogNDKZTest_IsLoggable_001 + * @tc.desc: Check whether is loggable for each log level + * @tc.type: FUNC + */ +HWTEST_F(HiLogNDKZTest, IsLoggable_001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Call OH_LOG_IsLoggable to check whether is loggable for each log level. + * @tc.expected: step1. LOG_DEBUG and lower level should return false in release version, and others return true. + */ + if (OHOS::system::GetParameter("hilog.loggable.global", "D") == "D") { + EXPECT_TRUE(OH_LOG_IsLoggable(0x2D00, LOG_TAG, LOG_DEBUG)); + } else { + EXPECT_FALSE(OH_LOG_IsLoggable(0x2D00, LOG_TAG, LOG_DEBUG)); + } + EXPECT_TRUE(OH_LOG_IsLoggable(0x2D00, LOG_TAG, LOG_INFO)); + EXPECT_TRUE(OH_LOG_IsLoggable(0x2D00, LOG_TAG, LOG_WARN)); + EXPECT_TRUE(OH_LOG_IsLoggable(0x2D00, LOG_TAG, LOG_ERROR)); + EXPECT_TRUE(OH_LOG_IsLoggable(0x2D00, LOG_TAG, LOG_FATAL)); + EXPECT_TRUE(OH_LOG_IsLoggable(0x2D00, "abc", LOG_WARN)); +} + + +/** + * @tc.name: Dfx_HiLogNDKZTest_hilogSocketTest + * @tc.desc: Query hilog socket rights + * @tc.type: FUNC + * @tc.require:issueI5NU7F + */ +HWTEST_F(HiLogNDKZTest, hilogSocketTest, TestSize.Level1) +{ + std::string str; + std::string hilogControlRights = "srw-rw----"; + std::string logMsgs = PopenToString("ls -al //dev/unix/socket/hilogControl"); + std::stringstream ss(logMsgs); + getline(ss, str); + EXPECT_TRUE(str.find(hilogControlRights) != std::string::npos); +} + +/** + * @tc.name: Dfx_HiLogNDKZTest_pidFlowCtrlTest + * @tc.desc: hilog pidFlowCtrlTest + * @tc.type: FUNC + */ +HWTEST_F(HiLogNDKZTest, pidFlowCtrlTest, TestSize.Level1) +{ + (void)PopenToString("hilog -Q pidon"); + const std::string pidCtrlLog = "DROPPED"; + FlowCtlTest(pidCtrlLog); + (void)PopenToString("hilog -Q pidoff"); +} + +/** + * @tc.name: Dfx_HiLogNDKZTest_SetMinLevelTest + * @tc.desc: hilog setMinLevelTest + * @tc.type: FUNC + */ +HWTEST_F(HiLogNDKZTest, setMinLevelTest, TestSize.Level1) +{ + HiLogWriteTest(INFO_METHOD, SOME_LOGS, LOG_C_METHODS); + OH_LOG_SetMinLogLevel(LOG_WARN); + HiLogWriteFailedTest(INFO_METHOD, SOME_LOGS, LOG_C_METHODS); + OH_LOG_SetMinLogLevel(LOG_DEBUG); + HiLogWriteFailedTest(DEBUG_METHOD, SOME_LOGS, LOG_C_METHODS); + HiLogWriteTest(INFO_METHOD, SOME_LOGS, LOG_C_METHODS); +} + +} // namespace HiLogTest +} // namespace HiviewDFX +} // namespace OHOS