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++.so",
30 "ld-musl-aarch64.so",
31 "libc_fdleak_debug.so",
32 "unknown",
33 "watchdog",
34 "kthread",
35 "rdr_system_error"}
36 },
37 {"Level2", {
38 "libart.so",
39 "__switch_to",
40 "dump_backtrace",
41 "show_stack",
42 "dump_stack"}
43 },
44 {"Level3", {
45 "panic"}
46 }
47 };
48
IsIgnoreLibrary(const string & val) const49 bool LogParse::IsIgnoreLibrary(const string& val) const
50 {
51 for (auto list : ignoreList_) {
52 for (auto str : list.second) {
53 if (val.find(str, 0) != string::npos) {
54 return true;
55 }
56 }
57 }
58 return false;
59 }
60
GetStackTop(const vector<string> & validStack,const size_t num) const61 stack<string> LogParse::GetStackTop(const vector<string>& validStack, const size_t num) const
62 {
63 size_t len = validStack.size();
64 stack<string> stackTop;
65 for (size_t i = 0; i < len; i++) {
66 if (i == 0 || len - i < num) {
67 stackTop.push(validStack.at(i));
68 }
69 }
70 return stackTop;
71 }
72
StackToPart(stack<string> & inStack,size_t num) const73 vector<string> LogParse::StackToPart(stack<string>& inStack, size_t num) const
74 {
75 stack<string> partStack;
76 while (!inStack.empty()) {
77 string topStr = inStack.top();
78 StringUtil::EraseString(topStr, "\t");
79 partStack.push(topStr);
80 inStack.pop();
81 }
82 vector<string> validPart;
83 if (!partStack.empty()) {
84 validPart = GetValidStack(num, partStack);
85 }
86 return validPart;
87 }
88
GetValidBlock(stack<string> inStack,vector<string> & lastPart) const89 string LogParse::GetValidBlock(stack<string> inStack, vector<string>& lastPart) const
90 {
91 vector<string> validStack;
92
93 lastPart = StackToPart(inStack, 3); // 3 : first/second/last frame
94 if (lastPart.empty()) {
95 return "";
96 } else if (lastPart.size() > STACK_LEN_MAX) {
97 // keep the begin 28 lines and the end 2 lines
98 lastPart.erase(lastPart.begin() + (STACK_LEN_MAX - 2), lastPart.end() - 2); // 2 : end 2 lines
99 }
100
101 reverse(lastPart.begin(), lastPart.end());
102
103 for (auto& it : lastPart) {
104 it = Tbox::GetStackName(it);
105 }
106 return Tbox::ARRAY_STR + StringUtil::VectorToString(lastPart, false);
107 }
108
GetValidStack(size_t num,stack<string> & inStack) const109 vector<string> LogParse::GetValidStack(size_t num, stack<string>& inStack) const
110 {
111 stack<string> src = inStack;
112 vector<string> validStack;
113 stack<string> outStatck;
114 size_t len = src.size();
115 for (size_t i = 0; i < len; i++) {
116 auto stackFrame = src.top();
117 if (!IsIgnoreLibrary(stackFrame)) {
118 validStack.push_back(stackFrame);
119 }
120 src.pop();
121 }
122 if (validStack.empty()) {
123 MatchIgnoreLibrary(inStack, outStatck, num);
124 len = outStatck.size();
125 for (size_t i = 0; i < len; i++) {
126 validStack.push_back(outStatck.top());
127 outStatck.pop();
128 }
129 }
130 return validStack;
131 }
132
MatchIgnoreLibrary(stack<string> inStack,stack<string> & outStack,size_t num) const133 void LogParse::MatchIgnoreLibrary(stack<string> inStack, stack<string>& outStack, size_t num) const
134 {
135 if (inStack.size() <= num) {
136 outStack = inStack;
137 return;
138 }
139 size_t count = 0;
140 for (auto it = ignoreList_.rbegin(); it != ignoreList_.rend(); ++it) {
141 if (count == ignoreList_.size() - 1) {
142 outStack = inStack;
143 return;
144 }
145
146 stack<string> src = inStack;
147 while (src.size() > num) {
148 string name = src.top();
149 for (auto str : it->second) {
150 if (name.find(str, 0) != string::npos) {
151 outStack = src;
152 return;
153 }
154 }
155 src.pop();
156 }
157 count++;
158 }
159 }
160
161 /*
162 * INPUT :
163 * info : trace spliting by "\n"
164 * OUTPUT :
165 * trace : last part trace to get Frame
166 * return string : valid trace spliting by "\n"
167 */
GetFilterTrace(const std::string & info,std::vector<std::string> & trace,std::string eventType) const168 std::string LogParse::GetFilterTrace(const std::string& info, std::vector<std::string>& trace,
169 std::string eventType) const
170 {
171 std::string newInfo = info;
172 if (eventType == "JS_ERROR" && newInfo.find("libace_napi.z.so") != std::string::npos) {
173 newInfo = StringUtil::GetRightSubstr(info, "libace_napi.z.so");
174 }
175 StringUtil::SplitStr(newInfo, "\n", trace, false, false);
176 std::stack<std::string> traceStack;
177 for (const auto& str : trace) {
178 traceStack.push(str);
179 }
180 trace.clear();
181 return GetValidBlock(traceStack, trace);
182 }
183
SetFrame(std::stack<std::string> & stack,std::map<std::string,std::string> & eventInfo) const184 void LogParse::SetFrame(std::stack<std::string>& stack, std::map<std::string, std::string>& eventInfo) const
185 {
186 std::vector<std::string> name = {"FIRST_FRAME", "SECOND_FRAME", "LAST_FRAME"};
187 size_t len = stack.size();
188 for (size_t i = 0; i < len; i++) {
189 if (eventInfo.find(name[i]) == eventInfo.end()) {
190 eventInfo[name[i]] = stack.top();
191 }
192 stack.pop();
193 }
194 }
195 }
196 }
197