1/*
2 * Copyright (c) 2021-2022 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 "base/log/dump_log.h"
17
18#include <fstream>
19#include "core/common/ace_application_info.h"
20
21namespace OHOS::Ace {
22
23DumpLog::DumpLog() = default;
24DumpLog::~DumpLog() = default;
25
26void DumpLog::Print(int32_t depth, const std::string& className, int32_t childSize)
27{
28    if (!ostream_ || !ostream_->good()) {
29        return;
30    }
31    std::string space = "  ";
32    for (int32_t i = 0; i < depth; ++i) {
33        ostream_->write(space.c_str(), space.length());
34    }
35    ostream_->write(space.c_str(), space.length());
36    std::string data = "|-> ";
37    data.append(className);
38    data.append(" childSize:" + std::to_string(childSize));
39    data.append("\n");
40    ostream_->write(data.c_str(), data.length());
41    for (auto& desc : description_) {
42        for (int32_t i = 0; i < depth; ++i) {
43            ostream_->write(space.c_str(), space.length());
44        }
45        std::string data = "";
46        if (childSize == 0) {
47            data = "      ";
48        } else {
49            data = "    | ";
50        }
51        data.append(desc);
52        ostream_->write(data.c_str(), data.length());
53    }
54    ostream_->flush();
55    description_.clear();
56    description_.shrink_to_fit();
57}
58
59void DumpLog::Print(const std::string& content)
60{
61    Print(0, content);
62}
63
64void DumpLog::Print(int32_t depth, const std::string& content)
65{
66    std::string space = " ";
67    for (int32_t i = 0; i < depth; ++i) {
68        ostream_->write(space.c_str(), space.length());
69    }
70    std::string data = content + separator_;
71    ostream_->write(data.c_str(), data.length());
72}
73
74void DumpLog::Reset()
75{
76    ostream_.reset();
77}
78
79void DumpLog::ShowDumpHelp(std::vector<std::string>& info)
80{
81    info.emplace_back(" -element                       |show element tree");
82    info.emplace_back(" -render                        |show render tree");
83    info.emplace_back(" -inspector                     |show inspector tree");
84    info.emplace_back(" -frontend                      |show path and components count of current page");
85    info.emplace_back(" -navigation                    |show navigation path stack");
86}
87
88void DumpLog::Append(int32_t depth, const std::string& className, int32_t childSize)
89{
90    for (int32_t i = 0; i < depth; ++i) {
91        result_.append("  ");
92    }
93    result_.append("|-> ");
94    result_.append(className);
95    result_.append(" childSize:" + std::to_string(childSize));
96    result_.append("\n");
97    for (auto& desc : description_) {
98        for (int32_t i = 0; i < depth; ++i) {
99            result_.append("  ");
100        }
101        if (childSize == 0) {
102            result_.append("      ");
103        } else {
104            result_.append("    | ");
105        }
106        result_.append(desc);
107    }
108    description_.clear();
109    description_.shrink_to_fit();
110}
111
112bool DumpLog::OutPutBySize()
113{
114    if (!ostream_->good()) {
115        result_.clear();
116        return false;
117    }
118    // if current result size > max size, dump will output as file
119    if (result_.size() + 1 > DumpLog::MAX_DUMP_LENGTH) {
120        auto dumpFilePath = AceApplicationInfo::GetInstance().GetDataFileDirPath() + "/arkui.dump";
121        std::unique_ptr<std::ostream> ostream = std::make_unique<std::ofstream>(dumpFilePath);
122        if (!ostream) {
123            result_.clear();
124            result_.append("Dump output failed,please try again");
125            ostream_->write(result_.c_str(), result_.length());
126            result_.clear();
127        }
128        CHECK_NULL_RETURN(ostream, false);
129        DumpLog::GetInstance().SetDumpFile(std::move(ostream));
130    }
131    ostream_->write(result_.c_str(), result_.length());
132    result_.clear();
133    ostream_->flush();
134    return true;
135}
136
137void DumpLog::OutPutDefault()
138{
139    if (!ostream_ || !ostream_->good()) {
140        result_.clear();
141        return;
142    }
143    ostream_->write(result_.c_str(), result_.length());
144    result_.clear();
145    ostream_->flush();
146}
147
148void DumpLog::PrintJson(const std::string& content)
149{
150    if (!ostream_->good()) {
151        return;
152    }
153    ostream_->write(content.c_str(), content.length());
154    ostream_->flush();
155}
156
157void DumpLog::PrintEndDumpInfoNG(bool isElement)
158{
159    int32_t depth = GetDepth() + DumpLog::END_POS_TWO;
160    std::string result;
161    for (int32_t i = 0; i < depth; ++i) {
162        result.append("}");
163    }
164    if (isElement) {
165        Append(result);
166    } else {
167        PrintJson(result);
168    }
169}
170
171std::string DumpLog::GetPrefix(int32_t depth)
172{
173    std::string prefix = "";
174    if (depth > 0) {
175        int32_t lastDepth = GetDepth();
176        if (depth == lastDepth) {
177            prefix.append("},");
178        } else if (depth > lastDepth) {
179            prefix = ",";
180        } else {
181            int32_t diff = lastDepth - depth + 1;
182            prefix.assign(diff, '}').append(",");
183        }
184    }
185    SetDepth(depth);
186    return prefix;
187}
188
189std::string DumpLog::FormatDumpInfo(const std::string& str, int32_t depth)
190{
191    if (str.length() > DumpLog::MIN_JSON_LENGTH) {
192        if (depth == 0) {
193            return str.substr(0, str.length() - DumpLog::END_POS_TWO);
194        }
195        return str.substr(1, str.length() - DumpLog::END_POS_THREE);
196    }
197    return str;
198}
199} // namespace OHOS::Ace
200