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 "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> parts;
175 StringUtil::SplitStr(pattern, "/", parts, false, false);
176 std::string out = (name.back() == '/') ? name : (name + "/");
177 for (auto& part : parts) {
178 smatch result;
179 if (regex_match(sourceFile, result, regex(out + part))) {
180 out = ((*(sourceFile.rbegin())) == '/') ? sourceFile : (sourceFile + "/");
181 } else {
182 out += part + "/";
183 }
184 }
185 desPath = out.substr(0, out.size() - 1);
186 return LogUtil::FileExist(desPath);
187 }
188
SplitFeatureId(const Json::Value & object) const189 vector<string> ExtractRule::SplitFeatureId(const Json::Value& object) const
190 {
191 if (!object.isMember(L2_FEATUREID)) {
192 HIVIEW_LOGE("failed to get json number %{public}s.", L1_SEG_STATUS.c_str());
193 return {};
194 }
195
196 vector<string> result;
197 StringUtil::SplitStr(object[L2_FEATUREID].asString(), ",", result, false, false);
198 return result;
199 }
200
ParseRule(const Json::Value & object,list<FeatureRule> & features) const201 void ExtractRule::ParseRule(const Json::Value& object, list<FeatureRule>& features) const
202 {
203 if (!object.isMember(L2_RULES)) {
204 return;
205 }
206 ParseRuleParam(object[L2_RULES], features, L2_RULES);
207
208 if (!object.isMember(L2_SEGMENT_RULE)) {
209 return;
210 }
211 ParseRuleParam(object[L2_SEGMENT_RULE], features, L2_SEGMENT_RULE);
212 }
213
ParseRuleParam(const Json::Value & object,list<FeatureRule> & features,const string & type) const214 void ExtractRule::ParseRuleParam(const Json::Value& object, list<FeatureRule>& features, const string& type) const
215 {
216 int objectSize = static_cast<int>(object.size());
217 if (objectSize > JSON_ARRAY_THRESHOLD) {
218 objectSize = JSON_ARRAY_THRESHOLD;
219 HIVIEW_LOGI("json array has been resized to threshold value.");
220 }
221 for (int i = 0; i < objectSize; i++) {
222 FeatureRule command{};
223 command.cmdType = type;
224 command.name = object[i][L3_NAMESPACE].asString();
225 command.source = object[i][L3_MATCH_KEY].asString();
226 command.depend = object[i][L3_DEPEND].asString();
227 GetExtractParam(object[i], command.param, L3_PARAM);
228 command.num = object[i][L3_NUM].asInt();
229 if (command.num > 0 && type == L2_RULES) {
230 HIVIEW_LOGE("rule command can't have num.\n");
231 continue;
232 }
233 features.emplace_back(command);
234 }
235 }
236
GetExtractParam(const Json::Value & rules,std::map<std::string,std::string> & param,const std::string & preKey) const237 void ExtractRule::GetExtractParam(const Json::Value& rules,
238 std::map<std::string, std::string>& param, const std::string& preKey) const {
239 for (auto iter = rules.begin(); iter != rules.end(); iter++) {
240 auto pos = iter.key().asString().find(preKey);
241 if (pos == 0) {
242 param.emplace(iter.key().asString(), (*iter).asString());
243 }
244 }
245 }
246 } // namespace HiviewDFX
247 } // namespace OHOS
248