1 /*
2  * Copyright (c) 2022 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 #ifndef ECMASCRIPT_LOG_H
17 #define ECMASCRIPT_LOG_H
18 
19 #include <cstdint>
20 #include <iostream>
21 #include <sstream>
22 
23 #include "ecmascript/common.h"
24 #include "ecmascript/napi/include/jsnapi.h"
25 
26 #ifdef ENABLE_HILOG
27 #if defined(__clang__)
28 #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
29 #elif defined(__GNUC__)
30 #pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
31 #endif
32 #include "hilog/log.h"
33 #undef LOG_DOMAIN
34 #define LOG_DOMAIN 0xD003F00
35 #undef LOG_TAG
36 #define LOG_TAG "ArkCompiler"
37 #endif
38 
39 
40 using LOG_LEVEL = panda::RuntimeOption::LOG_LEVEL;
41 enum Level {
42     VERBOSE,
43     DEBUG,
44     INFO,
45     WARN,
46     ERROR,
47     FATAL,
48 };
49 
50 using ComponentMark = uint64_t;
51 enum Component {
52     NONE = 0ULL,
53     GC = 1ULL << 0ULL,
54     INTERPRETER = 1ULL << 1ULL,
55     COMPILER = 1ULL << 2ULL,
56     DEBUGGER = 1ULL << 3ULL,
57     ECMASCRIPT = 1ULL << 4ULL,
58     BUILTINS = 1ULL << 5ULL,
59     TRACE = 1ULL << 6ULL,
60     JIT = 1UL << 7ULL,
61     BASELINEJIT = 1UL << 8ULL,
62     SA = 1ULL << 9ULL,
63     NO_TAG = 0xFFFFFFFFULL >> 1ULL,
64     ALL = 0xFFFFFFFFULL,
65 };
66 
67 namespace panda::ecmascript {
68 #ifdef ENABLE_HILOG
69 
70 #if ECMASCRIPT_ENABLE_VERBOSE_LEVEL_LOG
71 // print Debug level log if enable Verbose log
72 #define LOG_VERBOSE LOG_DEBUG
73 #else
74 #define LOG_VERBOSE LOG_LEVEL_MIN
75 #endif
76 #endif  // ENABLE_HILOG
77 
78 class JSRuntimeOptions;
79 class PUBLIC_API Log {
80 public:
81     static void Initialize(const JSRuntimeOptions &options);
LogIsLoggable(Level level, Component component)82     static inline bool LogIsLoggable(Level level, Component component)
83     {
84         switch (component)
85         {
86             case Component::SA:
87                 return ((components_ & component) != 0ULL);
88             default:
89                 return (level >= level_) && ((components_ & component) != 0ULL);
90         }
91     }
GetComponentStr(Component component)92     static inline std::string GetComponentStr(Component component)
93     {
94         switch (component)
95         {
96             case Component::NO_TAG:
97                 return "";
98             case Component::GC:
99                 return "[gc] ";
100             case Component::ECMASCRIPT:
101                 return "[ecmascript] ";
102             case Component::INTERPRETER:
103                 return "[interpreter] ";
104             case Component::DEBUGGER:
105                 return "[debugger] ";
106             case Component::COMPILER:
107                 return "[compiler] ";
108             case Component::BUILTINS:
109                 return "[builtins] ";
110             case Component::TRACE:
111                 return "[trace] ";
112             case Component::JIT:
113                 return "[jit] ";
114             case Component::BASELINEJIT:
115                 return "[baselinejit] ";
116             case Component::SA:
117                 return "[sa] ";
118             case Component::ALL:
119                 return "[default] ";
120             default:
121                 return "[unknown] ";
122         }
123     }
124     static std::string LevelToString(Level level);
125     static Level ConvertFromRuntime(LOG_LEVEL level);
126 
127 private:
128     static void SetLogLevelFromString(const std::string& level);
129     static void SetLogComponentFromString(const std::vector<std::string>& components);
130     static int32_t PrintLogger(int32_t, int32_t level, const char *, const char *, const char *message);
131 
132     static Level level_;
133     static ComponentMark components_;
134 };
135 
136 #if defined(ENABLE_HILOG)
137 template<LogLevel level, Component component>
138 class HiLog {
139 public:
HiLog()140     HiLog()
141     {
142         std::string str = Log::GetComponentStr(component);
143         stream_ << str;
144     }
~HiLog()145     ~HiLog()
146     {
147         if constexpr (level == LOG_LEVEL_MIN) {
148             // print nothing
149         } else if constexpr (level == LOG_DEBUG) {
150             HILOG_DEBUG(LOG_CORE, "%{public}s", stream_.str().c_str());
151         } else if constexpr (level == LOG_INFO) {
152             HILOG_INFO(LOG_CORE, "%{public}s", stream_.str().c_str());
153         } else if constexpr (level == LOG_WARN) {
154             HILOG_WARN(LOG_CORE, "%{public}s", stream_.str().c_str());
155         } else if constexpr (level == LOG_ERROR) {
156             HILOG_ERROR(LOG_CORE, "%{public}s", stream_.str().c_str());
157         } else {
158             HILOG_FATAL(LOG_CORE, "%{public}s", stream_.str().c_str());
159             std::abort();
160         }
161     }
162     template<class type>
operator <<(type input)163     std::ostream &operator <<(type input)
164     {
165         stream_ << input;
166         return stream_;
167     }
168 
169 private:
170     std::ostringstream stream_;
171 };
172 #elif defined(ENABLE_ANLOG)  // ENABLE_ANLOG
173 template<Level level>
174 class PUBLIC_API AndroidLog {
175 public:
AndroidLog()176     AndroidLog()
177     {
178         std::string str = "[default] ";
179         stream_ << str;
180     }
181     ~AndroidLog();
182 
183     template<class type>
operator <<(type input)184     std::ostream &operator <<(type input)
185     {
186         stream_ << input;
187         return stream_;
188     }
189 
190 private:
191     std::ostringstream stream_;
192 };
193 #else
194 template<Level level, Component component>
195 class StdLog {
196 public:
StdLog()197     StdLog()
198     {
199         std::string str = Log::GetComponentStr(component);
200         stream_ << str;
201     }
~StdLog()202     ~StdLog()
203     {
204         if constexpr (level == FATAL || level == ERROR) {
205             std::cerr << stream_.str().c_str() << std::endl;
206         } else {
207             std::cout << stream_.str().c_str() << std::endl;
208         }
209 
210         if constexpr (level == FATAL) {
211             std::abort();
212         }
213     }
214 
215     template<class type>
operator <<(type input)216     std::ostream &operator <<(type input)
217     {
218         stream_ << input;
219         return stream_;
220     }
221 
222 private:
223     std::ostringstream stream_;
224 };
225 #endif
226 
227 #if defined(ENABLE_HILOG)
228 #define ARK_LOG(level, component) panda::ecmascript::Log::LogIsLoggable(level, component) && \
229                                   panda::ecmascript::HiLog<LOG_##level, (component)>()
230 #elif defined(ENABLE_ANLOG)
231 #define ARK_LOG(level, component) panda::ecmascript::AndroidLog<(level)>()
232 #else
233 #if defined(OHOS_UNIT_TEST)
234 #define ARK_LOG(level, component) ((level >= INFO) || panda::ecmascript::Log::LogIsLoggable(level, component)) && \
235                                   panda::ecmascript::StdLog<(level), (component)>()
236 #else
237 #define ARK_LOG(level, component) panda::ecmascript::Log::LogIsLoggable(level, component) && \
238                                   panda::ecmascript::StdLog<(level), (component)>()
239 #endif
240 #endif
241 }  // namespace panda::ecmascript
242 #endif  // ECMASCRIPT_LOG_H
243