1 /*
2 * Copyright (c) 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 #include "extract_rule.h"
16
17 #include <fstream>
18 #include <regex>
19
20 #include "file_util.h"
21 #include "log_util.h"
22 #include "hiview_logger.h"
23 #include "string_util.h"
24
25 using namespace std;
26 namespace OHOS {
27 namespace HiviewDFX {
28 DEFINE_LOG_TAG("ExtractRule");
ParseExtractRule(const string & eventType,const string & config,const string & path)29 void ExtractRule::ParseExtractRule(const string& eventType, const string& config, const string& path)
30 {
31 std::ifstream fin(config, std::ifstream::binary);
32 if (!fin.is_open()) {
33 HIVIEW_LOGW("Failed to open file, path: %{public}s.", config.c_str());
34 return;
35 }
36 #ifdef JSONCPP_VERSION_STRING
37 Json::CharReaderBuilder builder;
38 Json::CharReaderBuilder::strictMode(&builder.settings_);
39 JSONCPP_STRING errs;
40 #else
41 Json::Reader reader(Json::Features::strictMode());
42 #endif
43
44 Json::Value root;
45 #ifdef JSONCPP_VERSION_STRING
46 bool ret = parseFromStream(builder, fin, &root, &errs);
47 if (!ret || !errs.empty()) {
48 HIVIEW_LOGE("Json parse fail, err is %{public}s in %{public}s.", errs.c_str(), config.c_str());
49 return;
50 }
51 #else
52 if (!reader.parse(fin, root)) {
53 HIVIEW_LOGE("Json parse fail in %{public}s.", config.c_str());
54 return;
55 }
56 #endif
57 ParseSegStatusCfg(root);
58 ParseRule(eventType, root, path);
59 return;
60 }
61
ParseSegStatusCfg(const Json::Value & json)62 void ExtractRule::ParseSegStatusCfg(const Json::Value& json)
63 {
64 if (!json.isMember(L1_SEG_STATUS)) {
65 HIVIEW_LOGE("failed to get json number %{public}s.", L1_SEG_STATUS);
66 return;
67 }
68
69 Json::Value arrayObj = json[L1_SEG_STATUS];
70 int arrayObjSize = static_cast<int>(arrayObj.size());
71 if (arrayObjSize > JSON_ARRAY_THRESHOLD) {
72 arrayObjSize = JSON_ARRAY_THRESHOLD;
73 HIVIEW_LOGI("json array has been resized to threshold value.");
74 }
75 for (int i = 0; i < arrayObjSize; i++) {
76 string name = arrayObj[i]["namespace"].asString();
77 vector<string> cfg;
78 cfg.emplace_back(arrayObj[i]["matchKey"].asString());
79 cfg.emplace_back(arrayObj[i]["desc"].asString());
80 if (!name.empty() && !cfg[0].empty()) {
81 segStatusCfgMap_.emplace(make_pair(name, cfg));
82 }
83 }
84 }
85
86 /*
87 * parse and store into feature set
88 */
ParseRule(const string & eventType,const Json::Value & json,const string & path)89 void ExtractRule::ParseRule(const string& eventType, const Json::Value& json, const string& path)
90 {
91 for (auto iter = json.begin(); iter != json.end(); iter++) {
92 auto key = iter.key().asString();
93 if (key.find("Rule") == std::string::npos) {
94 continue;
95 }
96 auto value = (*iter);
97 string dirOrFile = value[L2_DIR_OR_FILE].asString();
98 if (dirOrFile.empty()) {
99 continue;
100 }
101 string subcatalog = value[L2_SUBCATELOG].asString();
102 vector<string> featureIds = SplitFeatureId(value);
103 FeatureSet fsets{};
104 for (const auto& featureId : featureIds) {
105 if (!IsMatchId(eventType, featureId) || !IsMatchPath(path, dirOrFile, subcatalog, fsets.fullPath)) {
106 continue;
107 }
108 fsets.skipStep = value[L2_SKIP].asInt();
109 fsets.segmentType = value[L2_SEGMENT_TYPE].asString();
110 fsets.startSegVec = GetJsonArray(value, L2_SEGMENT_START);
111 fsets.segStackVec = GetJsonArray(value, L2_SEGMENT_STACK);
112 // 1st: parse feature
113 ParseRule(value, fsets.rules);
114 featureSets_.emplace(pair<string, FeatureSet>(featureId, fsets));
115 featureIds_.emplace_back(featureId);
116 HIVIEW_LOGI("ParseFile eventId %{public}s, FeatureId %{public}s.", eventType.c_str(), featureId.c_str());
117 }
118 }
119 HIVIEW_LOGD("ParseFile end.");
120 return;
121 }
122
GetFeatureId()123 const vector<string>& ExtractRule::GetFeatureId()
124 {
125 return featureIds_;
126 }
127
IsMatchId(const string & eventType,const string & featureId) const128 bool ExtractRule::IsMatchId(const string& eventType, const string& featureId) const
129 {
130 string firstMatch = StringUtil::GetRightSubstr(featureId, "_");
131 if (StringUtil::GetRleftSubstr(firstMatch, "_") == eventType) {
132 return true;
133 }
134 return false;
135 }
136
GetJsonArray(const Json::Value & json,const string & param)137 std::vector<std::string> ExtractRule::GetJsonArray(const Json::Value& json, const string& param)
138 {
139 if (json.isNull() || !json.isMember(param) || !json[param].isArray()) {
140 HIVIEW_LOGE("failed to get json array number %{public}s.\n", param.c_str());
141 return {};
142 }
143
144 int jsonSize = static_cast<int>(json[param].size());
145 if (jsonSize > JSON_ARRAY_THRESHOLD) {
146 jsonSize = JSON_ARRAY_THRESHOLD;
147 HIVIEW_LOGI("json array has been resized to threshold value.");
148 }
149 std::vector<std::string> result;
150 for (int i = 0; i < jsonSize; i++) {
151 result.push_back(json[param][i].asString());
152 }
153 return result;
154 }
155
156 /**
157 * sourcefile: the full path
158 * name: static path
159 * pattern: dynamic path
160 */
IsMatchPath(const string & sourceFile,const string & name,const string & pattern,string & desPath) const161 bool ExtractRule::IsMatchPath(const string& sourceFile, const string& name, const string& pattern,
162 string& desPath) const
163 {
164 HIVIEW_LOGI("sourceFile is %{public}s, name is %{public}s, pattern is %{public}s.\n",
165 sourceFile.c_str(), name.c_str(), pattern.c_str());
166 desPath = sourceFile;
167
168 if (LogUtil::IsTestModel(sourceFile, name, pattern, desPath)) {
169 HIVIEW_LOGI("this is test model, desPath is %{public}s.\n", desPath.c_str());
170 return true;
171 }
172
173 if (pattern.empty()) {
174 desPath = name;
175 return LogUtil::FileExist(desPath);
176 }
177
178 std::vector<std::string> paths;
179 StringUtil::SplitStr(pattern, "@|@", paths, false, false);
180
181 for (auto path : paths) {
182 std::vector<std::string> parts;
183 StringUtil::SplitStr(path, "/", parts, false, false);
184 std::string out = (name.back() == '/') ? name : (name + "/");
185 for (auto& part : parts) {
186 if (regex_match(sourceFile, regex(out + part))) {
187 out = ((*(sourceFile.rbegin())) == '/') ? sourceFile : (sourceFile + "/");
188 } else {
189 out += part + "/";
190 }
191 }
192 desPath = out.substr(0, out.size() - 1);
193 if (LogUtil::FileExist(desPath)) {
194 HIVIEW_LOGI("desPath is %{public}s.\n", desPath.c_str());
195 return true;
196 }
197 }
198 return false;
199 }
200
SplitFeatureId(const Json::Value & object) const201 vector<string> ExtractRule::SplitFeatureId(const Json::Value& object) const
202 {
203 if (!object.isMember(L2_FEATUREID)) {
204 HIVIEW_LOGE("failed to get json number %{public}s.", L1_SEG_STATUS);
205 return {};
206 }
207
208 vector<string> result;
209 StringUtil::SplitStr(object[L2_FEATUREID].asString(), ",", result, false, false);
210 return result;
211 }
212
ParseRule(const Json::Value & object,list<FeatureRule> & features) const213 void ExtractRule::ParseRule(const Json::Value& object, list<FeatureRule>& features) const
214 {
215 if (!object.isMember(L2_RULES)) {
216 return;
217 }
218 ParseRuleParam(object[L2_RULES], features, L2_RULES);
219
220 if (!object.isMember(L2_SEGMENT_RULE)) {
221 return;
222 }
223 ParseRuleParam(object[L2_SEGMENT_RULE], features, L2_SEGMENT_RULE);
224 }
225
ParseRuleParam(const Json::Value & object,list<FeatureRule> & features,const string & type) const226 void ExtractRule::ParseRuleParam(const Json::Value& object, list<FeatureRule>& features, const string& type) const
227 {
228 int objectSize = static_cast<int>(object.size());
229 if (objectSize > JSON_ARRAY_THRESHOLD) {
230 objectSize = JSON_ARRAY_THRESHOLD;
231 HIVIEW_LOGI("json array has been resized to threshold value.");
232 }
233 for (int i = 0; i < objectSize; i++) {
234 FeatureRule command{};
235 command.cmdType = type;
236 command.name = object[i][L3_NAMESPACE].asString();
237 command.source = object[i][L3_MATCH_KEY].asString();
238 command.depend = object[i][L3_DEPEND].asString();
239 GetExtractParam(object[i], command.param, L3_PARAM);
240 command.num = object[i][L3_NUM].asInt();
241 if (command.num > 0 && type == L2_RULES) {
242 HIVIEW_LOGE("rule command can't have num.\n");
243 continue;
244 }
245 features.emplace_back(command);
246 }
247 }
248
GetExtractParam(const Json::Value & rules,std::map<std::string,std::string> & param,const std::string & preKey) const249 void ExtractRule::GetExtractParam(const Json::Value& rules,
250 std::map<std::string, std::string>& param, const std::string& preKey) const
251 {
252 for (auto iter = rules.begin(); iter != rules.end(); iter++) {
253 auto pos = iter.key().asString().find(preKey);
254 if (pos == 0) {
255 param.emplace(iter.key().asString(), (*iter).asString());
256 }
257 }
258 }
259 } // namespace HiviewDFX
260 } // namespace OHOS
261