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