• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-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 "console_log_impl.h"
17 #if IS_ENABLED(CONSOLE_LOG_OUTPUT)
18 #include "js_app_environment.h"
19 #if (FEATURE_USER_MC_LOG_PRINTF == 1)
20 #include "product_adapter.h"
21 #endif // FEATURE_USER_MC_LOG_PRINTF
22 #ifdef FEATURE_ACELITE_HI_LOG_PRINTF
23 #undef LOG_DOMAIN
24 #undef LOG_TAG
25 #define LOG_DOMAIN 0xD003B00
26 #define LOG_TAG "JS-3RD-APP"
27 #include "hilog/log.h"
28 #endif // FEATURE_ACELITE_HI_LOG_PRINTF
29 #include <stdio.h>
30 #include <string.h>
31 
32 namespace OHOS {
33 namespace ACELite {
34 #ifdef CONSOLE_LOG_LINE_MAX_LENGTH
35 const int16_t LOG_BUFFER_SIZE = CONSOLE_LOG_LINE_MAX_LENGTH;
36 #else
37 const int16_t LOG_BUFFER_SIZE = 256; // use 256 as default if it's not config
38 #endif // CONSOLE_LOG_LINE_MAX_LENGTH
LogNative(const LogLevel logLevel,const jerry_value_t func,const jerry_value_t context,const jerry_value_t * args,const jerry_length_t argc)39 jerry_value_t LogNative(const LogLevel logLevel,
40                         const jerry_value_t func,
41                         const jerry_value_t context,
42                         const jerry_value_t *args,
43                         const jerry_length_t argc)
44 {
45     (void)func;    /* unused */
46     (void)context; /* unused */
47 
48     // print out log level if needed
49     LogOutLevel(logLevel);
50 
51     const char * const nullStr = "\\u0000";
52     jerry_value_t retVal = jerry_create_undefined();
53 
54     for (jerry_length_t argIndex = 0; argIndex < argc; argIndex++) {
55         jerry_value_t strVal;
56 
57         if (jerry_value_is_symbol(args[argIndex])) {
58             strVal = jerry_get_symbol_descriptive_string(args[argIndex]);
59         } else {
60             strVal = jerry_value_to_string(args[argIndex]);
61         }
62 
63         if (jerry_value_is_error(strVal)) {
64             /* There is no need to free the undefined value. */
65             retVal = strVal;
66             break;
67         }
68 
69         jerry_length_t length = jerry_get_utf8_string_length(strVal);
70         jerry_length_t substrPos = 0;
71         const uint16_t bufLength = LOG_BUFFER_SIZE;
72         jerry_char_t substrBuf[bufLength] = {0};
73 
74         do {
75             jerry_size_t substrSize =
76                 jerry_substring_to_utf8_char_buffer(strVal, substrPos, length, substrBuf, bufLength - 1);
77 
78             jerry_char_t *bufEndPos = substrBuf + substrSize;
79 
80             /* Update start position by the number of utf-8 characters. */
81             for (jerry_char_t *bufPos = substrBuf; bufPos < bufEndPos; bufPos++) {
82                 /* Skip intermediate utf-8 octets. */
83                 if ((*bufPos & 0xc0) != 0x80) {
84                     substrPos++;
85                 }
86             }
87 
88             for (jerry_char_t *bufPos = substrBuf; bufPos < bufEndPos; bufPos++) {
89                 char chr = static_cast<char>(*bufPos);
90 
91                 if (chr != '\0') {
92                     LogChar(chr, logLevel);
93                     continue;
94                 }
95 
96                 for (jerry_size_t null_index = 0; nullStr[null_index] != '\0'; null_index++) {
97                     LogChar(nullStr[null_index], logLevel);
98                 }
99             }
100         } while (substrPos < length);
101 
102         jerry_release_value(strVal);
103     }
104     // output end
105     LogChar('\n', logLevel, true);
106     FlushOutput();
107     return retVal;
108 }
109 
LogOutLevel(const LogLevel logLevel)110 void LogOutLevel(const LogLevel logLevel)
111 {
112     switch (logLevel) {
113         case LOG_LEVEL_ERR:
114             LogString(logLevel, "[Console Error] "); // console error
115             break;
116         case LOG_LEVEL_WARN:
117             LogString(logLevel, "[Console Warn] "); // console warn
118             break;
119         case LOG_LEVEL_INFO:
120             LogString(logLevel, "[Console Info] "); // console info
121             break;
122         case LOG_LEVEL_DEBUG:
123             LogString(logLevel, "[Console Debug] "); // console debug
124             break;
125         case LOG_LEVEL_TRACE:
126             LogString(logLevel, "[Console Trace] "); // console trace, this is not supported yet
127             break;
128         case LOG_LEVEL_NONE:
129             LogString(logLevel, "[Console Debug] "); // console.log(), default apply the DEBUG level
130             break;
131         default: // just return for not supported log level
132             break;
133     }
134 }
135 
136 /**
137  * @brief: the str to print out.
138  *
139  * @param str the string to print out
140  */
LogString(const LogLevel logLevel,const char * const str)141 void LogString(const LogLevel logLevel, const char * const str)
142 {
143     if (str == nullptr) {
144         return;
145     }
146 #if ((FEATURE_ACELITE_HI_LOG_PRINTF == 1) || (FEATURE_USER_MC_LOG_PRINTF == 1))
147     size_t strLength = strlen(str);
148     for (size_t i = 0; i < strLength; i++) {
149         LogChar(str[i], logLevel, false);
150     }
151 #else
152     Output(logLevel, str, strlen(str));
153 #endif
154 }
155 
156 static char logBuffer[LOG_BUFFER_SIZE] = {0};
157 static uint16_t logBufferIndex = 0;
158 
LogChar(char c,const LogLevel logLevel,bool endFlag)159 void LogChar(char c, const LogLevel logLevel, bool endFlag)
160 {
161     logBuffer[logBufferIndex++] = c;
162     if ((logBufferIndex == (LOG_BUFFER_SIZE - 1)) || (c == '\n')) {
163         if ((c == '\n') && (logBufferIndex > 0)) {
164             logBufferIndex--; // will trace out line separator after print the content out
165         }
166         logBuffer[logBufferIndex] = '\0';
167         Output(logLevel, logBuffer, logBufferIndex);
168         logBufferIndex = 0;
169         if (c == '\n' || !endFlag) {
170             // this is the newline during the console log, need to append the loglevel prefix,
171             // example: console.log("aa\nbb");
172 #if ((FEATURE_ACELITE_HI_LOG_PRINTF != 1) && (FEATURE_USER_MC_LOG_PRINTF != 1))
173             Output(logLevel, "\n", 1); // hilog will trace our the line separator directly
174 #endif
175             if (!endFlag) {
176                 LogOutLevel(logLevel);
177             }
178         }
179     }
180 }
181 
182 #ifdef FEATURE_ACELITE_HI_LOG_PRINTF
OutputToHiLog(const LogLevel logLevel,const char * const str)183 static void OutputToHiLog(const LogLevel logLevel, const char * const str)
184 {
185     switch (logLevel) {
186         case LOG_LEVEL_ERR:
187             HILOG_ERROR(HILOG_MODULE_APP, "%{public}s", str);
188             break;
189         case LOG_LEVEL_WARN:
190             HILOG_WARN(HILOG_MODULE_APP, "%{public}s", str);
191             break;
192         case LOG_LEVEL_INFO:
193             HILOG_INFO(HILOG_MODULE_APP, "%{public}s", str);
194             break;
195         case LOG_LEVEL_DEBUG:
196             HILOG_DEBUG(HILOG_MODULE_APP, "%{public}s", str);
197             break;
198         case LOG_LEVEL_TRACE:
199             HILOG_INFO(HILOG_MODULE_APP, "%{public}s", str);
200             break;
201         case LOG_LEVEL_NONE:
202             HILOG_DEBUG(HILOG_MODULE_APP, "%{public}s", str);
203             break;
204         default:
205             break;
206     }
207 }
208 #elif (FEATURE_USER_MC_LOG_PRINTF == 1)
OutputToHiLog(const LogLevel logLevel,const char * const str)209 static void OutputToHiLog(const LogLevel logLevel, const char * const str)
210 {
211     switch (logLevel) {
212         case LOG_LEVEL_ERR:
213             ProductAdapter::OutputJSConsoleLog((uint8_t)(LOG_LEVEL_ERR), str);
214             break;
215         case LOG_LEVEL_WARN:
216             ProductAdapter::OutputJSConsoleLog((uint8_t)(LOG_LEVEL_WARN), str);
217             break;
218         case LOG_LEVEL_INFO:
219             ProductAdapter::OutputJSConsoleLog((uint8_t)(LOG_LEVEL_INFO), str);
220             break;
221         case LOG_LEVEL_DEBUG:
222             // fall through
223         case LOG_LEVEL_TRACE:
224             // fall through
225         case LOG_LEVEL_NONE:
226             ProductAdapter::OutputJSConsoleLog((uint8_t)(LOG_LEVEL_DEBUG), str);
227             break;
228         default:
229             break;
230     }
231 }
232 #endif
233 
234 #ifdef TDD_ASSERTIONS
235 static JSLogOutputExtraHandler g_logOutputExtraHandler = nullptr;
236 // add extra hanlder for TDD test cases
RegisterJSLogOutputHandler(JSLogOutputExtraHandler extraHandler)237 void RegisterJSLogOutputHandler(JSLogOutputExtraHandler extraHandler)
238 {
239     g_logOutputExtraHandler = extraHandler;
240 }
241 #endif // TDD_ASSERTIONS
242 
Output(const LogLevel logLevel,const char * const str,const uint8_t length)243 void Output(const LogLevel logLevel, const char * const str, const uint8_t length)
244 {
245     if (str == nullptr) {
246         return;
247     }
248     (void)length;
249     Debugger::GetInstance().Output(str);
250 #if ((FEATURE_ACELITE_HI_LOG_PRINTF == 1) || (FEATURE_USER_MC_LOG_PRINTF == 1))
251     OutputToHiLog(logLevel, str);
252 #endif
253 #ifdef TDD_ASSERTIONS
254     // output to extra handler if it was set by test cases
255     if (g_logOutputExtraHandler != nullptr) {
256         g_logOutputExtraHandler(logLevel, str, length);
257     }
258 #endif // TDD_ASSERTIONS
259 }
260 
FlushOutput()261 void FlushOutput()
262 {
263     Debugger::GetInstance().FlushOutput();
264 }
265 } // namespace ACELite
266 } // namespace OHOS
267 
268 #endif // ENABLED(CONSOLE_LOG_OUTPUT)
269