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 #include "log_parse.h"
16
17 #include "string_util.h"
18 #include "tbox.h"
19
20 using namespace std;
21 namespace OHOS {
22 namespace HiviewDFX {
23 const std::string LogParse::UNMATCHED_EXCEPTION = "UnMatchedException";
24
25 // some stack function is invalid, so it should be ignored
26 const std::map<std::string, std::set<std::string>> LogParse::ignoreList_ = {
27 {"Level1", {
28 "libc.so",
29 "libc_fdleak_debug.so",
30 "unknown",
31 "watchdog",
32 "kthread",
33 "rdr_system_error"}
34 },
35 {"Level2", {
36 "libart.so",
37 "__switch_to",
38 "dump_backtrace",
39 "show_stack",
40 "dump_stack"}
41 },
42 {"Level3", {
43 "panic"}
44 }
45 };
46
47 // it is key word in app crash log, it can replace complexed info which may have safe and privacy info
48 const std::set<std::string> LogParse::exceptionList_ = {
49 "ArithmeticException",
50 "ArrayIndexOutOfBoundsException",
51 "ArrayStoreException",
52 "ClassCastException",
53 "ClassNotFoundException",
54 "CloneNotSupportedException",
55 "EnumConstantNotPresentException",
56 "IllegalAccessException",
57 "IllegalArgumentException",
58 "IllegalMonitorStateException",
59 "IllegalStateException",
60 "IllegalThreadStateException",
61 "IndexOutOfBoundsException",
62 "InstantiationException",
63 "InterruptedException",
64 "NegativeArraySizeException",
65 "NoSuchFieldException",
66 "NoSuchMethodException",
67 "NullPointerException",
68 "NumberFormatException",
69 "ReflectiveOperationException",
70 "RuntimeException",
71 "SecurityException",
72 "StringIndexOutOfBoundsException"
73 };
74
IsIgnoreLibrary(const string & val) const75 bool LogParse::IsIgnoreLibrary(const string& val) const
76 {
77 for (auto list : ignoreList_) {
78 for (auto str : list.second) {
79 if (val.find(str, 0) != string::npos) {
80 return true;
81 }
82 }
83 }
84 return false;
85 }
86
87 /*
88 * Remove ignored backtrace
89 * inStack : inverted sequence with fault log
90 * outStack : filter stack
91 */
GetValidStack(int num,stack<string> & inStack,stack<string> & outStack) const92 bool LogParse::GetValidStack(int num, stack<string>& inStack, stack<string>& outStack) const
93 {
94 vector<string> validStack;
95 size_t count = static_cast<size_t>(num);
96 // count < 1: indicate stack is empty
97 if (count < 1 || inStack.empty()) {
98 return false;
99 }
100
101 // Automatically checks if it is a stack
102 bool iStack = Tbox::IsCallStack(inStack.top());
103 if (iStack) {
104 validStack = GetValidStack(count, inStack);
105 }
106 outStack = GetStackTop(validStack, count);
107 return true;
108 }
109
GetStackTop(const vector<string> & validStack,const size_t num) const110 stack<string> LogParse::GetStackTop(const vector<string>& validStack, const size_t num) const
111 {
112 size_t len = validStack.size();
113 stack<string> stackTop;
114 for (size_t i = 0; i < len; i++) {
115 if (i == 0 || len - i < num) {
116 stackTop.push(validStack.at(i));
117 }
118 }
119 return stackTop;
120 }
121
StackToMultipart(stack<string> & inStack,size_t num) const122 list<vector<string>> LogParse::StackToMultipart(stack<string>& inStack, size_t num) const
123 {
124 stack<string> partStack;
125 vector<string> validPart;
126 list<vector<string>> multiPart;
127 for (size_t i = 0; i < inStack.size(); i++) {
128 string topStr = inStack.top();
129 StringUtil::EraseString(topStr, "\t");
130 if (Tbox::HasCausedBy(topStr)) {
131 topStr = MatchExceptionLibrary(topStr);
132 if (!partStack.empty()) {
133 validPart = GetValidStack(num, partStack);
134 }
135 validPart.insert(validPart.begin(), topStr);
136 multiPart.push_back(validPart);
137 partStack = stack<string>();
138 validPart.clear();
139 inStack.pop();
140 continue;
141 }
142 partStack.push(topStr);
143 inStack.pop();
144 }
145 if (!partStack.empty()) {
146 validPart = GetValidStack(num, partStack);
147 multiPart.push_back(validPart);
148 }
149 return multiPart;
150 }
151
GetValidBlock(stack<string> inStack,vector<string> & lastPart) const152 string LogParse::GetValidBlock(stack<string> inStack, vector<string>& lastPart) const
153 {
154 vector<string> validStack;
155
156 list<vector<string>> multiPart = StackToMultipart(inStack, 3); // 3 : first/second/last frame
157 size_t size = multiPart.size();
158 if (size == 0) {
159 return "";
160 }
161 if (size == 1) {
162 // only one part
163 validStack = multiPart.front();
164 if (validStack.size() > STACK_LEN_MAX) {
165 // keep the begin 28 lines and the end 2 lines
166 validStack.erase(validStack.begin() + (STACK_LEN_MAX - 2), validStack.end() - 2); // 2 : end 2 lines
167 }
168 } else if (size >= 2) { // at least 2 parts
169 for (auto part : multiPart) {
170 if (validStack.size() >= STACK_LEN_MAX) {
171 break;
172 }
173 validStack.insert(validStack.begin(), part.begin(), part.end());
174 }
175 if (multiPart.front().size() > STACK_LEN_MAX) {
176 // keep the begin 28 lines and the end 2 lines
177 validStack.erase(validStack.begin() + (STACK_LEN_MAX - 2), validStack.end() - 2); // 2 : end 2 lines
178 } else if (validStack.size() > STACK_LEN_MAX) {
179 // keep the begin 2 lines and the end 28 lines
180 validStack.erase(validStack.begin() + 2, validStack.end() - (STACK_LEN_MAX - 2)); // 2 : begin 2 lines
181 }
182 }
183
184 for (auto part : multiPart) {
185 // multiPart has at least 2 parts
186 if (size > 1 && !part.empty() && HasExceptionList(part.front())) {
187 part.erase(part.begin());
188 }
189 // lastPart should has at least 3 lines
190 if (!part.empty()) {
191 reverse(part.begin(), part.end());
192 lastPart = part;
193 break;
194 }
195 }
196 return Tbox::ARRAY_STR + StringUtil::VectorToString(validStack, false);
197 }
198
GetValidStack(size_t num,stack<string> & inStack) const199 vector<string> LogParse::GetValidStack(size_t num, stack<string>& inStack) const
200 {
201 stack<string> src = inStack;
202 vector<string> validStack;
203 stack<string> outStatck;
204 string stackName;
205 size_t len = src.size();
206 for (size_t i = 0; i < len; i++) {
207 stackName = Tbox::GetStackName(src.top()); // extract function name from the stack
208 if (!IsIgnoreLibrary(stackName)) {
209 validStack.push_back(stackName);
210 }
211 src.pop();
212 }
213 if (validStack.empty()) {
214 MatchIgnoreLibrary(inStack, outStatck, num);
215 len = outStatck.size();
216 for (size_t i = 0; i < len; i++) {
217 stackName = Tbox::GetStackName(outStatck.top());
218 validStack.push_back(stackName);
219 outStatck.pop();
220 }
221 }
222 return validStack;
223 }
224
MatchExceptionLibrary(const string & val)225 string LogParse::MatchExceptionLibrary(const string& val)
226 {
227 for (auto& str : LogParse::exceptionList_) {
228 if (val.find(str, 0) != string::npos) {
229 return str;
230 }
231 }
232 return UNMATCHED_EXCEPTION;
233 }
234
MatchIgnoreLibrary(stack<string> inStack,stack<string> & outStack,size_t num) const235 void LogParse::MatchIgnoreLibrary(stack<string> inStack, stack<string>& outStack, size_t num) const
236 {
237 if (inStack.size() <= num) {
238 outStack = inStack;
239 return;
240 }
241 size_t count = 0;
242 for (auto it = ignoreList_.rbegin(); it != ignoreList_.rend(); ++it) {
243 if (count == ignoreList_.size() - 1) {
244 outStack = inStack;
245 return;
246 }
247
248 stack<string> src = inStack;
249 while (src.size() > num) {
250 string name = src.top();
251 for (auto str : it->second) {
252 if (name.find(str, 0) != string::npos) {
253 outStack = src;
254 return;
255 }
256 }
257 src.pop();
258 }
259 count++;
260 }
261 }
262
263 /*
264 * INPUT :
265 * info : trace spliting by "\n"
266 * OUTPUT :
267 * trace : last part trace to get Frame
268 * return string : valid trace spliting by "\n"
269 */
GetFilterTrace(const std::string & info,std::vector<std::string> & trace) const270 std::string LogParse::GetFilterTrace(const std::string& info, std::vector<std::string>& trace) const
271 {
272 StringUtil::SplitStr(info, "\n", trace, false, false);
273 std::stack<std::string> traceStack;
274 for (const auto& str : trace) {
275 traceStack.push(str);
276 }
277 trace.clear();
278 return GetValidBlock(traceStack, trace);
279 }
280
SetFrame(std::stack<std::string> & stack,std::map<std::string,std::string> & eventInfo) const281 void LogParse::SetFrame(std::stack<std::string>& stack, std::map<std::string, std::string>& eventInfo) const
282 {
283 std::vector<std::string> name = {"FIRST_FRAME", "SECOND_FRAME", "LAST_FRAME"};
284 size_t len = stack.size();
285 for (size_t i = 0; i < len; i++) {
286 if (eventInfo.find(name[i]) == eventInfo.end()) {
287 eventInfo[name[i]] = stack.top();
288 }
289 stack.pop();
290 }
291 }
292
HasExceptionList(const string & line) const293 bool LogParse::HasExceptionList(const string& line) const
294 {
295 auto iter = exceptionList_.find(line);
296 if (line == UNMATCHED_EXCEPTION || iter != exceptionList_.end()) {
297 return true;
298 }
299 return false;
300 }
301 }
302 }