• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }