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 "log_buffer.h"
17
18 #include <cstring>
19 #include <thread>
20 #include "hilog_common.h"
21 #include "flow_control_init.h"
22 #include "log_time_stamp.h"
23 namespace OHOS {
24 namespace HiviewDFX {
25 using namespace std;
26
27 const float DROP_RATIO = 0.05;
28 static size_t g_maxBufferSize = 4194304;
29 static size_t g_maxBufferSizeByType[LOG_TYPE_MAX] = {262144, 262144, 262144, 262144, 262144};
30 const int DOMAIN_STRICT_MASK = 0xd000000;
31 const int DOMAIN_FUZZY_MASK = 0xdffff;
32 const int DOMAIN_MODULE_BITS = 8;
33
HilogBuffer()34 HilogBuffer::HilogBuffer()
35 {
36 size = 0;
37 for (int i = 0; i < LOG_TYPE_MAX; i++) {
38 sizeByType[i] = 0;
39 cacheLenByType[i] = 0;
40 printLenByType[i] = 0;
41 droppedByType[i] = 0;
42 }
43 }
44
~HilogBuffer()45 HilogBuffer::~HilogBuffer() {}
46
Insert(const HilogMsg & msg)47 size_t HilogBuffer::Insert(const HilogMsg& msg)
48 {
49 size_t elemSize = CONTENT_LEN((&msg)); /* include '\0' */
50
51 if (unlikely(msg.tag_len > MAX_TAG_LEN || msg.tag_len == 0 || elemSize > MAX_LOG_LEN || elemSize <= 0)) {
52 return 0;
53 }
54
55 LogMsgContainer &msgList = (msg.type == LOG_KMSG) ? hilogKlogList : hilogDataList;
56 HilogData msgAsData(msg);
57 {
58 std::unique_lock<decltype(hilogBufferMutex)> lock(hilogBufferMutex);
59
60 // Delete old entries when full
61 if (elemSize + sizeByType[msg.type] >= g_maxBufferSizeByType[msg.type]) {
62 // Drop 5% of maximum log when full
63 std::list<HilogData>::iterator it = msgList.begin();
64 while (sizeByType[msg.type] > g_maxBufferSizeByType[msg.type] * (1 - DROP_RATIO) &&
65 it != msgList.end()) {
66 if ((*it).type != msg.type) { // Only remove old logs of the same type
67 ++it;
68 continue;
69 }
70 OnDeleteItem(it);
71 size_t cLen = it->len - it->tag_len;
72 size -= cLen;
73 sizeByType[(*it).type] -= cLen;
74 it = msgList.erase(it);
75 }
76
77 // Re-confirm if enough elements has been removed
78 if (sizeByType[msg.type] >= g_maxBufferSizeByType[msg.type]) {
79 std::cout << "Failed to clean old logs." << std::endl;
80 }
81 }
82
83 // Append new log into HilogBuffer
84 msgList.push_back(std::move(msgAsData));
85 OnPushBackedItem(msgList);
86 }
87
88 // Update current size of HilogBuffer
89 size += elemSize;
90 sizeByType[msg.type] += elemSize;
91 cacheLenByType[msg.type] += elemSize;
92 if (cacheLenByDomain.count(msg.domain) == 0) {
93 cacheLenByDomain.insert(pair<uint32_t, uint64_t>(msg.domain, elemSize));
94 } else {
95 cacheLenByDomain[msg.domain] += elemSize;
96 }
97
98 // Notify readers about new element added
99 OnNewItem(msgList);
100 return elemSize;
101 }
102
Query(const LogFilterExt & filter,const ReaderId & id,OnFound onFound)103 bool HilogBuffer::Query(const LogFilterExt& filter, const ReaderId& id, OnFound onFound)
104 {
105 auto reader = GetReader(id);
106 if (!reader) {
107 std::cerr << "Reader not registered!\n";
108 return false;
109 }
110 uint16_t qTypes = filter.inclusions.types;
111 LogMsgContainer &msgList = (qTypes == (0b01 << LOG_KMSG)) ? hilogKlogList : hilogDataList;
112
113 std::shared_lock<decltype(hilogBufferMutex)> lock(hilogBufferMutex);
114
115 if (reader->m_msgList != &msgList) {
116 reader->m_msgList = &msgList;
117 reader->m_pos = msgList.begin();
118 }
119
120 while (reader->m_pos != msgList.end()) {
121 const HilogData& logData = *reader->m_pos;
122 reader->m_pos++;
123 if (LogMatchFilter(filter, logData)) {
124 UpdateStatistics(logData);
125 if (onFound) {
126 onFound(logData);
127 }
128 return true;
129 }
130 }
131 return false;
132 }
133
UpdateStatistics(const HilogData & logData)134 void HilogBuffer::UpdateStatistics(const HilogData& logData)
135 {
136 printLenByType[logData.type] += strlen(logData.content);
137 auto it = printLenByDomain.find(logData.domain);
138 if (it == printLenByDomain.end()) {
139 printLenByDomain.insert(pair<uint32_t, uint64_t>(logData.domain, strlen(logData.content)));
140 } else {
141 printLenByDomain[logData.domain] += strlen(logData.content);
142 }
143 }
144
Delete(uint16_t logType)145 int32_t HilogBuffer::Delete(uint16_t logType)
146 {
147 std::list<HilogData> &msgList = (logType == (0b01 << LOG_KMSG)) ? hilogKlogList : hilogDataList;
148 if (logType >= LOG_TYPE_MAX) {
149 return ERR_LOG_TYPE_INVALID;
150 }
151 size_t sum = 0;
152 std::unique_lock<decltype(hilogBufferMutex)> lock(hilogBufferMutex);
153 std::list<HilogData>::iterator it = msgList.begin();
154
155 // Delete logs corresponding to queryCondition
156 while (it != msgList.end()) {
157 // Only remove old logs of the same type
158 if ((*it).type != logType) {
159 ++it;
160 continue;
161 }
162 // Delete corresponding logs
163 OnDeleteItem(it);
164
165 size_t cLen = it->len - it->tag_len;
166 sum += cLen;
167 sizeByType[(*it).type] -= cLen;
168 size -= cLen;
169 it = msgList.erase(it);
170 }
171 return sum;
172 }
173
CreateBufReader(std::function<void ()> onNewDataCallback)174 HilogBuffer::ReaderId HilogBuffer::CreateBufReader(std::function<void()> onNewDataCallback)
175 {
176 std::unique_lock<decltype(m_logReaderMtx)> lock(m_logReaderMtx);
177 auto reader = std::make_shared<BufferReader>();
178 reader->m_onNewDataCallback = onNewDataCallback;
179 ReaderId id = reinterpret_cast<ReaderId>(reader.get());
180 m_logReaders.insert(std::make_pair(id, reader));
181 return id;
182 }
183
RemoveBufReader(const ReaderId & id)184 void HilogBuffer::RemoveBufReader(const ReaderId& id)
185 {
186 std::unique_lock<decltype(m_logReaderMtx)> lock(m_logReaderMtx);
187 auto it = m_logReaders.find(id);
188 if (it != m_logReaders.end()) {
189 m_logReaders.erase(it);
190 }
191 }
192
OnDeleteItem(LogMsgContainer::iterator itemPos)193 void HilogBuffer::OnDeleteItem(LogMsgContainer::iterator itemPos)
194 {
195 std::shared_lock<decltype(m_logReaderMtx)> lock(m_logReaderMtx);
196 for (auto& [id, readerPtr] : m_logReaders) {
197 if (readerPtr->m_pos == itemPos) {
198 readerPtr->m_pos = std::next(itemPos);
199 }
200 }
201 }
202
OnPushBackedItem(LogMsgContainer & msgList)203 void HilogBuffer::OnPushBackedItem(LogMsgContainer& msgList)
204 {
205 std::shared_lock<decltype(m_logReaderMtx)> lock(m_logReaderMtx);
206 for (auto& [id, readerPtr] : m_logReaders) {
207 if (readerPtr->m_pos == msgList.end()) {
208 readerPtr->m_pos = std::prev(msgList.end());
209 }
210 }
211 }
212
OnNewItem(LogMsgContainer & msgList)213 void HilogBuffer::OnNewItem(LogMsgContainer& msgList)
214 {
215 std::shared_lock<decltype(m_logReaderMtx)> lock(m_logReaderMtx);
216 for (auto& [id, readerPtr] : m_logReaders) {
217 if (readerPtr->m_msgList == &msgList && readerPtr->m_onNewDataCallback) {
218 readerPtr->m_onNewDataCallback();
219 }
220 }
221 }
222
GetReader(const ReaderId & id)223 std::shared_ptr<HilogBuffer::BufferReader> HilogBuffer::GetReader(const ReaderId& id)
224 {
225 std::shared_lock<decltype(m_logReaderMtx)> lock(m_logReaderMtx);
226 auto it = m_logReaders.find(id);
227 if (it != m_logReaders.end()) {
228 return it->second;
229 }
230 return std::shared_ptr<HilogBuffer::BufferReader>();
231 }
232
GetBuffLen(uint16_t logType)233 int64_t HilogBuffer::GetBuffLen(uint16_t logType)
234 {
235 if (logType >= LOG_TYPE_MAX) {
236 return ERR_LOG_TYPE_INVALID;
237 }
238 uint64_t buffSize = g_maxBufferSizeByType[logType];
239 return buffSize;
240 }
241
SetBuffLen(uint16_t logType,uint64_t buffSize)242 int32_t HilogBuffer::SetBuffLen(uint16_t logType, uint64_t buffSize)
243 {
244 if (logType >= LOG_TYPE_MAX) {
245 return ERR_LOG_TYPE_INVALID;
246 }
247 if (buffSize <= 0 || buffSize > MAX_BUFFER_SIZE) {
248 return ERR_BUFF_SIZE_INVALID;
249 }
250 g_maxBufferSizeByType[logType] = buffSize;
251 g_maxBufferSize += (buffSize - sizeByType[logType]);
252 return buffSize;
253 }
254
GetStatisticInfoByLog(uint16_t logType,uint64_t & printLen,uint64_t & cacheLen,int32_t & dropped)255 int32_t HilogBuffer::GetStatisticInfoByLog(uint16_t logType, uint64_t& printLen, uint64_t& cacheLen, int32_t& dropped)
256 {
257 if (logType >= LOG_TYPE_MAX) {
258 return ERR_LOG_TYPE_INVALID;
259 }
260 printLen = printLenByType[logType];
261 cacheLen = cacheLenByType[logType];
262 dropped = GetDroppedByType(logType);
263 return 0;
264 }
265
GetStatisticInfoByDomain(uint32_t domain,uint64_t & printLen,uint64_t & cacheLen,int32_t & dropped)266 int32_t HilogBuffer::GetStatisticInfoByDomain(uint32_t domain, uint64_t& printLen, uint64_t& cacheLen,
267 int32_t& dropped)
268 {
269 printLen = printLenByDomain[domain];
270 cacheLen = cacheLenByDomain[domain];
271 dropped = GetDroppedByDomain(domain);
272 return 0;
273 }
274
ClearStatisticInfoByLog(uint16_t logType)275 int32_t HilogBuffer::ClearStatisticInfoByLog(uint16_t logType)
276 {
277 if (logType >= LOG_TYPE_MAX) {
278 return ERR_LOG_TYPE_INVALID;
279 }
280 ClearDroppedByType();
281 printLenByType[logType] = 0;
282 cacheLenByType[logType] = 0;
283 droppedByType[logType] = 0;
284 return 0;
285 }
286
ClearStatisticInfoByDomain(uint32_t domain)287 int32_t HilogBuffer::ClearStatisticInfoByDomain(uint32_t domain)
288 {
289 ClearDroppedByDomain();
290 printLenByDomain[domain] = 0;
291 cacheLenByDomain[domain] = 0;
292 droppedByDomain[domain] = 0;
293 return 0;
294 }
295
LogMatchFilter(const LogFilterExt & filter,const HilogData & logData)296 bool HilogBuffer::LogMatchFilter(const LogFilterExt& filter, const HilogData& logData)
297 {
298 /* domain patterns:
299 * strict mode: 0xdxxxxxx (full)
300 * fuzzy mode: 0xdxxxx (using last 2 digits of full domain as mask)
301 */
302 // inclusions
303 if (((static_cast<uint8_t>((0b01 << (logData.type)) & (filter.inclusions.types)) == 0) ||
304 (static_cast<uint8_t>((0b01 << (logData.level)) & (filter.inclusions.levels)) == 0)))
305 return false;
306
307 if (!filter.inclusions.pids.empty()) {
308 auto it = std::find(filter.inclusions.pids.begin(), filter.inclusions.pids.end(), logData.pid);
309 if (it == filter.inclusions.pids.end())
310 return false;
311 }
312 if (!filter.inclusions.domains.empty()) {
313 auto it = std::find_if(filter.inclusions.domains.begin(), filter.inclusions.domains.end(),
314 [&] (uint32_t domain) {
315 return ((domain >= DOMAIN_STRICT_MASK && domain == logData.domain) ||
316 (domain <= DOMAIN_FUZZY_MASK && domain == (logData.domain >> DOMAIN_MODULE_BITS)));
317 });
318 if (it == filter.inclusions.domains.end())
319 return false;
320 }
321 if (!filter.inclusions.tags.empty()) {
322 auto it = std::find(filter.inclusions.tags.begin(), filter.inclusions.tags.end(), logData.tag);
323 if (it == filter.inclusions.tags.end())
324 return false;
325 }
326
327 // exclusion
328 if (!filter.exclusions.pids.empty()) {
329 auto it = std::find(filter.exclusions.pids.begin(), filter.exclusions.pids.end(), logData.pid);
330 if (it != filter.exclusions.pids.end())
331 return false;
332 }
333
334 if (!filter.exclusions.domains.empty()) {
335 auto it = std::find_if(filter.exclusions.domains.begin(), filter.exclusions.domains.end(),
336 [&] (uint32_t domain) {
337 return ((domain >= DOMAIN_STRICT_MASK && domain == logData.domain) ||
338 (domain <= DOMAIN_FUZZY_MASK && domain == (logData.domain >> DOMAIN_MODULE_BITS)));
339 });
340 if (it != filter.exclusions.domains.end())
341 return false;
342 }
343 if (!filter.exclusions.tags.empty()) {
344 auto it = std::find(filter.exclusions.tags.begin(), filter.exclusions.tags.end(), logData.tag);
345 if (it != filter.exclusions.tags.end())
346 return false;
347 }
348 if ((static_cast<uint8_t>((0b01 << (logData.type)) & (filter.exclusions.types)) != 0) ||
349 (static_cast<uint8_t>((0b01 << (logData.level)) & (filter.exclusions.levels)) != 0)) {
350 return false;
351 }
352 return true;
353 }
354 } // namespace HiviewDFX
355 } // namespace OHOS
356