1 /*
2 * Copyright (c) 2023 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 #include "console.h"
16 #include "log.h"
17
18 namespace OHOS::JsSysModule {
19 using namespace Commonlibrary::Concurrent::Common;
20
21 thread_local std::map<std::string, int64_t> Console::timerMap;
22 thread_local std::map<std::string, uint32_t> Console::counterMap;
23 thread_local std::string Console::groupIndent;
24 constexpr size_t GROUPINDETATIONWIDTH = 2; // 2 : indentation
25 constexpr uint32_t SECOND = 1000;
26 constexpr uint32_t MINUTE = 60 * SECOND;
27 constexpr uint32_t HOUR = 60 * MINUTE;
28
29 std::map<std::string, std::string> tableChars = {
30 {"middleMiddle", "─"},
31 {"rowMiddle", "┼"},
32 {"topRight", "┐"},
33 {"topLeft", "┌"},
34 {"leftMiddle", "├"},
35 {"topMiddle", "┬"},
36 {"bottomRight", "┘"},
37 {"bottomLeft", "└"},
38 {"bottomMiddle", "┴"},
39 {"rightMiddle", "┤"},
40 {"left", "│ "},
41 {"right", " │"},
42 {"middle", " │ "},
43 };
44
LogPrint(LogLevel level,const char * content)45 void Console::LogPrint(LogLevel level, const char* content)
46 {
47 switch (level) {
48 case LogLevel::DEBUG:
49 HILOG_DEBUG("%{public}s", content);
50 break;
51 case LogLevel::INFO:
52 HILOG_INFO("%{public}s", content);
53 break;
54 case LogLevel::WARN:
55 HILOG_WARN("%{public}s", content);
56 break;
57 case LogLevel::ERROR:
58 HILOG_ERROR("%{public}s", content);
59 break;
60 case LogLevel::FATAL:
61 HILOG_FATAL("%{public}s", content);
62 break;
63 default:
64 HILOG_FATAL("Console::LogPrint: this branch is unreachable");
65 }
66 }
67
ParseLogContent(const std::vector<std::string> & params)68 std::string Console::ParseLogContent(const std::vector<std::string>& params)
69 {
70 std::string ret;
71 if (params.empty()) {
72 return ret;
73 }
74 std::string formatStr = params[0];
75 size_t size = params.size();
76 size_t len = formatStr.size();
77 size_t pos = 0;
78 size_t count = 1;
79 for (; pos < len; ++pos) {
80 if (count >= size) {
81 break;
82 }
83 if (formatStr[pos] == '%') {
84 if (pos + 1 >= len) {
85 break;
86 }
87 switch (formatStr[pos + 1]) {
88 case 's':
89 case 'j':
90 case 'd':
91 case 'O':
92 case 'o':
93 case 'i':
94 case 'f':
95 case 'c':
96 ret += params[count++];
97 ++pos;
98 break;
99 case '%':
100 ret += formatStr[pos];
101 ++pos;
102 break;
103 default:
104 ret += formatStr[pos];
105 break;
106 }
107 } else {
108 ret += formatStr[pos];
109 }
110 }
111 if (pos < len) {
112 ret += formatStr.substr(pos, len - pos);
113 }
114 for (; count < size; ++count) {
115 ret += " ";
116 ret += params[count];
117 }
118 return ret;
119 }
120
MakeLogContent(napi_env env,napi_callback_info info,size_t & argc,size_t startIdx,bool format)121 std::string Console::MakeLogContent(napi_env env, napi_callback_info info, size_t& argc, size_t startIdx, bool format)
122 {
123 std::vector<std::string> content;
124 content.reserve(argc);
125 // get argv
126 napi_value* argv = new napi_value[argc];
127 Helper::ObjectScope<napi_value> scope(argv, true);
128 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
129
130 for (size_t i = startIdx; i < argc; i++) {
131 if (!Helper::NapiHelper::IsString(env, argv[i])) {
132 napi_value buffer;
133 napi_status status = napi_coerce_to_string(env, argv[i], &buffer);
134 if (status != napi_ok) {
135 HILOG_ERROR("Console log failed to convert to string object");
136 continue;
137 }
138 argv[i] = buffer;
139 }
140 std::string stringValue = Helper::NapiHelper::GetPrintString(env, argv[i]);
141 if (stringValue.empty()) {
142 continue;
143 }
144 content.emplace_back(stringValue);
145 }
146 if (format) {
147 return ParseLogContent(content);
148 } else {
149 std::string ret;
150 size_t size = content.size();
151 for (size_t i = 0; i < size; ++i) {
152 ret += " ";
153 ret += content[i];
154 }
155 return ret;
156 }
157 }
158
StringRepeat(size_t number,const std::string & tableChars)159 std::string Console::StringRepeat(size_t number, const std::string& tableChars)
160 {
161 std::string divider;
162 size_t length = number;
163 for (size_t i = 0; i < length; i++) {
164 divider += tableChars;
165 }
166 return divider;
167 }
168
169
170 template<LogLevel LEVEL>
ConsoleLog(napi_env env,napi_callback_info info)171 napi_value Console::ConsoleLog(napi_env env, napi_callback_info info)
172 {
173 size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
174 if (argc < 1) {
175 return Helper::NapiHelper::GetUndefinedValue(env);
176 }
177 std::string content;
178 content += groupIndent;
179 content += MakeLogContent(env, info, argc, 0); // startInx = 0
180 LogPrint(LEVEL, content.c_str());
181 return Helper::NapiHelper::GetUndefinedValue(env);
182 }
183
GetTimerOrCounterName(napi_env env,napi_callback_info info,size_t argc)184 std::string Console::GetTimerOrCounterName(napi_env env, napi_callback_info info, size_t argc)
185 {
186 if (argc < 1) {
187 return "default";
188 }
189 napi_value* argv = new napi_value[argc];
190 Helper::ObjectScope<napi_value> scope(argv, true);
191 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
192 if (!Helper::NapiHelper::IsString(env, argv[0])) {
193 napi_value buffer = nullptr;
194 napi_status status = napi_coerce_to_string(env, argv[0], &buffer);
195 if (status != napi_ok) {
196 Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
197 "the type of Timer or Counter name must be string.");
198 return "";
199 }
200 argv[0] = buffer;
201 }
202 std::string name = Helper::NapiHelper::GetPrintString(env, argv[0]);
203 if (name.empty()) {
204 Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
205 "Timer or Counter name must be not null.");
206 return "";
207 }
208 return name;
209 }
210
Count(napi_env env,napi_callback_info info)211 napi_value Console::Count(napi_env env, napi_callback_info info)
212 {
213 size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
214 std::string counterName = GetTimerOrCounterName(env, info, argc);
215 counterMap[counterName]++;
216 HILOG_INFO("%{public}s%{public}s: %{public}d",
217 groupIndent.c_str(), counterName.c_str(), counterMap[counterName]);
218 return Helper::NapiHelper::GetUndefinedValue(env);
219 }
220
CountReset(napi_env env,napi_callback_info info)221 napi_value Console::CountReset(napi_env env, napi_callback_info info)
222 {
223 size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
224 std::string counterName = GetTimerOrCounterName(env, info, argc);
225 if (counterMap.find(counterName) == counterMap.end()) {
226 HILOG_WARN("%{public}sCounter %{public}s doesn't exists, please check Counter Name.",
227 groupIndent.c_str(), counterName.c_str());
228 return Helper::NapiHelper::GetUndefinedValue(env);
229 }
230 counterMap.erase(counterName);
231 return Helper::NapiHelper::GetUndefinedValue(env);
232 }
233
Dir(napi_env env,napi_callback_info info)234 napi_value Console::Dir(napi_env env, napi_callback_info info)
235 {
236 size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
237 if (argc < 1) {
238 HILOG_INFO("%{public}sundefined", groupIndent.c_str());
239 return Helper::NapiHelper::GetUndefinedValue(env);
240 }
241 napi_value* argv = new napi_value[argc];
242 Helper::ObjectScope<napi_value> scope(argv, true);
243 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
244 std::string ctorVal = Helper::NapiHelper::GetConstructorName(env, argv[0]);
245 // JSON.stringify()
246 napi_value globalValue = nullptr;
247 napi_get_global(env, &globalValue);
248 napi_value jsonValue;
249 napi_get_named_property(env, globalValue, "JSON", &jsonValue);
250 napi_value stringifyValue = nullptr;
251 napi_get_named_property(env, jsonValue, "stringify", &stringifyValue);
252 napi_value transValue = nullptr;
253 napi_call_function(env, jsonValue, stringifyValue, 1, &argv[0], &transValue);
254 if (transValue == nullptr) {
255 Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR, "Dir content must not be null.");
256 return Helper::NapiHelper::GetUndefinedValue(env);
257 }
258 std::string content = Helper::NapiHelper::GetPrintString(env, transValue);
259 bool functionFlag = Helper::NapiHelper::IsFunction(env, argv[0]);
260 if (!ctorVal.empty() && !functionFlag) {
261 HILOG_INFO("%{public}s%{public}s: %{public}s", groupIndent.c_str(), ctorVal.c_str(), content.c_str());
262 } else if (!ctorVal.empty() && functionFlag) {
263 HILOG_INFO("%{public}s[Function %{public}s]", groupIndent.c_str(), ctorVal.c_str());
264 } else {
265 HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), content.c_str());
266 }
267 return Helper::NapiHelper::GetUndefinedValue(env);
268 }
269
Group(napi_env env,napi_callback_info info)270 napi_value Console::Group(napi_env env, napi_callback_info info)
271 {
272 size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
273 if (argc > 0) {
274 ConsoleLog<LogLevel::INFO>(env, info);
275 }
276 groupIndent += StringRepeat(GROUPINDETATIONWIDTH, " ");
277 return Helper::NapiHelper::GetUndefinedValue(env);
278 }
279
GroupEnd(napi_env env,napi_callback_info info)280 napi_value Console::GroupEnd(napi_env env, napi_callback_info info)
281 {
282 size_t length = groupIndent.size();
283 if (length >= GROUPINDETATIONWIDTH) {
284 groupIndent = groupIndent.substr(0, length - GROUPINDETATIONWIDTH);
285 }
286 return Helper::NapiHelper::GetUndefinedValue(env);
287 }
288
ArrayJoin(std::vector<std::string> rowDivider,const std::string & tableChars)289 std::string Console::ArrayJoin(std::vector<std::string> rowDivider, const std::string& tableChars)
290 {
291 size_t size = rowDivider.size();
292 if (size == 0) {
293 return "no rowDivider";
294 }
295 std::string result = rowDivider[0];
296 for (size_t i = 1; i < size; i++) {
297 result += tableChars;
298 result += rowDivider[i];
299 }
300 return result;
301 }
302
RenderHead(napi_env env,napi_value head,std::vector<size_t> columnWidths)303 std::string Console::RenderHead(napi_env env, napi_value head, std::vector<size_t> columnWidths)
304 {
305 std::string result = tableChars["left"];
306 size_t length = columnWidths.size();
307 for (size_t i = 0; i < length; i++) {
308 napi_value element = nullptr;
309 napi_get_element(env, head, i, &element);
310 napi_value string = nullptr;
311 napi_status status = napi_coerce_to_string(env, element, &string);
312 if (status != napi_ok) {
313 Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
314 "Table elements can't convert to string.");
315 return "";
316 }
317 std::string elemStr = Helper::NapiHelper::GetPrintString(env, string);
318 size_t stringLen = elemStr.size();
319 size_t left = (columnWidths[i] - stringLen) / 2; // 2: half
320 size_t right = columnWidths[i] - stringLen - left;
321 result += StringRepeat(left, " ") + elemStr + StringRepeat(right, " ");
322 if (i != length - 1) {
323 result += tableChars["middle"];
324 }
325 }
326 result += tableChars["right"];
327 return result;
328 }
329
GetStringAndStringWidth(napi_env env,napi_value element,size_t & stringLen)330 std::string Console::GetStringAndStringWidth(napi_env env, napi_value element, size_t& stringLen)
331 {
332 napi_value string = nullptr;
333 napi_status status = napi_coerce_to_string(env, element, &string);
334 if (status != napi_ok) {
335 Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
336 "GetStringAndStringWidth: can't convert to string.");
337 return "";
338 }
339 std::string result = Helper::NapiHelper::GetPrintString(env, string);
340 napi_valuetype valuetype;
341 napi_typeof(env, element, &valuetype);
342 if (valuetype != napi_undefined) {
343 stringLen = result.size(); // If element type is undefined, length is 0.
344 }
345 return result;
346 }
347
PrintRows(napi_env env,napi_value Rows,std::vector<size_t> columnWidths,size_t indexNum)348 void Console::PrintRows(napi_env env, napi_value Rows, std::vector<size_t> columnWidths, size_t indexNum)
349 {
350 size_t length = columnWidths.size();
351 for (size_t i = 0; i < indexNum; i++) {
352 std::string result = tableChars["left"];
353 for (size_t j = 0; j < length; j++) {
354 napi_value element = nullptr;
355 napi_get_element(env, Rows, j * indexNum + i, &element);
356 size_t stringLen = 0;
357 std::string stringVal = GetStringAndStringWidth(env, element, stringLen);
358 if (stringLen > 0) {
359 size_t left = (columnWidths[j] - stringLen) / 2; // 2: half
360 size_t right = columnWidths[j] - stringLen - left;
361 result += StringRepeat(left, " ") + stringVal + StringRepeat(right, " ");
362 } else {
363 result += StringRepeat(columnWidths[j], " ");
364 }
365 if (j != length - 1) {
366 result += tableChars["middle"];
367 }
368 }
369 result += tableChars["right"];
370 HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), result.c_str());
371 }
372 }
373
GraphTable(napi_env env,napi_value head,napi_value columns,const size_t & length)374 void Console::GraphTable(napi_env env, napi_value head, napi_value columns, const size_t& length)
375 {
376 uint32_t columnLen = 0;
377 napi_get_array_length(env, head, &columnLen);
378 std::vector<size_t> columnWidths(columnLen);
379 std::vector<std::string> rowDivider(columnLen);
380 // get maxColumnWidths and get rowDivider(------)
381 // get key string length
382 for (size_t i = 0; i < columnLen; i++) {
383 napi_value element = nullptr;
384 napi_get_element(env, head, i, &element);
385 size_t stringLen = 0;
386 GetStringAndStringWidth(env, element, stringLen);
387 columnWidths[i] = stringLen;
388 }
389 // compare key/value string and get max length
390 for (size_t i = 0; i < columnLen; i++) {
391 for (size_t j = 0; j < length; j++) {
392 napi_value element = nullptr;
393 napi_get_element(env, columns, i * length + j, &element);
394 size_t stringLen = 0;
395 GetStringAndStringWidth(env, element, stringLen);
396 columnWidths[i] = columnWidths[i] > stringLen ? columnWidths[i] : stringLen;
397 }
398 rowDivider[i] = StringRepeat(columnWidths[i] + 2, tableChars["middleMiddle"]); // 2: two space
399 }
400 // print head row
401 std::string indexRow1 = tableChars["topLeft"] +
402 ArrayJoin(rowDivider, tableChars["topMiddle"]) +
403 tableChars["topRight"];
404 std::string indexRow2 = RenderHead(env, head, columnWidths);
405 std::string indexRow3 = tableChars["leftMiddle"] +
406 ArrayJoin(rowDivider, tableChars["rowMiddle"]) +
407 tableChars["rightMiddle"];
408 HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), indexRow1.c_str());
409 HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), indexRow2.c_str());
410 HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), indexRow3.c_str());
411 // print value row
412 PrintRows(env, columns, columnWidths, length);
413 // print end row
414 std::string endRow = tableChars["bottomLeft"] +
415 ArrayJoin(rowDivider, tableChars["bottomMiddle"]) +
416 tableChars["bottomRight"];
417 HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), endRow.c_str());
418 }
419
GetKeyArray(napi_env env,napi_value map)420 napi_value GetKeyArray(napi_env env, napi_value map)
421 {
422 napi_value mapKeys = nullptr;
423 napi_object_get_keys(env, map, &mapKeys);
424 uint32_t maplen = 0;
425 napi_get_array_length(env, mapKeys, &maplen);
426
427 size_t keyLength = maplen + 1;
428 napi_value outputKeysArray = nullptr;
429 napi_create_array_with_length(env, keyLength, &outputKeysArray);
430 // set (index) to array
431 napi_value result = nullptr;
432 napi_create_string_utf8(env, "(index)", NAPI_AUTO_LENGTH, &result);
433 napi_set_element(env, outputKeysArray, 0, result);
434
435 // set Keys to array
436 for (size_t j = 0; j < maplen ; ++j) {
437 napi_value keyNumber = nullptr;
438 napi_get_element(env, mapKeys, j, &keyNumber);
439 napi_set_element(env, outputKeysArray, j + 1, keyNumber); // startkeyIdx = 1
440 }
441 return outputKeysArray;
442 }
443
GetValueArray(napi_env env,napi_value map,const size_t & length,napi_value keyArray)444 napi_value GetValueArray(napi_env env, napi_value map, const size_t& length, napi_value keyArray)
445 {
446 napi_value mapKeys = nullptr;
447 napi_object_get_keys(env, map, &mapKeys);
448 uint32_t maplen = 0;
449 napi_get_array_length(env, mapKeys, &maplen);
450 size_t keyLength = maplen + 1;
451
452 size_t valueLength = keyLength * length;
453 napi_value outputValuesArray = nullptr;
454 napi_create_array_with_length(env, valueLength, &outputValuesArray);
455 // set indexKeyValue
456 size_t valueIdx = 0;
457 for (size_t j = 0; j < length ; ++j) {
458 napi_value keyNumber = nullptr;
459 napi_get_element(env, keyArray, j, &keyNumber);
460 napi_set_element(env, outputValuesArray, valueIdx++, keyNumber);
461 }
462 for (size_t i = 0; i < maplen ; ++i) {
463 napi_value keyNumber = nullptr;
464 napi_get_element(env, mapKeys, i, &keyNumber);
465 char* innerKey = Helper::NapiHelper::GetChars(env, keyNumber);
466 if (innerKey == nullptr) {
467 Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
468 "property key must not be null.");
469 return Helper::NapiHelper::GetUndefinedValue(env);
470 }
471 napi_value valueNumber = nullptr;
472 napi_get_named_property(env, map, innerKey, &valueNumber);
473 Helper::CloseHelp::DeletePointer(innerKey, true);
474 for (size_t j = 0; j < length ; ++j) {
475 napi_value value = nullptr;
476 napi_get_element(env, valueNumber, j, &value);
477 napi_set_element(env, outputValuesArray, valueIdx++, value);
478 }
479 }
480 return outputValuesArray;
481 }
482
SetPrimitive(napi_env env,napi_value map,const size_t & length,napi_value valuesKeyArray,napi_value outputKeysArray,napi_value outputValuesArray)483 void SetPrimitive(napi_env env, napi_value map, const size_t& length, napi_value valuesKeyArray,
484 napi_value outputKeysArray, napi_value outputValuesArray)
485 {
486 napi_value mapKeys = nullptr;
487 napi_object_get_keys(env, map, &mapKeys);
488 uint32_t maplen = 0;
489 napi_get_array_length(env, mapKeys, &maplen);
490 napi_value result = nullptr;
491 napi_create_string_utf8(env, "Values", NAPI_AUTO_LENGTH, &result);
492 napi_set_element(env, outputKeysArray, maplen + 1, result);
493 uint32_t valuesLen = 0;
494 napi_get_array_length(env, valuesKeyArray, &valuesLen);
495 size_t startVal = (maplen + 1) * length;
496 for (size_t j = 0; j < length ; ++j) {
497 napi_value value = nullptr;
498 napi_get_element(env, valuesKeyArray, j, &value);
499 napi_set_element(env, outputValuesArray, startVal + j, value);
500 }
501 }
502
ProcessNestedObject(napi_env env,napi_value item,napi_value & map,std::map<std::string,bool> & initialMap,size_t index)503 void ProcessNestedObject(napi_env env, napi_value item, napi_value& map, std::map<std::string, bool>& initialMap,
504 size_t index)
505 {
506 napi_value keys = nullptr;
507 napi_object_get_keys(env, item, &keys);
508 uint32_t innerLength = 0;
509 napi_get_array_length(env, keys, &innerLength);
510 for (size_t j = 0; j < innerLength; ++j) {
511 napi_value keyNumber = nullptr;
512 napi_get_element(env, keys, j, &keyNumber);
513 char* innerKey = Helper::NapiHelper::GetChars(env, keyNumber);
514 if (innerKey == nullptr) {
515 Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
516 "property key must not be null.");
517 return;
518 }
519 napi_value innerItem = nullptr;
520 napi_get_named_property(env, item, innerKey, &innerItem);
521 if (initialMap.find(std::string(innerKey)) == initialMap.end()) {
522 napi_value mapArray = nullptr;
523 napi_create_array_with_length(env, innerLength, &mapArray);
524 napi_set_element(env, mapArray, index, innerItem);
525 napi_set_named_property(env, map, innerKey, mapArray);
526 initialMap[innerKey] = true;
527 } else {
528 napi_value mapArray = nullptr;
529 napi_get_named_property(env, map, innerKey, &mapArray);
530 napi_set_element(env, mapArray, index, innerItem);
531 napi_set_named_property(env, map, innerKey, mapArray);
532 }
533 Helper::CloseHelp::DeletePointer(innerKey, true);
534 }
535 }
536
InitializeValuesKeyArray(napi_env env,napi_value valuesKeyArray,uint32_t length)537 void InitializeValuesKeyArray(napi_env env, napi_value valuesKeyArray, uint32_t length)
538 {
539 for (size_t j = 0; j < length ; ++j) {
540 napi_value result = nullptr;
541 napi_create_string_utf8(env, "", NAPI_AUTO_LENGTH, &result);
542 napi_set_element(env, valuesKeyArray, j, result);
543 }
544 }
545
ProcessTabularData(napi_env env,napi_value tabularData)546 napi_value Console::ProcessTabularData(napi_env env, napi_value tabularData)
547 {
548 napi_value keyArray = nullptr;
549 napi_object_get_keys(env, tabularData, &keyArray);
550 uint32_t length = 0;
551 napi_get_array_length(env, keyArray, &length);
552 napi_value valuesKeyArray = nullptr;
553 napi_create_array_with_length(env, length, &valuesKeyArray);
554
555 napi_value map = nullptr;
556 napi_create_object(env, &map);
557 bool hasPrimitive = false;
558 bool primitiveInit = false;
559 std::map<std::string, bool> initialMap;
560
561 for (size_t i = 0; i < length; i++) {
562 napi_value keyItem = nullptr;
563 napi_get_element(env, keyArray, i, &keyItem);
564 char* key = Helper::NapiHelper::GetChars(env, keyItem);
565 if (key == nullptr) {
566 Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
567 "property key must not be null.");
568 return Helper::NapiHelper::GetUndefinedValue(env);
569 }
570 napi_value item = nullptr;
571 napi_get_named_property(env, tabularData, key, &item);
572 Helper::CloseHelp::DeletePointer(key, true);
573 bool isPrimitive = ((item == nullptr) ||
574 (!Helper::NapiHelper::IsObject(env, item) && !Helper::NapiHelper::IsFunction(env, item)));
575 if (isPrimitive) {
576 if (!primitiveInit) {
577 InitializeValuesKeyArray(env, valuesKeyArray, length);
578 primitiveInit = true;
579 }
580 hasPrimitive = true;
581 napi_set_element(env, valuesKeyArray, i, item);
582 } else {
583 ProcessNestedObject(env, item, map, initialMap, i);
584 }
585 }
586 // set outputKeysArray
587 napi_value outputKeysArray = GetKeyArray(env, map);
588 // set outputValuesArray
589 napi_value outputValuesArray = GetValueArray(env, map, length, keyArray);
590 // if has Primitive, add new colomn Values
591 if (hasPrimitive) {
592 SetPrimitive(env, map, length, valuesKeyArray, outputKeysArray, outputValuesArray);
593 }
594 GraphTable(env, outputKeysArray, outputValuesArray, length);
595 return Helper::NapiHelper::GetUndefinedValue(env);
596 }
597
Table(napi_env env,napi_callback_info info)598 napi_value Console::Table(napi_env env, napi_callback_info info)
599 {
600 size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
601 if (argc < 1) {
602 return Helper::NapiHelper::GetUndefinedValue(env);
603 }
604 napi_value* argv = new napi_value[argc];
605 Helper::ObjectScope<napi_value> scope(argv, true);
606 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
607 if (!Helper::NapiHelper::IsObject(env, argv[0])) {
608 ConsoleLog<LogLevel::INFO>(env, info);
609 }
610 napi_value tabularData = argv[0];
611 return ProcessTabularData(env, tabularData);
612 }
613
PrintTime(std::string timerName,double time,const std::string & log)614 void Console::PrintTime(std::string timerName, double time, const std::string& log)
615 {
616 uint32_t hours = 0;
617 uint32_t minutes = 0;
618 uint32_t seconds = 0;
619 uint32_t ms = time;
620 if (ms >= SECOND) {
621 if (ms >= MINUTE) {
622 if (ms >= HOUR) {
623 hours = ms / HOUR;
624 ms = ms - HOUR * hours;
625 }
626 minutes = ms / MINUTE;
627 ms = ms - MINUTE * minutes;
628 }
629 seconds = ms / SECOND;
630 ms = ms - SECOND * seconds;
631 }
632 if (hours != 0) {
633 HILOG_INFO("%{public}s%{public}s: %{public}d:%{public}.2d:%{public}.2d.%{public}.3d(h:m:s.mm) %{public}s",
634 groupIndent.c_str(), timerName.c_str(), hours, minutes, seconds, ms, log.c_str());
635 return;
636 }
637 if (minutes != 0) {
638 HILOG_INFO("%{public}s%{public}s: %{public}d:%{public}.2d.%{public}.3d(m:s.mm) %{public}s",
639 groupIndent.c_str(), timerName.c_str(), minutes, seconds, ms, log.c_str());
640 return;
641 }
642 if (seconds != 0) {
643 HILOG_INFO("%{public}s%{public}s: %{public}d.%{public}.3ds %{public}s",
644 groupIndent.c_str(), timerName.c_str(), seconds, ms, log.c_str());
645 return;
646 }
647 HILOG_INFO("%{public}s%{public}s: %{public}.3fms %{public}s",
648 groupIndent.c_str(), timerName.c_str(), time, log.c_str());
649 }
650
Time(napi_env env,napi_callback_info info)651 napi_value Console::Time(napi_env env, napi_callback_info info)
652 {
653 size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
654 std::string timerName = GetTimerOrCounterName(env, info, argc);
655 if (timerMap.find(timerName) == timerMap.end()) {
656 timerMap[timerName] = std::chrono::duration_cast<std::chrono::microseconds>
657 (std::chrono::high_resolution_clock::now().time_since_epoch()).count();
658 } else {
659 HILOG_WARN("Timer %{public}s already exists, please check Timer Name", timerName.c_str());
660 }
661 return Helper::NapiHelper::GetUndefinedValue(env);
662 }
663
TimeLog(napi_env env,napi_callback_info info)664 napi_value Console::TimeLog(napi_env env, napi_callback_info info)
665 {
666 size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
667 std::string timerName = GetTimerOrCounterName(env, info, argc);
668 if (timerMap.find(timerName) != timerMap.end()) {
669 // get time in ms
670 int64_t endTime = std::chrono::duration_cast<std::chrono::microseconds>
671 (std::chrono::high_resolution_clock::now().time_since_epoch()).count();
672 double ms = static_cast<uint64_t>(endTime - timerMap[timerName]) / 1000.0;
673 std::string content = MakeLogContent(env, info, argc, 1, false); // startInx = 1, format = false;
674 PrintTime(timerName, ms, content);
675 } else {
676 HILOG_WARN("%{public}sTimer %{public}s doesn't exists, please check Timer Name.",
677 groupIndent.c_str(), timerName.c_str());
678 }
679 return Helper::NapiHelper::GetUndefinedValue(env);
680 }
681
TimeEnd(napi_env env,napi_callback_info info)682 napi_value Console::TimeEnd(napi_env env, napi_callback_info info)
683 {
684 size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
685 std::string timerName = GetTimerOrCounterName(env, info, argc);
686 if (timerMap.find(timerName) != timerMap.end()) {
687 // get time in ms
688 int64_t endTime = std::chrono::duration_cast<std::chrono::microseconds>
689 (std::chrono::high_resolution_clock::now().time_since_epoch()).count();
690 double ms = static_cast<uint64_t>(endTime - timerMap[timerName]) / 1000.0;
691 PrintTime(timerName, ms, "");
692 timerMap.erase(timerName);
693 } else {
694 HILOG_WARN("%{public}sTimer %{public}s doesn't exists, please check Timer Name.",
695 groupIndent.c_str(), timerName.c_str());
696 }
697 return Helper::NapiHelper::GetUndefinedValue(env);
698 }
699
Trace(napi_env env,napi_callback_info info)700 napi_value Console::Trace(napi_env env, napi_callback_info info)
701 {
702 size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
703 std::string content;
704 if (argc > 0) {
705 content = MakeLogContent(env, info, argc, 0); // startInx = 0
706 }
707 HILOG_INFO("%{public}sTrace: %{public}s", groupIndent.c_str(), content.c_str());
708 std::string stack;
709 napi_get_stack_trace(env, stack);
710 std::string tempStr = "";
711 for (size_t i = 0; i < stack.length(); i++) {
712 if (stack[i] == '\n') {
713 HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), tempStr.c_str());
714 tempStr = "";
715 } else {
716 tempStr += stack[i];
717 }
718 }
719 return Helper::NapiHelper::GetUndefinedValue(env);
720 }
721
TraceHybridStack(napi_env env,napi_callback_info info)722 napi_value Console::TraceHybridStack(napi_env env, napi_callback_info info)
723 {
724 std::string stack;
725 napi_get_hybrid_stack_trace(env, stack);
726 HILOG_INFO("%{public}sTraceHybridStack: ", groupIndent.c_str());
727 std::string tempStr = "";
728 for (size_t i = 0; i < stack.length(); i++) {
729 if (stack[i] == '\n') {
730 HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), tempStr.c_str());
731 tempStr = "";
732 } else {
733 tempStr += stack[i];
734 }
735 }
736 return Helper::NapiHelper::GetUndefinedValue(env);
737 }
738
Assert(napi_env env,napi_callback_info info)739 napi_value Console::Assert(napi_env env, napi_callback_info info)
740 {
741 // 1. check args
742 size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
743 if (argc < 1) {
744 HILOG_ERROR("%{public}sAssertion failed", groupIndent.c_str());
745 return Helper::NapiHelper::GetUndefinedValue(env);
746 }
747 napi_value* argv = new napi_value[argc];
748 Helper::ObjectScope<napi_value> scope(argv, true);
749 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
750
751 if (Helper::NapiHelper::GetBooleanValue(env, argv[0])) {
752 return Helper::NapiHelper::GetUndefinedValue(env);
753 }
754 std::string content = "Assertion failed";
755 if (argc > 1) {
756 content += ":";
757 content += MakeLogContent(env, info, argc, 1); // startIndex = 1
758 }
759 HILOG_ERROR("%{public}s%{public}s", groupIndent.c_str(), content.c_str());
760 return Helper::NapiHelper::GetUndefinedValue(env);
761 }
762
InitConsoleModule(napi_env env)763 void Console::InitConsoleModule(napi_env env)
764 {
765 napi_property_descriptor properties[] = {
766 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("log", ConsoleLog<LogLevel::INFO>),
767 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("debug", ConsoleLog<LogLevel::DEBUG>),
768 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("info", ConsoleLog<LogLevel::INFO>),
769 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("warn", ConsoleLog<LogLevel::WARN>),
770 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("error", ConsoleLog<LogLevel::ERROR>),
771 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("fatal", ConsoleLog<LogLevel::FATAL>),
772 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("group", Group),
773 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("groupCollapsed", Group),
774 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("groupEnd", GroupEnd),
775 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("table", Table),
776 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("time", Time),
777 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("timeLog", TimeLog),
778 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("timeEnd", TimeEnd),
779 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("trace", Trace),
780 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("traceHybridStack", TraceHybridStack),
781 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("assert", Assert),
782 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("count", Count),
783 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("countReset", CountReset),
784 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("dir", Dir),
785 DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("dirxml", ConsoleLog<LogLevel::INFO>)
786 };
787 napi_value globalObj = Helper::NapiHelper::GetGlobalObject(env);
788 napi_value console = nullptr;
789 napi_create_object(env, &console);
790 napi_define_properties(env, console, sizeof(properties) / sizeof(properties[0]), properties);
791 napi_set_named_property(env, globalObj, "console", console);
792 }
793 } // namespace Commonlibrary::JsSysModule