1020a203aSopenharmony_ci/*
2020a203aSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
3020a203aSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4020a203aSopenharmony_ci * you may not use this file except in compliance with the License.
5020a203aSopenharmony_ci * You may obtain a copy of the License at
6020a203aSopenharmony_ci *
7020a203aSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8020a203aSopenharmony_ci *
9020a203aSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10020a203aSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11020a203aSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12020a203aSopenharmony_ci * See the License for the specific language governing permissions and
13020a203aSopenharmony_ci * limitations under the License.
14020a203aSopenharmony_ci */
15020a203aSopenharmony_ci#include "feature_analysis.h"
16020a203aSopenharmony_ci
17020a203aSopenharmony_ci#include <algorithm>
18020a203aSopenharmony_ci#include <list>
19020a203aSopenharmony_ci#include <regex>
20020a203aSopenharmony_ci#include <string>
21020a203aSopenharmony_ci#include <vector>
22020a203aSopenharmony_ci
23020a203aSopenharmony_ci#include "file_util.h"
24020a203aSopenharmony_ci#include "log_util.h"
25020a203aSopenharmony_ci#include "hiview_logger.h"
26020a203aSopenharmony_ci#include "string_util.h"
27020a203aSopenharmony_ci
28020a203aSopenharmony_ciusing namespace std;
29020a203aSopenharmony_cinamespace OHOS {
30020a203aSopenharmony_cinamespace HiviewDFX {
31020a203aSopenharmony_ciDEFINE_LOG_TAG("FeatureAnalysis");
32020a203aSopenharmony_ci
33020a203aSopenharmony_ciconst string FeatureAnalysis::COMPOSE_PLUS = "+";
34020a203aSopenharmony_ciconst string FeatureAnalysis::COMPOSE_COLON = ":";
35020a203aSopenharmony_cinamespace {
36020a203aSopenharmony_ci    const string PARAMETER_REASON = "REASON";
37020a203aSopenharmony_ci}
38020a203aSopenharmony_ci
39020a203aSopenharmony_ciFeatureAnalysis::~FeatureAnalysis()
40020a203aSopenharmony_ci{
41020a203aSopenharmony_ci    HIVIEW_LOGD("<%{public}d> FeatureAnalysis::~FeatureAnalysis.", taskId_);
42020a203aSopenharmony_ci}
43020a203aSopenharmony_ci
44020a203aSopenharmony_cibool FeatureAnalysis::AnalysisLog()
45020a203aSopenharmony_ci{
46020a203aSopenharmony_ci    HIVIEW_LOGI("<%{public}d> begin analysis <%{public}s>, eventType is <%{public}s>.", taskId_,
47020a203aSopenharmony_ci        featureSet_.fullPath.c_str(), eventType_.c_str());
48020a203aSopenharmony_ci
49020a203aSopenharmony_ci    Extract();
50020a203aSopenharmony_ci    if (paramSeekRecord_.empty()) {
51020a203aSopenharmony_ci        errorCode_ = EXTRACT_ERROR;
52020a203aSopenharmony_ci        return false;
53020a203aSopenharmony_ci    }
54020a203aSopenharmony_ci    Compose();
55020a203aSopenharmony_ci    return true;
56020a203aSopenharmony_ci}
57020a203aSopenharmony_ci
58020a203aSopenharmony_civoid FeatureAnalysis::Extract()
59020a203aSopenharmony_ci{
60020a203aSopenharmony_ci    stringstream buffer("");
61020a203aSopenharmony_ci    if (!LogUtil::ReadFileBuff(featureSet_.fullPath, buffer) || !buffer.good() || buffer.eof()) {
62020a203aSopenharmony_ci        errorCode_ = BUFFER_ERROR;
63020a203aSopenharmony_ci        HIVIEW_LOGE("<%{public}d> file is invalid", taskId_);
64020a203aSopenharmony_ci        return;
65020a203aSopenharmony_ci    }
66020a203aSopenharmony_ci
67020a203aSopenharmony_ci    // extract info
68020a203aSopenharmony_ci    RawInfoPosition(buffer);
69020a203aSopenharmony_ci}
70020a203aSopenharmony_ci
71020a203aSopenharmony_civoid FeatureAnalysis::RawInfoPosition(stringstream& buffer)
72020a203aSopenharmony_ci{
73020a203aSopenharmony_ci    int skipStep = (featureSet_.skipStep > 0) ? featureSet_.skipStep : MAX_SKIP_LINE;
74020a203aSopenharmony_ci    int dismatchCount = 1; // default : countDismatch - 1 >= skipSpace
75020a203aSopenharmony_ci    string line;
76020a203aSopenharmony_ci    bool segmentStart = false;
77020a203aSopenharmony_ci    HIVIEW_LOGI("<%{public}d> skipStep is %{public}d. size:%{public}zu", taskId_, skipStep, featureSet_.rules.size());
78020a203aSopenharmony_ci    while (getline(buffer, line)) {
79020a203aSopenharmony_ci        if (line.length() > 2048 || // 2048 : max length of line
80020a203aSopenharmony_ci            (CheckStartSegment(segmentStart) && (line.empty() || line[0] == ' ' || line[0] == '\t'))) {
81020a203aSopenharmony_ci            continue;
82020a203aSopenharmony_ci        }
83020a203aSopenharmony_ci        GetCursorInfo(buffer, line);
84020a203aSopenharmony_ci        for (auto iterCmd = featureSet_.rules.begin(); iterCmd != featureSet_.rules.end();) {
85020a203aSopenharmony_ci            // Check the variable symbol and replace it with the parameter value of the variable
86020a203aSopenharmony_ci            FeatureRule& featureCmd = *iterCmd;
87020a203aSopenharmony_ci
88020a203aSopenharmony_ci            if (CheckDepend(featureCmd) || (!CheckVariableParam(featureCmd)) || (!IsSourceMatch(line, featureCmd))) {
89020a203aSopenharmony_ci                iterCmd++;
90020a203aSopenharmony_ci                continue;
91020a203aSopenharmony_ci            }
92020a203aSopenharmony_ci            int num = featureCmd.num;
93020a203aSopenharmony_ci            bool matchFlag = ParseElementForParam(line, featureCmd);
94020a203aSopenharmony_ci            while (--num > 0 && getline(buffer, line)) {
95020a203aSopenharmony_ci                GetCursorInfo(buffer, line);
96020a203aSopenharmony_ci                ParseElementForParam(line, featureCmd);
97020a203aSopenharmony_ci            }
98020a203aSopenharmony_ci
99020a203aSopenharmony_ci            if (matchFlag && featureCmd.cmdType == L2_RULES) {
100020a203aSopenharmony_ci                iterCmd = featureSet_.rules.erase(iterCmd); // erase will iterCmd++, but break avoid out of range
101020a203aSopenharmony_ci            } else {
102020a203aSopenharmony_ci                iterCmd++;
103020a203aSopenharmony_ci            }
104020a203aSopenharmony_ci            dismatchCount = 0;
105020a203aSopenharmony_ci            break;
106020a203aSopenharmony_ci        }
107020a203aSopenharmony_ci        dismatchCount++;
108020a203aSopenharmony_ci        if (featureSet_.rules.empty() || dismatchCount - 1 >= skipStep) {
109020a203aSopenharmony_ci            break;
110020a203aSopenharmony_ci        }
111020a203aSopenharmony_ci    }
112020a203aSopenharmony_ci}
113020a203aSopenharmony_ci
114020a203aSopenharmony_civoid FeatureAnalysis::GetCursorInfo(stringstream& buff, const string& line)
115020a203aSopenharmony_ci{
116020a203aSopenharmony_ci    line_ = line;
117020a203aSopenharmony_ci    lineCursor_ = static_cast<int>(buff.tellg()) - static_cast<int>(line.length()) - 1;
118020a203aSopenharmony_ci}
119020a203aSopenharmony_ci
120020a203aSopenharmony_cibool FeatureAnalysis::CheckStartSegment(bool& segmentStart) const
121020a203aSopenharmony_ci{
122020a203aSopenharmony_ci    if (segmentStart) {
123020a203aSopenharmony_ci        return segmentStart;
124020a203aSopenharmony_ci    }
125020a203aSopenharmony_ci    vector<std::pair<std::string, LineFeature>> info = paramSeekRecord_;
126020a203aSopenharmony_ci    for (const auto& one : info) {
127020a203aSopenharmony_ci        if (one.first.find("LayerTwoCmd") != string::npos ||
128020a203aSopenharmony_ci            one.first.find("LayerOneCmd") != string::npos) {
129020a203aSopenharmony_ci            segmentStart = true;
130020a203aSopenharmony_ci            break;
131020a203aSopenharmony_ci        }
132020a203aSopenharmony_ci    }
133020a203aSopenharmony_ci    return segmentStart;
134020a203aSopenharmony_ci}
135020a203aSopenharmony_ci
136020a203aSopenharmony_ci// line match source or not
137020a203aSopenharmony_cibool FeatureAnalysis::IsSourceMatch(const string& line, const FeatureRule& rule) const
138020a203aSopenharmony_ci{
139020a203aSopenharmony_ci    string cmdSrc = rule.source;
140020a203aSopenharmony_ci    // if startwith "@R@"
141020a203aSopenharmony_ci    if (L3_REGULAR_DESCRIPTOR == cmdSrc.substr(0, L3_REGULAR_DESCRIPTOR.length())) {
142020a203aSopenharmony_ci        cmdSrc = cmdSrc.substr(L3_REGULAR_DESCRIPTOR.length());
143020a203aSopenharmony_ci        return regex_search(line, regex(cmdSrc));
144020a203aSopenharmony_ci    }
145020a203aSopenharmony_ci
146020a203aSopenharmony_ci    // handle OR or AND expression
147020a203aSopenharmony_ci    bool isOrExp = (cmdSrc.find(L3_OR_DESCRIPTOR) == string::npos) ? false : true;
148020a203aSopenharmony_ci    bool isAndExp = (cmdSrc.find(L3_AND_DESCRIPTOR) == string::npos) ? false : true;
149020a203aSopenharmony_ci    if (!isOrExp && !isAndExp) {
150020a203aSopenharmony_ci        return line.find(cmdSrc) != string::npos;
151020a203aSopenharmony_ci    } else if (isOrExp) {
152020a203aSopenharmony_ci        return IsMatchOrExpression(line, cmdSrc);
153020a203aSopenharmony_ci    } else if (isAndExp) {
154020a203aSopenharmony_ci        return IsMatchAndExpression(line, cmdSrc);
155020a203aSopenharmony_ci    }
156020a203aSopenharmony_ci    return false;
157020a203aSopenharmony_ci}
158020a203aSopenharmony_ci
159020a203aSopenharmony_cibool FeatureAnalysis::IsMatchOrExpression(const string& line, const string& src) const
160020a203aSopenharmony_ci{
161020a203aSopenharmony_ci    vector<string> srcSplit;
162020a203aSopenharmony_ci    StringUtil::SplitStr(src, L3_OR_DESCRIPTOR, srcSplit, false, false);
163020a203aSopenharmony_ci    for (auto str : srcSplit) {
164020a203aSopenharmony_ci        if (line.find(str) != string::npos) {
165020a203aSopenharmony_ci            return true;
166020a203aSopenharmony_ci        }
167020a203aSopenharmony_ci    }
168020a203aSopenharmony_ci    return false;
169020a203aSopenharmony_ci}
170020a203aSopenharmony_ci
171020a203aSopenharmony_cibool FeatureAnalysis::IsMatchAndExpression(const string& line, const string& src) const
172020a203aSopenharmony_ci{
173020a203aSopenharmony_ci    string lineCpy = line;
174020a203aSopenharmony_ci    size_t pos;
175020a203aSopenharmony_ci    vector<string> srcSplit;
176020a203aSopenharmony_ci    StringUtil::SplitStr(src, L3_AND_DESCRIPTOR, srcSplit, false, false);
177020a203aSopenharmony_ci    for (auto str : srcSplit) {
178020a203aSopenharmony_ci        pos = lineCpy.find(str);
179020a203aSopenharmony_ci        if (pos == string::npos) {
180020a203aSopenharmony_ci            return false;
181020a203aSopenharmony_ci        }
182020a203aSopenharmony_ci        lineCpy = lineCpy.substr(pos + str.length());
183020a203aSopenharmony_ci    }
184020a203aSopenharmony_ci    return true;
185020a203aSopenharmony_ci}
186020a203aSopenharmony_ci
187020a203aSopenharmony_cibool FeatureAnalysis::ParseElementForParam(const string& src, FeatureRule& rule)
188020a203aSopenharmony_ci{
189020a203aSopenharmony_ci    if (rule.param.empty()) {
190020a203aSopenharmony_ci        return true; // if param is empty, erase the rule
191020a203aSopenharmony_ci    }
192020a203aSopenharmony_ci
193020a203aSopenharmony_ci    bool hasContinue = false;
194020a203aSopenharmony_ci    for (auto iter = rule.param.begin(); iter != rule.param.end();) {
195020a203aSopenharmony_ci        // subParam.first: parameter name; subParam.second: the expression to match
196020a203aSopenharmony_ci        string reg = "";
197020a203aSopenharmony_ci        smatch result;
198020a203aSopenharmony_ci        int seekType = GetSeekInfo(iter->second, reg);
199020a203aSopenharmony_ci        hasContinue = (seekType == LAST_MATCH) ? true : hasContinue;
200020a203aSopenharmony_ci        if (reg.find(L3_VARIABLE_TRACE_BLOCK) != string::npos || regex_search(src, result, regex(reg))) {
201020a203aSopenharmony_ci            string value = result.str(1).empty() ? "" : string(result.str(1));
202020a203aSopenharmony_ci            SetParamRecord(rule.name + "." + iter->first, FormatLineFeature(value, reg), seekType);
203020a203aSopenharmony_ci            SetStackRegex(rule.name + "." + iter->first, reg);
204020a203aSopenharmony_ci            if (seekType == FIRST_MATCH && rule.cmdType == L2_RULES) {
205020a203aSopenharmony_ci                iter = rule.param.erase(iter);
206020a203aSopenharmony_ci            } else {
207020a203aSopenharmony_ci                iter++;
208020a203aSopenharmony_ci            }
209020a203aSopenharmony_ci        } else {
210020a203aSopenharmony_ci            iter++;
211020a203aSopenharmony_ci        }
212020a203aSopenharmony_ci    }
213020a203aSopenharmony_ci
214020a203aSopenharmony_ci    return hasContinue ? false : rule.param.empty();
215020a203aSopenharmony_ci}
216020a203aSopenharmony_ci
217020a203aSopenharmony_ciint FeatureAnalysis::GetSeekInfo(const string& param, string& value) const
218020a203aSopenharmony_ci{
219020a203aSopenharmony_ci    if (param.find(L3_SEEK_LAST) != string::npos) {
220020a203aSopenharmony_ci        value = StringUtil::GetRightSubstr(param, L3_SEEK_LAST);
221020a203aSopenharmony_ci        return LAST_MATCH;
222020a203aSopenharmony_ci    }
223020a203aSopenharmony_ci    value = param;
224020a203aSopenharmony_ci    return FIRST_MATCH;
225020a203aSopenharmony_ci}
226020a203aSopenharmony_ci
227020a203aSopenharmony_cibool FeatureAnalysis::CheckVariableParam(FeatureRule& rule) const
228020a203aSopenharmony_ci{
229020a203aSopenharmony_ci    // Check whether there is a variable operator &@& in the command
230020a203aSopenharmony_ci    string symbol = "";
231020a203aSopenharmony_ci    string value = "";
232020a203aSopenharmony_ci    bool hasValSymbol = CheckVariable(rule, L3_DESCRIPTOR_LEFT, L3_DESCRIPTOR_RIGHT);
233020a203aSopenharmony_ci    if (!hasValSymbol) {
234020a203aSopenharmony_ci        return true;
235020a203aSopenharmony_ci    }
236020a203aSopenharmony_ci    // To replace it if there is one or more variable symbol
237020a203aSopenharmony_ci    for (const auto& param : paramSeekRecord_) {
238020a203aSopenharmony_ci        symbol = L3_DESCRIPTOR_LEFT + param.first + L3_DESCRIPTOR_RIGHT;
239020a203aSopenharmony_ci        value = param.second.value;
240020a203aSopenharmony_ci        ReplaceVariable(rule, symbol, value);
241020a203aSopenharmony_ci    }
242020a203aSopenharmony_ci    return !CheckVariable(rule, L3_DESCRIPTOR_LEFT, L3_DESCRIPTOR_RIGHT); // check var in config
243020a203aSopenharmony_ci}
244020a203aSopenharmony_ci
245020a203aSopenharmony_cibool FeatureAnalysis::CheckVariable(const FeatureRule& rule, const string& leftTag, const string& rightTag) const
246020a203aSopenharmony_ci{
247020a203aSopenharmony_ci    if ((rule.source.find(leftTag) != string::npos && rule.source.find(rightTag) != string::npos) ||
248020a203aSopenharmony_ci        (rule.depend.find(leftTag) != string::npos && rule.depend.find(rightTag) != string::npos)) {
249020a203aSopenharmony_ci        return true;
250020a203aSopenharmony_ci    }
251020a203aSopenharmony_ci    for (auto subParam : rule.param) {
252020a203aSopenharmony_ci        if (subParam.second.find(leftTag) != string::npos && subParam.second.find(rightTag) != string::npos) {
253020a203aSopenharmony_ci            return true;
254020a203aSopenharmony_ci        }
255020a203aSopenharmony_ci    }
256020a203aSopenharmony_ci
257020a203aSopenharmony_ci    return false;
258020a203aSopenharmony_ci}
259020a203aSopenharmony_ci
260020a203aSopenharmony_civoid FeatureAnalysis::ReplaceVariable(FeatureRule& rule, const string& symbol, const string& value) const
261020a203aSopenharmony_ci{
262020a203aSopenharmony_ci    ReplaceVariable(rule.source, symbol, value, rule.source);
263020a203aSopenharmony_ci    ReplaceVariable(rule.depend, symbol, value, rule.depend);
264020a203aSopenharmony_ci    for (auto subParam : rule.param) {
265020a203aSopenharmony_ci        if (ReplaceVariable(subParam.second, symbol, value, subParam.second)) {
266020a203aSopenharmony_ci            rule.param[subParam.first] = subParam.second;
267020a203aSopenharmony_ci        }
268020a203aSopenharmony_ci    }
269020a203aSopenharmony_ci}
270020a203aSopenharmony_ci
271020a203aSopenharmony_cibool FeatureAnalysis::ReplaceVariable(const string& src, const string& param,
272020a203aSopenharmony_ci    const string& value, string& des) const
273020a203aSopenharmony_ci{
274020a203aSopenharmony_ci    des = src;
275020a203aSopenharmony_ci    size_t pos = src.find(param);
276020a203aSopenharmony_ci    if (pos != string::npos) {
277020a203aSopenharmony_ci        des.replace(pos, param.length(), value, 0, value.length());
278020a203aSopenharmony_ci        return true;
279020a203aSopenharmony_ci    }
280020a203aSopenharmony_ci
281020a203aSopenharmony_ci    return false;
282020a203aSopenharmony_ci}
283020a203aSopenharmony_ci
284020a203aSopenharmony_ci/*
285020a203aSopenharmony_ci * return false if the depend element does not exist
286020a203aSopenharmony_ci * return false if the depend element exists and the feature that the depend element relies on has a value
287020a203aSopenharmony_ci * return true if the depend element exists and the feature that the depend element relies on has no value
288020a203aSopenharmony_ci */
289020a203aSopenharmony_cibool FeatureAnalysis::CheckDepend(const FeatureRule& rule) const
290020a203aSopenharmony_ci{
291020a203aSopenharmony_ci    bool result = false;
292020a203aSopenharmony_ci    if (rule.depend.empty()) {
293020a203aSopenharmony_ci        return result;
294020a203aSopenharmony_ci    }
295020a203aSopenharmony_ci
296020a203aSopenharmony_ci    if (paramSeekRecord_.empty()) {  // depend exist but no value
297020a203aSopenharmony_ci        return true;
298020a203aSopenharmony_ci    }
299020a203aSopenharmony_ci
300020a203aSopenharmony_ci    result = true;
301020a203aSopenharmony_ci    for (const auto& one : paramSeekRecord_) {
302020a203aSopenharmony_ci        if (one.first.find(rule.depend) != string::npos) {
303020a203aSopenharmony_ci            result = false; // depend exist but value exist
304020a203aSopenharmony_ci            break;
305020a203aSopenharmony_ci        }
306020a203aSopenharmony_ci    }
307020a203aSopenharmony_ci    return result;
308020a203aSopenharmony_ci}
309020a203aSopenharmony_ci
310020a203aSopenharmony_ciLineFeature FeatureAnalysis::FormatLineFeature(const string& value, const string& regex) const
311020a203aSopenharmony_ci{
312020a203aSopenharmony_ci    LineFeature paramRecord{};
313020a203aSopenharmony_ci    paramRecord.value = value;
314020a203aSopenharmony_ci    paramRecord.lineCursor = lineCursor_;
315020a203aSopenharmony_ci    return paramRecord;
316020a203aSopenharmony_ci}
317020a203aSopenharmony_ci
318020a203aSopenharmony_ci/*
319020a203aSopenharmony_ci * info : eventinfo_ or relatedInfo_ result
320020a203aSopenharmony_ci * params : rule info, for example : key : value
321020a203aSopenharmony_ci *  "SUBJECT": "BasicParam.s_subject",
322020a203aSopenharmony_ci *  "END_STACK": "MainCallTrace.s_trust_stack",
323020a203aSopenharmony_ci * features : Log feature
324020a203aSopenharmony_ci */
325020a203aSopenharmony_civoid FeatureAnalysis::Compose()
326020a203aSopenharmony_ci{
327020a203aSopenharmony_ci    string result;
328020a203aSopenharmony_ci    for (const auto& param : composeRule_) {
329020a203aSopenharmony_ci        // keep ordered rule_prio, REASON is specially composed
330020a203aSopenharmony_ci        if (eventInfo_.find(param.first) != eventInfo_.end() && param.first != PARAMETER_REASON) {
331020a203aSopenharmony_ci            continue;
332020a203aSopenharmony_ci        }
333020a203aSopenharmony_ci        result = ComposeParam(param.second);
334020a203aSopenharmony_ci        if (!result.empty()) {
335020a203aSopenharmony_ci            eventInfo_[param.first] = (param.first == PARAMETER_REASON) ?
336020a203aSopenharmony_ci                (eventInfo_[param.first] + COMPOSE_COLON + result) : result;
337020a203aSopenharmony_ci        }
338020a203aSopenharmony_ci    }
339020a203aSopenharmony_ci    ProcessReason(eventInfo_);
340020a203aSopenharmony_ci}
341020a203aSopenharmony_ci
342020a203aSopenharmony_cistring FeatureAnalysis::ComposeTrace(const string& filePath, const string& param,
343020a203aSopenharmony_ci    const vector<pair<string, LineFeature>>& lineFeatures, const string& regex) const
344020a203aSopenharmony_ci{
345020a203aSopenharmony_ci    string result;
346020a203aSopenharmony_ci    auto iter = find_if(lineFeatures.begin(), lineFeatures.end(),
347020a203aSopenharmony_ci        [&param](const pair<string, LineFeature>& one) {return one.first == param;});
348020a203aSopenharmony_ci    if (iter != lineFeatures.end()) {
349020a203aSopenharmony_ci        stringstream buffer("");
350020a203aSopenharmony_ci        if (LogUtil::ReadFileBuff(filePath, buffer)) {
351020a203aSopenharmony_ci            LogUtil::GetTrace(buffer, iter->second.lineCursor, regex, result);
352020a203aSopenharmony_ci        }
353020a203aSopenharmony_ci    }
354020a203aSopenharmony_ci    return result;
355020a203aSopenharmony_ci}
356020a203aSopenharmony_ci
357020a203aSopenharmony_cistring FeatureAnalysis::ComposeParam(const string& param) const
358020a203aSopenharmony_ci{
359020a203aSopenharmony_ci    std::vector<std::pair<std::string, LineFeature>> lineFeatures = paramSeekRecord_;
360020a203aSopenharmony_ci    vector<string> params = SplitParam(param);
361020a203aSopenharmony_ci    vector<string> results;
362020a203aSopenharmony_ci    for (const auto& key : params) {
363020a203aSopenharmony_ci        auto iter = find_if(lineFeatures.begin(), lineFeatures.end(),
364020a203aSopenharmony_ci            [&key](const pair<string, LineFeature>& one) {return one.first == key;});
365020a203aSopenharmony_ci        if (iter != lineFeatures.end()) {
366020a203aSopenharmony_ci            auto regexIter = stackRegex_.find(key);
367020a203aSopenharmony_ci            if (regexIter != stackRegex_.end()) {
368020a203aSopenharmony_ci                auto value = ComposeTrace(featureSet_.fullPath, key, lineFeatures, regexIter->second);
369020a203aSopenharmony_ci                results.emplace_back(value);
370020a203aSopenharmony_ci            } else {
371020a203aSopenharmony_ci                results.emplace_back(iter->second.value);
372020a203aSopenharmony_ci            }
373020a203aSopenharmony_ci        }
374020a203aSopenharmony_ci    }
375020a203aSopenharmony_ci
376020a203aSopenharmony_ci    string tag;
377020a203aSopenharmony_ci    if (!results.empty()) {
378020a203aSopenharmony_ci        if (param.find(COMPOSE_PLUS) != string::npos) {
379020a203aSopenharmony_ci            tag = " ";
380020a203aSopenharmony_ci        } else if (param.find(COMPOSE_COLON) != string::npos) {
381020a203aSopenharmony_ci            tag = COMPOSE_COLON;
382020a203aSopenharmony_ci        } else {
383020a203aSopenharmony_ci            tag = "";
384020a203aSopenharmony_ci        }
385020a203aSopenharmony_ci    }
386020a203aSopenharmony_ci    string result = StringUtil::VectorToString(results, false, tag);
387020a203aSopenharmony_ci    auto end = result.size() - tag.size();
388020a203aSopenharmony_ci    return (end > 0) ? result.substr(0, end) : result;
389020a203aSopenharmony_ci}
390020a203aSopenharmony_ci
391020a203aSopenharmony_civector<string> FeatureAnalysis::SplitParam(const string& param) const
392020a203aSopenharmony_ci{
393020a203aSopenharmony_ci    vector<string> params;
394020a203aSopenharmony_ci    if (param.find(COMPOSE_PLUS) != string::npos) {
395020a203aSopenharmony_ci        StringUtil::SplitStr(param, COMPOSE_PLUS, params, false, false);
396020a203aSopenharmony_ci    } else if (param.find(COMPOSE_COLON) != string::npos) {
397020a203aSopenharmony_ci        StringUtil::SplitStr(param, COMPOSE_COLON, params, false, false);
398020a203aSopenharmony_ci    } else {
399020a203aSopenharmony_ci        params.emplace_back(param);
400020a203aSopenharmony_ci    }
401020a203aSopenharmony_ci    return params;
402020a203aSopenharmony_ci}
403020a203aSopenharmony_ci
404020a203aSopenharmony_civoid FeatureAnalysis::ProcessReason(map<string, string>& info)
405020a203aSopenharmony_ci{
406020a203aSopenharmony_ci    if (info.find(PARAMETER_REASON) != info.end() &&
407020a203aSopenharmony_ci        info[PARAMETER_REASON].substr(0, 1) == COMPOSE_COLON) { // 1: first char
408020a203aSopenharmony_ci        info[PARAMETER_REASON] = info[PARAMETER_REASON].substr(1);
409020a203aSopenharmony_ci    }
410020a203aSopenharmony_ci}
411020a203aSopenharmony_ci
412020a203aSopenharmony_civoid FeatureAnalysis::SetParamRecord(const std::string& key, const LineFeature& value, const int type)
413020a203aSopenharmony_ci{
414020a203aSopenharmony_ci    if (type == LAST_MATCH) {
415020a203aSopenharmony_ci        for (auto iter = paramSeekRecord_.begin(); iter != paramSeekRecord_.end(); iter++) {
416020a203aSopenharmony_ci            if (iter->first == key) {
417020a203aSopenharmony_ci                paramSeekRecord_.erase(iter);
418020a203aSopenharmony_ci                break;
419020a203aSopenharmony_ci            }
420020a203aSopenharmony_ci        }
421020a203aSopenharmony_ci    }
422020a203aSopenharmony_ci    paramSeekRecord_.emplace_back(pair<string, LineFeature>(key, value));
423020a203aSopenharmony_ci}
424020a203aSopenharmony_ci
425020a203aSopenharmony_civoid FeatureAnalysis::SetStackRegex(const std::string& key, const std::string& regex)
426020a203aSopenharmony_ci{
427020a203aSopenharmony_ci    if (regex.find(L3_VARIABLE_TRACE_BLOCK) != string::npos) {
428020a203aSopenharmony_ci        stackRegex_.emplace(pair(key, StringUtil::EraseString(regex, L3_VARIABLE_TRACE_BLOCK)));
429020a203aSopenharmony_ci    }
430020a203aSopenharmony_ci}
431020a203aSopenharmony_ci} // namespace HiviewDFX
432020a203aSopenharmony_ci} // namespace OHOS
433