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