1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "properties.h"
17 #include "hilog_common.h"
18 #include "hilog/log.h"
19 #include "hilog/log_c.h"
20 #include "hilog_napi_base.h"
21 #include "napi/native_api.h"
22 #include "napi/native_node_api.h"
23 #include "n_func_arg.h"
24 #include "n_class.h"
25 #include "securec.h"
26 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30 namespace OHOS {
31 namespace HiviewDFX {
32 using namespace std;
33 const HiLogLabel LABEL = { LOG_CORE, 0xD002D00, "Hilog_JS" };
34 static constexpr int MIN_NUMBER = 3;
35 static constexpr int MAX_NUMBER = 100;
36 static constexpr int PUBLIC_LEN = 6;
37 static constexpr int PRIVATE_LEN = 7;
38 static constexpr int PROPERTY_POS = 2;
39 static const string PRIV_STR = "<private>";
40 
ParseLogContent(string & formatStr,vector<napiParam> & params,string & logContent)41 void ParseLogContent(string& formatStr, vector<napiParam>& params, string& logContent)
42 {
43     string& ret = logContent;
44     if (params.empty()) {
45         ret += formatStr;
46         return;
47     }
48     auto size = params.size();
49     auto len = formatStr.size();
50     uint32_t pos = 0;
51     uint32_t count = 0;
52     bool debug = true;
53 #if not (defined(__WINDOWS__) || defined(__MAC__) || defined(__LINUX__))
54     debug = IsDebugOn();
55 #endif
56     bool priv = (!debug) && IsPrivateSwitchOn();
57     for (; pos < len; ++pos) {
58         bool showPriv = true;
59         if (count >= size) {
60             break;
61         }
62         if (formatStr[pos] != '%') {
63             ret += formatStr[pos];
64             continue;
65         }
66 
67         if (((pos + PUBLIC_LEN + PROPERTY_POS) < len) &&
68             formatStr.substr(pos + PROPERTY_POS, PUBLIC_LEN) == "public") {
69             pos += (PUBLIC_LEN + PROPERTY_POS);
70             showPriv = false;
71         } else if (((pos + PRIVATE_LEN + PROPERTY_POS) < len) &&
72             formatStr.substr(pos + PROPERTY_POS, PRIVATE_LEN) == "private") {
73             pos += (PRIVATE_LEN + PROPERTY_POS);
74         }
75 
76         if (pos + 1 >= len) {
77             break;
78         }
79         switch (formatStr[pos + 1]) {
80             case 'd':
81             case 'i':
82                 if (params[count].type == napi_number || params[count].type == napi_bigint) {
83                     ret += (priv && showPriv) ? PRIV_STR : params[count].val;
84                 }
85                 count++;
86                 ++pos;
87                 break;
88             case 's':
89                 if (params[count].type == napi_string || params[count].type == napi_undefined ||
90                     params[count].type == napi_boolean || params[count].type == napi_null) {
91                     ret += (priv && showPriv) ? PRIV_STR : params[count].val;
92                 }
93                 count++;
94                 ++pos;
95                 break;
96             case 'O':
97             case 'o':
98                 if (params[count].type == napi_object) {
99                     ret += (priv && showPriv) ? PRIV_STR : params[count].val;
100                 }
101                 count++;
102                 ++pos;
103                 break;
104             case '%':
105                 ret += formatStr[pos];
106                 ++pos;
107                 break;
108             default:
109                 ret += formatStr[pos];
110                 break;
111         }
112     }
113     if (pos < len) {
114         ret += formatStr.substr(pos, len - pos);
115     }
116     return;
117 }
118 
IsLoggable(napi_env env,napi_callback_info info)119 napi_value HilogNapiBase::IsLoggable(napi_env env, napi_callback_info info)
120 {
121     NFuncArg funcArg(env, info);
122 
123     if (!funcArg.InitArgs(NARG_CNT::THREE)) {
124         return nullptr;
125     }
126     bool succ = false;
127     int32_t domain;
128     tie(succ, domain) = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
129     if (!succ) {
130         return nullptr;
131     }
132     if ((domain < static_cast<int32_t>(DOMAIN_APP_MIN)) || (domain > static_cast<int32_t>(DOMAIN_APP_MAX))) {
133         return NVal::CreateBool(env, false).val_;
134     }
135     int32_t level;
136     tie(succ, level) = NVal(env, funcArg[NARG_POS::THIRD]).ToInt32();
137     if (!succ) {
138         return nullptr;
139     }
140     unique_ptr<char[]> tag;
141     tie(succ, tag, ignore) = NVal(env, funcArg[NARG_POS::SECOND]).ToUTF8String();
142     if (!succ) {
143         return nullptr;
144     }
145     bool res = HiLogIsLoggable(domain, tag.get(), static_cast<LogLevel>(level));
146     return NVal::CreateBool(env, res).val_;
147 }
148 
Debug(napi_env env,napi_callback_info info)149 napi_value HilogNapiBase::Debug(napi_env env, napi_callback_info info)
150 {
151     return HilogImpl(env, info, LOG_DEBUG, true);
152 }
153 
Info(napi_env env,napi_callback_info info)154 napi_value HilogNapiBase::Info(napi_env env, napi_callback_info info)
155 {
156     return HilogImpl(env, info, LOG_INFO, true);
157 }
158 
Warn(napi_env env,napi_callback_info info)159 napi_value HilogNapiBase::Warn(napi_env env, napi_callback_info info)
160 {
161     return HilogImpl(env, info, LOG_WARN, true);
162 }
163 
Error(napi_env env,napi_callback_info info)164 napi_value HilogNapiBase::Error(napi_env env, napi_callback_info info)
165 {
166     return HilogImpl(env, info, LOG_ERROR, true);
167 }
168 
Fatal(napi_env env,napi_callback_info info)169 napi_value HilogNapiBase::Fatal(napi_env env, napi_callback_info info)
170 {
171     return HilogImpl(env, info, LOG_FATAL, true);
172 }
173 
SysLogDebug(napi_env env,napi_callback_info info)174 napi_value HilogNapiBase::SysLogDebug(napi_env env, napi_callback_info info)
175 {
176     return HilogImpl(env, info, LOG_DEBUG, false);
177 }
178 
SysLogInfo(napi_env env,napi_callback_info info)179 napi_value HilogNapiBase::SysLogInfo(napi_env env, napi_callback_info info)
180 {
181     return HilogImpl(env, info, LOG_INFO, false);
182 }
183 
SysLogWarn(napi_env env,napi_callback_info info)184 napi_value HilogNapiBase::SysLogWarn(napi_env env, napi_callback_info info)
185 {
186     return HilogImpl(env, info, LOG_WARN, false);
187 }
188 
SysLogError(napi_env env,napi_callback_info info)189 napi_value HilogNapiBase::SysLogError(napi_env env, napi_callback_info info)
190 {
191     return HilogImpl(env, info, LOG_ERROR, false);
192 }
193 
SysLogFatal(napi_env env,napi_callback_info info)194 napi_value HilogNapiBase::SysLogFatal(napi_env env, napi_callback_info info)
195 {
196     return HilogImpl(env, info, LOG_FATAL, false);
197 }
198 
parseNapiValue(napi_env env,napi_callback_info info,napi_value element,vector<napiParam> & params)199 napi_value HilogNapiBase::parseNapiValue(napi_env env, napi_callback_info info,
200     napi_value element, vector<napiParam>& params)
201 {
202     bool succ = false;
203     napi_valuetype type;
204     napiParam res = {napi_null, ""};
205     napi_status typeStatus = napi_typeof(env, element, &type);
206     unique_ptr<char[]> name;
207     if (typeStatus != napi_ok) {
208         return nullptr;
209     }
210     if (type == napi_number || type == napi_bigint || type == napi_object ||
211         type == napi_undefined || type == napi_boolean || type == napi_null) {
212         napi_value elmString;
213         napi_status objectStatus = napi_coerce_to_string(env, element, &elmString);
214         if (objectStatus != napi_ok) {
215             return nullptr;
216         }
217         tie(succ, name, ignore) = NVal(env, elmString).ToUTF8String();
218         if (!succ) {
219             return nullptr;
220         }
221     } else if (type == napi_string) {
222         tie(succ, name, ignore) = NVal(env, element).ToUTF8String();
223         if (!succ) {
224             return nullptr;
225         }
226     } else {
227         HiLog::Info(LABEL, "%{public}s", "type mismatch");
228     }
229     res.type = type;
230     if (name != nullptr) {
231         res.val = name.get();
232     }
233     params.emplace_back(res);
234     return nullptr;
235 }
236 
HilogImpl(napi_env env,napi_callback_info info,int level,bool isAppLog)237 napi_value HilogNapiBase::HilogImpl(napi_env env, napi_callback_info info, int level, bool isAppLog)
238 {
239     NFuncArg funcArg(env, info);
240     funcArg.InitArgs(MIN_NUMBER, MAX_NUMBER);
241     bool succ = false;
242     int32_t domain;
243     tie(succ, domain) = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
244     if (!succ) {
245         HiLog::Info(LABEL, "%{public}s", "domain mismatch");
246         return nullptr;
247     }
248     unique_ptr<char[]> tag;
249     tie(succ, tag, ignore) = NVal(env, funcArg[NARG_POS::SECOND]).ToUTF8String();
250     if (!succ) {
251         HiLog::Info(LABEL, "%{public}s", "tag mismatch");
252         return nullptr;
253     }
254     unique_ptr<char[]> fmt;
255     tie(succ, fmt, ignore) = NVal(env, funcArg[NARG_POS::THIRD]).ToUTF8String();
256     if (!succ) {
257         HiLog::Info(LABEL, "%{public}s", "Format mismatch");
258         return nullptr;
259     }
260     string fmtString = fmt.get();
261     bool res = false;
262     napi_value array = funcArg[NARG_POS::FOURTH];
263     napi_is_array(env, array, &res);
264     string logContent;
265     vector<napiParam> params;
266     if (!res) {
267         for (size_t i = MIN_NUMBER; i < funcArg.GetArgc(); i++) {
268             napi_value argsVal = funcArg[i];
269             (void)parseNapiValue(env, info, argsVal, params);
270         }
271     } else {
272         if (funcArg.GetArgc() != MIN_NUMBER + 1) {
273             NAPI_ASSERT(env, false, "Argc mismatch");
274             HiLog::Info(LABEL, "%{public}s", "Argc mismatch");
275             return nullptr;
276         }
277         uint32_t length;
278         napi_status lengthStatus = napi_get_array_length(env, array, &length);
279         if (lengthStatus != napi_ok) {
280             return nullptr;
281         }
282         uint32_t i;
283         for (i = 0; i < length; i++) {
284             napi_value element;
285             napi_status eleStatus = napi_get_element(env, array, i, &element);
286             if (eleStatus != napi_ok) {
287                 return nullptr;
288             }
289             (void)parseNapiValue(env, info, element, params);
290         }
291     }
292     ParseLogContent(fmtString, params, logContent);
293     HiLogPrint((isAppLog ? LOG_APP : LOG_CORE),
294         static_cast<LogLevel>(level), domain, tag.get(), "%{public}s", logContent.c_str());
295     return nullptr;
296 }
297 }  // namespace HiviewDFX
298 }  // namespace OHOS
299 
300 #ifdef __cplusplus
301 }
302 #endif
303