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