1049e185fSopenharmony_ci/*
2049e185fSopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd.
3049e185fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4049e185fSopenharmony_ci * you may not use this file except in compliance with the License.
5049e185fSopenharmony_ci * You may obtain a copy of the License at
6049e185fSopenharmony_ci *
7049e185fSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8049e185fSopenharmony_ci *
9049e185fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10049e185fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11049e185fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12049e185fSopenharmony_ci * See the License for the specific language governing permissions and
13049e185fSopenharmony_ci * limitations under the License.
14049e185fSopenharmony_ci */
15049e185fSopenharmony_ci
16049e185fSopenharmony_ci#include "dfx_log_dump.h"
17049e185fSopenharmony_ci#include <fstream>
18049e185fSopenharmony_ci#include <unistd.h>
19049e185fSopenharmony_ci#include <malloc.h>
20049e185fSopenharmony_ci#include <sys/time.h>
21049e185fSopenharmony_ci#include "securec.h"
22049e185fSopenharmony_ci
23049e185fSopenharmony_cinamespace {
24049e185fSopenharmony_ciconstexpr int32_t FILE_MAX = 100;
25049e185fSopenharmony_ciconstexpr int32_t FILE_LINE_MAX = 50000;
26049e185fSopenharmony_ci}
27049e185fSopenharmony_cinamespace OHOS {
28049e185fSopenharmony_cinamespace Media {
29049e185fSopenharmony_ciDfxLogDump &DfxLogDump::GetInstance()
30049e185fSopenharmony_ci{
31049e185fSopenharmony_ci    static DfxLogDump dfxLogDump;
32049e185fSopenharmony_ci    return dfxLogDump;
33049e185fSopenharmony_ci}
34049e185fSopenharmony_ci
35049e185fSopenharmony_ciDfxLogDump::DfxLogDump()
36049e185fSopenharmony_ci{
37049e185fSopenharmony_ci    thread_ = std::make_unique<std::thread>([this] () -> void { this->TaskProcessor(); });
38049e185fSopenharmony_ci}
39049e185fSopenharmony_ci
40049e185fSopenharmony_ciDfxLogDump::~DfxLogDump()
41049e185fSopenharmony_ci{
42049e185fSopenharmony_ci    {
43049e185fSopenharmony_ci        std::unique_lock<std::mutex> lock(mutex_);
44049e185fSopenharmony_ci        isExit_ = true;
45049e185fSopenharmony_ci        cond_.notify_all();
46049e185fSopenharmony_ci    }
47049e185fSopenharmony_ci    if (thread_ != nullptr && thread_->joinable()) {
48049e185fSopenharmony_ci        thread_->join();
49049e185fSopenharmony_ci    }
50049e185fSopenharmony_ci}
51049e185fSopenharmony_ci
52049e185fSopenharmony_cistatic void AddNewLog(const char *level, const OHOS::HiviewDFX::HiLogLabel &label, std::string &logStr)
53049e185fSopenharmony_ci{
54049e185fSopenharmony_ci    struct timeval time = {};
55049e185fSopenharmony_ci    (void)gettimeofday(&time, nullptr);
56049e185fSopenharmony_ci    int64_t second = time.tv_sec % 60;
57049e185fSopenharmony_ci    int64_t allMinute = time.tv_sec / 60;
58049e185fSopenharmony_ci    int64_t minute = allMinute % 60;
59049e185fSopenharmony_ci    int64_t hour = allMinute / 60 % 24;
60049e185fSopenharmony_ci    int64_t mSecond = time.tv_usec / 1000;
61049e185fSopenharmony_ci
62049e185fSopenharmony_ci    logStr += std::to_string(hour);
63049e185fSopenharmony_ci    logStr += ":";
64049e185fSopenharmony_ci    logStr += std::to_string(minute);
65049e185fSopenharmony_ci    logStr += ":";
66049e185fSopenharmony_ci    logStr += std::to_string(second);
67049e185fSopenharmony_ci    logStr += ":";
68049e185fSopenharmony_ci    logStr += std::to_string(mSecond);
69049e185fSopenharmony_ci    logStr += " ";
70049e185fSopenharmony_ci    logStr += level;
71049e185fSopenharmony_ci    logStr += " pid:";
72049e185fSopenharmony_ci    logStr += std::to_string(getpid());
73049e185fSopenharmony_ci    logStr += " tid:";
74049e185fSopenharmony_ci    logStr += std::to_string(gettid());
75049e185fSopenharmony_ci    logStr += " ";
76049e185fSopenharmony_ci    logStr += label.tag;
77049e185fSopenharmony_ci    logStr += ":";
78049e185fSopenharmony_ci}
79049e185fSopenharmony_ci
80049e185fSopenharmony_civoid DfxLogDump::SaveLog(const char *level, const OHOS::HiviewDFX::HiLogLabel &label, const char *fmt, ...)
81049e185fSopenharmony_ci{
82049e185fSopenharmony_ci    std::unique_lock<std::mutex> lock(mutex_);
83049e185fSopenharmony_ci    if (!isEnable_) {
84049e185fSopenharmony_ci        return;
85049e185fSopenharmony_ci    }
86049e185fSopenharmony_ci    std::string temp = "";
87049e185fSopenharmony_ci    std::string fmtStr = fmt;
88049e185fSopenharmony_ci    int32_t srcPos = 0;
89049e185fSopenharmony_ci    auto dtsPos = fmtStr.find("{public}", srcPos);
90049e185fSopenharmony_ci    const int32_t pubLen = 8;
91049e185fSopenharmony_ci    while (dtsPos != std::string::npos) {
92049e185fSopenharmony_ci        temp += fmtStr.substr(srcPos, dtsPos - srcPos);
93049e185fSopenharmony_ci        srcPos = static_cast<int32_t>(dtsPos) + pubLen;
94049e185fSopenharmony_ci        dtsPos = fmtStr.find("{public}", srcPos);
95049e185fSopenharmony_ci    }
96049e185fSopenharmony_ci    temp += fmtStr.substr(srcPos);
97049e185fSopenharmony_ci
98049e185fSopenharmony_ci    va_list ap;
99049e185fSopenharmony_ci    va_start(ap, fmt);
100049e185fSopenharmony_ci    constexpr uint32_t maxLogLen = 1024;
101049e185fSopenharmony_ci    char logBuf[maxLogLen];
102049e185fSopenharmony_ci    auto ret = vsnprintf_s(logBuf, maxLogLen, maxLogLen - 1, temp.c_str(), ap);
103049e185fSopenharmony_ci    va_end(ap);
104049e185fSopenharmony_ci
105049e185fSopenharmony_ci    AddNewLog(level, label, logString_);
106049e185fSopenharmony_ci    if (ret < 0) {
107049e185fSopenharmony_ci        logString_ += "dump log error";
108049e185fSopenharmony_ci    } else {
109049e185fSopenharmony_ci        logString_ += logBuf;
110049e185fSopenharmony_ci    }
111049e185fSopenharmony_ci    logString_ += "\n";
112049e185fSopenharmony_ci    lineCount_++;
113049e185fSopenharmony_ci    if (lineCount_ >= FILE_LINE_MAX) {
114049e185fSopenharmony_ci        cond_.notify_all();
115049e185fSopenharmony_ci    }
116049e185fSopenharmony_ci}
117049e185fSopenharmony_ci
118049e185fSopenharmony_civoid DfxLogDump::UpdateCheckEnable()
119049e185fSopenharmony_ci{
120049e185fSopenharmony_ci    std::string file = "/data/media/log/check.config";
121049e185fSopenharmony_ci    std::ofstream ofStream(file);
122049e185fSopenharmony_ci    if (!ofStream.is_open()) {
123049e185fSopenharmony_ci        isEnable_ = false;
124049e185fSopenharmony_ci        return;
125049e185fSopenharmony_ci    }
126049e185fSopenharmony_ci    ofStream.close();
127049e185fSopenharmony_ci    isEnable_ = true;
128049e185fSopenharmony_ci}
129049e185fSopenharmony_ci
130049e185fSopenharmony_civoid DfxLogDump::TaskProcessor()
131049e185fSopenharmony_ci{
132049e185fSopenharmony_ci    pthread_setname_np(pthread_self(), "DfxLogTask");
133049e185fSopenharmony_ci    (void)mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
134049e185fSopenharmony_ci    (void)mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
135049e185fSopenharmony_ci    while (true) {
136049e185fSopenharmony_ci        std::string temp;
137049e185fSopenharmony_ci        int32_t lineCount = 0;
138049e185fSopenharmony_ci        {
139049e185fSopenharmony_ci            std::unique_lock<std::mutex> lock(mutex_);
140049e185fSopenharmony_ci            if (isExit_) {
141049e185fSopenharmony_ci                return;
142049e185fSopenharmony_ci            }
143049e185fSopenharmony_ci            static constexpr int32_t timeout = 60; // every 1 minute have a log
144049e185fSopenharmony_ci            cond_.wait_for(lock, std::chrono::seconds(timeout),
145049e185fSopenharmony_ci                [this] {
146049e185fSopenharmony_ci                    UpdateCheckEnable();
147049e185fSopenharmony_ci                    return isExit_ || isDump_ || lineCount_ >= FILE_LINE_MAX || !logString_.empty();
148049e185fSopenharmony_ci            });
149049e185fSopenharmony_ci            isDump_ = false;
150049e185fSopenharmony_ci            lineCount = lineCount_;
151049e185fSopenharmony_ci            lineCount_ = lineCount_ >= FILE_LINE_MAX ? 0 : lineCount_;
152049e185fSopenharmony_ci            swap(logString_, temp);
153049e185fSopenharmony_ci        }
154049e185fSopenharmony_ci
155049e185fSopenharmony_ci        std::string file = "/data/media/log/";
156049e185fSopenharmony_ci        file += std::to_string(getpid());
157049e185fSopenharmony_ci        file += "_hilog_media.log";
158049e185fSopenharmony_ci        file += std::to_string(fileCount_);
159049e185fSopenharmony_ci        std::ofstream ofStream;
160049e185fSopenharmony_ci        if (isNewFile_) {
161049e185fSopenharmony_ci            ofStream.open(file, std::ios::out | std::ios::trunc);
162049e185fSopenharmony_ci        } else {
163049e185fSopenharmony_ci            ofStream.open(file, std::ios::out | std::ios::app);
164049e185fSopenharmony_ci        }
165049e185fSopenharmony_ci        if (!ofStream.is_open()) {
166049e185fSopenharmony_ci            continue;
167049e185fSopenharmony_ci        }
168049e185fSopenharmony_ci        isNewFile_ = false;
169049e185fSopenharmony_ci        if (lineCount >= FILE_LINE_MAX) {
170049e185fSopenharmony_ci            isNewFile_ = true;
171049e185fSopenharmony_ci            fileCount_++;
172049e185fSopenharmony_ci            fileCount_ = fileCount_ > FILE_MAX ? 0 : fileCount_;
173049e185fSopenharmony_ci        }
174049e185fSopenharmony_ci        ofStream.write(temp.c_str(), temp.size());
175049e185fSopenharmony_ci        ofStream.close();
176049e185fSopenharmony_ci    }
177049e185fSopenharmony_ci}
178049e185fSopenharmony_ci} // namespace Media
179049e185fSopenharmony_ci} // namespace OHOS