• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 "trace_file_writer.h"
16 
17 #include <cinttypes>
18 #include <memory>
19 #include <sys/statvfs.h>
20 #include <unistd.h>
21 
22 #include "common.h"
23 #include "logging.h"
24 
25 using CharPtr = std::unique_ptr<char>::pointer;
26 using ConstCharPtr = std::unique_ptr<const char>::pointer;
27 
28 namespace {
29 constexpr int MB_TO_BYTE = (1024 * 1024);
30 constexpr int GB_TO_BYTE = (1024 * 1024 * 1024);
31 constexpr int SPLIT_FILE_MIN_SIZE = 200;    // split file min size
32 constexpr int SPLIT_FILE_DEFAULT_NUM = 10;  // split file default num
33 } // namespace
34 
TraceFileWriter(const std::string & path)35 TraceFileWriter::TraceFileWriter(const std::string& path) : TraceFileWriter(path, false, 0, 0)
36 {
37 }
38 
TraceFileWriter(const std::string & path,bool splitFile,uint32_t splitFileMaxSizeMb,uint32_t splitFileMaxNum)39 TraceFileWriter::TraceFileWriter(const std::string& path, bool splitFile, uint32_t splitFileMaxSizeMb,
40     uint32_t splitFileMaxNum) : path_(path), isSplitFile_(splitFile)
41 {
42     splitFileMaxSize_ = (splitFileMaxSizeMb < SPLIT_FILE_MIN_SIZE) ? (SPLIT_FILE_MIN_SIZE * MB_TO_BYTE) :
43         (splitFileMaxSizeMb * MB_TO_BYTE);
44     splitFileMaxNum_ = (splitFileMaxNum == 0) ? SPLIT_FILE_DEFAULT_NUM : splitFileMaxNum;
45     oldPath_ = path;
46     fileNum_ = 1;
47 
48     WriteHeader();
49     (void)FlushStream();
50 }
51 
~TraceFileWriter()52 TraceFileWriter::~TraceFileWriter()
53 {
54     (void)FlushStream();
55     if (stream_.is_open()) {
56         stream_.close();
57     }
58 }
59 
Path() const60 std::string TraceFileWriter::Path() const
61 {
62     return path_;
63 }
64 
SetPluginConfig(const void * data,size_t size)65 bool TraceFileWriter::SetPluginConfig(const void* data, size_t size)
66 {
67     if (isSplitFile_) {
68         std::vector<char> configVec;
69         auto configData = reinterpret_cast<ConstCharPtr>(data);
70         configVec.insert(configVec.end(), configData, configData + size);
71         pluginConfigsData_.push_back(std::move(configVec));
72     }
73 
74     Write(data, size);
75     return true;
76 }
77 
SetTimeStamp()78 void TraceFileWriter::SetTimeStamp()
79 {
80     constexpr uint64_t nanoSeconds = 1000000000;
81     struct timespec ts;
82     clock_gettime(CLOCK_BOOTTIME, &ts);
83     header_.data_.boottime = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
84         static_cast<uint64_t>(ts.tv_nsec);
85     clock_gettime(CLOCK_REALTIME, &ts);
86     header_.data_.realtime = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
87         static_cast<uint64_t>(ts.tv_nsec);
88     clock_gettime(CLOCK_REALTIME_COARSE, &ts);
89     header_.data_.realtimeCoarse = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
90         static_cast<uint64_t>(ts.tv_nsec);
91     clock_gettime(CLOCK_MONOTONIC, &ts);
92     header_.data_.monotonic = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
93         static_cast<uint64_t>(ts.tv_nsec);
94     clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
95     header_.data_.monotonicCoarse = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
96         static_cast<uint64_t>(ts.tv_nsec);
97     clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
98     header_.data_.monotonicRaw = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
99         static_cast<uint64_t>(ts.tv_nsec);
100 }
101 
WriteHeader()102 bool TraceFileWriter::WriteHeader()
103 {
104     LogDiskUsage();
105     if (isSplitFile_) {
106         std::string timeStr = COMMON::GetTimeStr();
107         std::size_t pos = oldPath_.find_last_of('.');
108         if (pos != std::string::npos) {
109             path_ = oldPath_.substr(0, pos) + "_" + timeStr + "_" + std::to_string(fileNum_) +
110                 oldPath_.substr(pos, oldPath_.size());
111         } else {
112             path_ = oldPath_ + "_" + timeStr + "_" + std::to_string(fileNum_);
113         }
114         splitFilePaths_.push(path_);
115         DeleteOldSplitFile();
116     }
117 
118     stream_.open(path_, std::ios_base::out | std::ios_base::binary);
119     CHECK_TRUE(stream_.is_open(), false, "open %s failed, %d!", path_.c_str(), errno);
120 
121     // write initial header, makes file write position move forward
122     helper_ = {};
123     header_ = {};
124     stream_.write(reinterpret_cast<CharPtr>(&header_), sizeof(header_));
125     CHECK_TRUE(stream_, false, "write initial header to %s failed!", path_.c_str());
126     dataSize_ = header_.HEADER_SIZE;
127     HILOG_INFO(LOG_CORE, "write file(%s) header end", path_.c_str());
128     return true;
129 }
130 
131 // delete first split file if split file num over max
DeleteOldSplitFile()132 void TraceFileWriter::DeleteOldSplitFile()
133 {
134     if (splitFilePaths_.size() <= splitFileMaxNum_) {
135         HILOG_INFO(LOG_CORE, "splitFilePaths_ size %zu, no need to delete.", splitFilePaths_.size());
136         return;
137     }
138 
139     std::string splitFilePath = splitFilePaths_.front();
140     int ret = unlink(splitFilePath.c_str());
141     HILOG_INFO(LOG_CORE, "DeleteOldSplitFile remove %s return %d. ", splitFilePath.c_str(), ret);
142     splitFilePaths_.pop();
143 }
144 
Write(const void * data,size_t size)145 long TraceFileWriter::Write(const void* data, size_t size)
146 {
147     if (isSplitFile_ && !isStop_) {
148         if (IsSplitFile(size)) {
149             return -1;
150         }
151     }
152 
153     uint32_t dataLen = size;
154     CHECK_TRUE(stream_.is_open(), 0, "binary file %s not open or open failed!", path_.c_str());
155 
156     // write 4B data length.
157     stream_.write(reinterpret_cast<CharPtr>(&dataLen), sizeof(dataLen));
158     CHECK_TRUE(stream_, 0, "binary file %s write raw buffer size failed!", path_.c_str());
159     CHECK_TRUE(helper_.AddSegment(reinterpret_cast<uint8_t*>(&dataLen), sizeof(dataLen)),
160         0, "Add payload for size %u FAILED!", dataLen);
161 
162     // write data bytes
163     stream_.write(reinterpret_cast<ConstCharPtr>(data), size);
164     CHECK_TRUE(stream_, 0, "binary file %s write raw buffer data failed!", path_.c_str());
165     CHECK_TRUE(helper_.AddSegment(reinterpret_cast<uint8_t*>(const_cast<void*>(data)), size),
166         0, "Add payload for data bytes %zu FAILED!", size);
167 
168     long nbytes = sizeof(dataLen) + size;
169     writeBytes_ += nbytes;
170     ++writeCount_;
171     return nbytes;
172 }
173 
IsSplitFile(uint32_t size)174 bool TraceFileWriter::IsSplitFile(uint32_t size)
175 {
176     dataSize_ += sizeof(uint32_t) + size;
177     if (dataSize_ >= splitFileMaxSize_) {
178         HILOG_INFO(LOG_CORE, "need to split the file(%s), data size:%d, size: %d, splitFileMaxSize_:%d",
179             path_.c_str(), dataSize_, size, splitFileMaxSize_);
180 
181         // update old file header
182         Finish();
183         if (stream_.is_open()) {
184             stream_.close();
185         }
186         fileNum_++;
187 
188         // write header of the new file
189         if (!WriteHeader()) {
190             return false;
191         }
192 
193         // write the plugin config of the new file
194         for (size_t i = 0; i < pluginConfigsData_.size(); i++) {
195             Write(pluginConfigsData_[i].data(), pluginConfigsData_[i].size());
196         }
197         Flush();
198         return true;
199     }
200     return false;
201 }
202 
Write(const MessageLite & message)203 long TraceFileWriter::Write(const MessageLite& message)
204 {
205     auto size = message.ByteSizeLong();
206     if (isSplitFile_ && !isStop_) {
207         if (IsSplitFile(size)) {
208             return -1;
209         }
210     }
211 
212     // serialize message to bytes array
213     std::vector<char> msgData(size);
214     CHECK_TRUE(message.SerializeToArray(msgData.data(), msgData.size()), 0, "SerializeToArray failed!");
215 
216     return Write(msgData.data(), msgData.size());
217 }
218 
Finish()219 bool TraceFileWriter::Finish()
220 {
221     // update header info
222     helper_.Update(header_);
223 
224     // move write position to begin of file
225     CHECK_TRUE(stream_.is_open(), false, "binary file %s not open or open failed!", path_.c_str());
226     stream_.seekp(0);
227     CHECK_TRUE(stream_, false, "seek write position to head for %s failed!", path_.c_str());
228 
229     SetTimeStamp(); // add timestamp in header
230 
231     // write final header
232     stream_.write(reinterpret_cast<CharPtr>(&header_), sizeof(header_));
233     CHECK_TRUE(stream_, false, "write final header to %s failed!", path_.c_str());
234     CHECK_TRUE(stream_.flush(), false, "binary file %s flush failed!", path_.c_str());
235     return true;
236 }
237 
Flush()238 bool TraceFileWriter::Flush()
239 {
240     return FlushStream();
241 }
242 
FlushStream()243 bool TraceFileWriter::FlushStream()
244 {
245     CHECK_TRUE(stream_.is_open(), false, "binary file %s not open or open failed!", path_.c_str());
246     CHECK_TRUE(stream_.flush(), false, "binary file %s flush failed!", path_.c_str());
247     HILOG_INFO(LOG_CORE, "flush: %s, bytes: %" PRIu64 ", count: %" PRIu64, path_.c_str(), writeBytes_, writeCount_);
248     return true;
249 }
250 
SetStopSplitFile(bool isStop)251 void TraceFileWriter::SetStopSplitFile(bool isStop)
252 {
253     isStop_ = isStop;
254 }
255 
LogDiskUsage()256 void TraceFileWriter::LogDiskUsage()
257 {
258     std::string diskPath = "/data/local/tmp/";
259     std::string::size_type pos = oldPath_.find_last_of('/');
260     if (pos != std::string::npos) {
261         diskPath = oldPath_.substr(0, pos);
262     }
263 
264     struct statvfs diskInfo;
265     int ret = statvfs(diskPath.c_str(), &diskInfo);
266     if (ret != 0) {
267         std::string errorMsg = COMMON::GetErrorMsg();
268         HILOG_ERROR(LOG_CORE, "LogDiskUsage() return %d, path:%s, msg:%s", ret, diskPath.c_str(), errorMsg.c_str());
269         return;
270     }
271 
272     unsigned long long freeSize = static_cast<unsigned long long>(diskInfo.f_bsize) *
273         static_cast<unsigned long long>(diskInfo.f_bfree);
274     unsigned long long totalSize = static_cast<unsigned long long>(diskInfo.f_bsize) *
275         static_cast<unsigned long long>(diskInfo.f_blocks);
276     float freePercent = static_cast<float>(freeSize) / static_cast<float>(totalSize);
277     uint32_t freeSizeGb = freeSize / GB_TO_BYTE;
278     // 100: in terms of percentage
279     HILOG_INFO(LOG_CORE, "LogDiskUsage() freePercent:%.1f, freeSizeGb:%u", freePercent * 100, freeSizeGb);
280 }