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