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 
16 #include <cstring>
17 #include <iostream>
18 #include <queue>
19 #include <vector>
20 #include <regex>
21 #include <iomanip>
22 
23 #include <securec.h>
24 #include <hilog/log.h>
25 #include <log_utils.h>
26 #include <hilog_cmd.h>
27 
28 #include "log_display.h"
29 
30 namespace OHOS {
31 namespace HiviewDFX {
32 using namespace std;
33 static constexpr char colCmd = ' ';
34 static constexpr int LOGTYPE_W = 8;
35 static constexpr int DOMAIN_TITLE_W = 10;
36 static constexpr int DOMAIN_W = (DOMAIN_TITLE_W - 2);
37 static constexpr int PID_W = 7;
38 static constexpr int PNAME_W = 32;
39 static constexpr int TAG_W = 32;
40 static constexpr int FREQ_W = 10;
41 static constexpr int TIME_W = 20;
42 static constexpr int TP_W = 10;
43 static constexpr int LINES_W = 10;
44 static constexpr int LENGTH_W = 10;
45 static constexpr int DROPPED_W = 10;
46 static constexpr int FLOAT_PRECSION = 2;
47 static constexpr int STATS_W = 60;
48 static constexpr int MIN2SEC = 60;
49 static constexpr int HOUR2MIN = 60;
50 static constexpr int HOUR2SEC = MIN2SEC * HOUR2MIN;
51 static constexpr int NS2MS = 1000 * 1000;
TimeStr(uint32_t tv_sec,uint32_t tv_nsec)52 static string TimeStr(uint32_t tv_sec, uint32_t tv_nsec)
53 {
54     char buffer[TIME_W] = {0};
55     int len = 0;
56     int ret = 0;
57     time_t ts = tv_sec;
58     struct tm tmLocal;
59     if (localtime_r(&ts, &tmLocal) == nullptr) {
60         return 0;
61     }
62     len += strftime(buffer, TIME_W, "%m-%d %H:%M:%S", &tmLocal);
63     ret = snprintf_s(buffer + len, TIME_W - len, TIME_W - len - 1, ".%03u", tv_nsec / NS2MS);
64     if (ret <= 0) {
65         return "ERROR";
66     }
67     return buffer;
68 }
69 
PrintDomainTitle()70 static void PrintDomainTitle()
71 {
72     cout << setw(LOGTYPE_W) << "LOGTYPE" << colCmd;
73     cout << setw(DOMAIN_TITLE_W) << "DOMAIN" << colCmd;
74 }
75 
PrintPidTitle()76 static void PrintPidTitle()
77 {
78     cout << setw(LOGTYPE_W) << "LOGTYPE" << colCmd;
79     cout << setw(PID_W) << "PID" << colCmd;
80     cout << setw(PNAME_W) << "NAME" << colCmd;
81 }
82 
PrintStatsTitile()83 static void PrintStatsTitile()
84 {
85     cout << setw(TAG_W) << "TAG" << colCmd;
86     cout << setw(FREQ_W) << "MAX_FREQ" << colCmd;
87     cout << setw(TIME_W) << "TIME" << colCmd;
88     cout << setw(TP_W) << "MAX_TP" << colCmd;
89     cout << setw(TIME_W) << "TIME" << colCmd;
90     cout << setw(LINES_W) << "LINES" << colCmd;
91     cout << setw(LENGTH_W) << "LENGTH" << colCmd;
92     cout << setw(DROPPED_W) << "DROPPED" << colCmd;
93 }
94 
GetTotalLines(const StatsRsp & rsp)95 static uint32_t GetTotalLines(const StatsRsp &rsp)
96 {
97     uint16_t i = 0;
98     uint32_t lines = 0;
99     for (i = 0; i < LevelNum; i++) {
100         lines += rsp.lines[i];
101     }
102     return lines;
103 }
104 
GetTotalLen(const StatsRsp & rsp)105 static uint64_t GetTotalLen(const StatsRsp &rsp)
106 {
107     uint16_t i = 0;
108     uint64_t len = 0;
109     for (i = 0; i < LevelNum; i++) {
110         len += rsp.len[i];
111     }
112     return len;
113 }
114 
PrintStats(const StatsRsp & rsp)115 static void PrintStats(const StatsRsp &rsp)
116 {
117     cout << fixed;
118     cout << setw(FREQ_W) << setprecision(FLOAT_PRECSION) << rsp.freqMax << colCmd;
119     cout << setw(TIME_W) << TimeStr(rsp.freqMaxSec, rsp.freqMaxNsec) << colCmd;
120     cout << setw(TP_W) << setprecision(FLOAT_PRECSION) << rsp.throughputMax << colCmd;
121     cout << setw(TIME_W) << TimeStr(rsp.tpMaxSec, rsp.tpMaxNsec) << colCmd;
122     cout << setw(LINES_W) << GetTotalLines(rsp) << colCmd;
123     cout << setw(LENGTH_W) << Size2Str(GetTotalLen(rsp)) << colCmd;
124     cout << setw(DROPPED_W) << rsp.dropped << colCmd;
125 }
126 
DurationStr(uint32_t tv_sec,uint32_t tv_nsec)127 static string DurationStr(uint32_t tv_sec, uint32_t tv_nsec)
128 {
129     char buffer[TIME_W] = {0};
130     uint32_t tmp = tv_sec;
131     uint32_t hour = tmp / HOUR2SEC;
132     tmp -= (hour * HOUR2SEC);
133     uint32_t min = tmp / MIN2SEC;
134     uint32_t sec = tmp - (min * MIN2SEC);
135     uint32_t msec = tv_nsec / NS2MS;
136     int ret = 0;
137     ret = snprintf_s(buffer, TIME_W, TIME_W - 1, "%uh%um%us.%u", hour, min, sec, msec);
138     if (ret <= 0) {
139         return "ERROR";
140     }
141     return buffer;
142 }
143 
144 template<typename T>
SortByLens(vector<T> & v,const T * list,int num)145 static void SortByLens(vector<T>& v, const T* list, int num)
146 {
147     v.insert(v.begin(), list, list + num);
148     std::sort(v.begin(), v.end(), [](T& a, T& b) {
149         return GetTotalLen(a.stats) > GetTotalLen(b.stats);
150     });
151 }
152 
SortDomainList(vector<DomainStatsRsp> & vd,const DomainStatsRsp * domainList,int num)153 static void SortDomainList(vector<DomainStatsRsp>& vd, const DomainStatsRsp* domainList, int num)
154 {
155     SortByLens(vd, domainList, num);
156 }
157 
SortProcList(vector<ProcStatsRsp> & vp,const ProcStatsRsp * procList,int num)158 static void SortProcList(vector<ProcStatsRsp>& vp, const ProcStatsRsp* procList, int num)
159 {
160     SortByLens(vp, procList, num);
161 }
162 
SortTagList(vector<TagStatsRsp> & vt,const TagStatsRsp * tagList,int num)163 static void SortTagList(vector<TagStatsRsp>& vt, const TagStatsRsp* tagList, int num)
164 {
165     SortByLens(vt, tagList, num);
166 }
167 
HilogShowDomainStatsInfo(const StatsQueryRsp & rsp)168 static void HilogShowDomainStatsInfo(const StatsQueryRsp& rsp)
169 {
170     cout << "Domain Table:" << endl;
171     PrintDomainTitle();
172     PrintStatsTitile();
173     cout << endl;
174     uint16_t i = 0;
175     for (i = 0; i < rsp.typeNum; i++) {
176         LogTypeDomainStatsRsp &ldStats = rsp.ldStats[i];
177         uint16_t j = 0;
178         if (ldStats.dStats == nullptr) {
179             continue;
180         }
181         vector<DomainStatsRsp> vd; // sort domain list
182         SortDomainList(vd, ldStats.dStats, ldStats.domainNum);
183         for (j = 0; j < ldStats.domainNum; j++) {
184             DomainStatsRsp &dStats = vd[j];
185             cout << setw(LOGTYPE_W) << LogType2Str(ldStats.type) << colCmd;
186             cout << std::hex << "0x" << setw(DOMAIN_W) << dStats.domain << std::dec << colCmd;
187             cout << setw(TAG_W) << "-" << colCmd;
188             PrintStats(dStats.stats);
189             cout << endl;
190             uint16_t k = 0;
191             if (dStats.tStats == nullptr) {
192                 continue;
193             }
194             vector<TagStatsRsp> vt; // sort tag list
195             SortTagList(vt, dStats.tStats, dStats.tagNum);
196             for (k = 0; k < dStats.tagNum; k++) {
197                 TagStatsRsp &tStats = vt[k];
198                 cout << setw(LOGTYPE_W) << LogType2Str(ldStats.type) << colCmd;
199                 cout << std::hex << "0x" << setw(DOMAIN_W) << dStats.domain << std::dec << colCmd;
200                 cout << setw(TAG_W) << tStats.tag << colCmd;
201                 PrintStats(tStats.stats);
202                 cout << endl;
203             }
204         }
205     }
206 }
207 
GetProcessName(const ProcStatsRsp & pStats)208 static string GetProcessName(const ProcStatsRsp &pStats)
209 {
210     /* hap process is forked from /system/bin/appspawn, sa process is started by /system/bin/sa_main
211        the name will be changed after process forking, hilogd holds the original name always,
212        here we need reconfirm it */
213     string name = GetNameByPid(pStats.pid);
214     if (name == "") {
215         name = pStats.name;
216     }
217     return name.substr(0, PNAME_W - 1);
218 }
219 
HiLogShowProcInfo(const std::string & logType,uint32_t pid,const std::string & processName,const std::string & tag)220 static inline void HiLogShowProcInfo(const std::string& logType, uint32_t pid, const std::string& processName,
221     const std::string& tag)
222 {
223     cout << setw(LOGTYPE_W) << logType << colCmd;
224     cout << setw(PID_W) << pid << colCmd;
225     cout << setw(PNAME_W) << processName << colCmd;
226     cout << setw(TAG_W) << tag << colCmd;
227 }
228 
HilogShowProcStatsInfo(const StatsQueryRsp & rsp)229 static void HilogShowProcStatsInfo(const StatsQueryRsp& rsp)
230 {
231     cout << "Pid Table:" << endl;
232     PrintPidTitle();
233     PrintStatsTitile();
234     cout << endl;
235     uint16_t i = 0;
236     if (rsp.pStats == nullptr) {
237         return;
238     }
239     vector<ProcStatsRsp> vp; // sort process list
240     SortProcList(vp, rsp.pStats, rsp.procNum);
241     for (i = 0; i < rsp.procNum; i++) {
242         ProcStatsRsp &pStats = vp[i];
243         string name = GetProcessName(pStats);
244         HiLogShowProcInfo("-", pStats.pid, name, "-");
245         PrintStats(pStats.stats);
246         cout << endl;
247         uint16_t j = 0;
248         if (pStats.lStats == nullptr) {
249             continue;
250         }
251         for (j = 0; j < pStats.typeNum; j++) {
252             LogTypeStatsRsp &lStats = pStats.lStats[j];
253             if (GetTotalLines(lStats.stats) == 0) {
254                 continue;
255             }
256             HiLogShowProcInfo(LogType2Str(lStats.type), pStats.pid, name, "-");
257             PrintStats(lStats.stats);
258             cout << endl;
259         }
260         if (pStats.tStats == nullptr) {
261             continue;
262         }
263         vector<TagStatsRsp> vt; // sort tag list
264         SortTagList(vt, pStats.tStats, pStats.tagNum);
265         for (j = 0; j < pStats.tagNum; j++) {
266             TagStatsRsp &tStats = vt[j];
267             HiLogShowProcInfo("-", pStats.pid, name, std::string(tStats.tag));
268             PrintStats(tStats.stats);
269             cout << endl;
270         }
271     }
272 }
273 
HilogShowLogStatsInfo(const StatsQueryRsp & rsp)274 void HilogShowLogStatsInfo(const StatsQueryRsp& rsp)
275 {
276     cout << std::left;
277     cout << "Log statistic report (Duration: " << DurationStr(rsp.durationSec, rsp.durationNsec);
278     cout << ", From: " << TimeStr(rsp.tsBeginSec, rsp.tsBeginNsec) << "):" << endl;
279     uint32_t lines = 0;
280     uint64_t lens = 0;
281     for (int i = 0; i < LevelNum; i++) {
282         lines += rsp.totalLines[i];
283         lens += rsp.totalLens[i];
284     }
285     if (lines == 0) {
286         return;
287     }
288     cout << "Total lines: " << lines << ", length: " << Size2Str(lens) << endl;
289     static const int PERCENT = 100;
290     for (int i = 0; i < LevelNum; i++) {
291         string level = LogLevel2Str(static_cast<uint16_t>(i + LevelBase));
292         cout << level << " lines: " << rsp.totalLines[i];
293         cout << "(" << setprecision(FLOAT_PRECSION) << (static_cast<float>(rsp.totalLines[i] * PERCENT) / lines) <<
294             "%)";
295         cout << ", length: " << Size2Str(rsp.totalLens[i]);
296         cout << "(" << setprecision(FLOAT_PRECSION) << (static_cast<float>(rsp.totalLens[i] * PERCENT) / lens) <<
297             "%)";
298         cout<< endl;
299     }
300     cout << setw(STATS_W) << setfill('-') << "-" << endl;
301     HilogShowDomainStatsInfo(rsp);
302     cout << setw(STATS_W) << setfill('-') << "-" << endl;
303     HilogShowProcStatsInfo(rsp);
304 }
305 } // namespace HiviewDFX
306 } // namespace OHOS