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 <cstdlib>
17#include <cstring>
18#include <cinttypes>
19#include <iostream>
20#include <string>
21#include <thread>
22#include <string_view>
23
24#include "log_kmsg.h"
25#include "flow_control.h"
26#include "log_domains.h"
27#include "log_collector.h"
28
29namespace OHOS {
30namespace HiviewDFX {
31using namespace std;
32
33void LogCollector::InsertDropInfo(const HilogMsg &msg, int droppedCount)
34{
35    string dropLog = to_string(droppedCount) + " line(s) dropped!";
36    constexpr auto tag = "LOGLIMITD"sv;
37    std::vector<char> buffer(sizeof(HilogMsg) + tag.size() + dropLog.size() + 1, '\0');
38    HilogMsg *dropMsg = reinterpret_cast<HilogMsg *>(buffer.data());
39    if (dropMsg != nullptr) {
40        dropMsg->len     = buffer.size();
41        dropMsg->version = msg.version;
42        dropMsg->type    = msg.type;
43        dropMsg->level   = msg.level;
44        dropMsg->tagLen = tag.size();
45        dropMsg->tv_sec  = msg.tv_sec;
46        dropMsg->tv_nsec = msg.tv_nsec;
47        dropMsg->mono_sec = msg.mono_sec;
48        dropMsg->pid     = msg.pid;
49        dropMsg->tid     = msg.tid;
50        dropMsg->domain  = msg.domain;
51
52        auto remainSize = buffer.size() - sizeof(HilogMsg);
53        if (memcpy_s(dropMsg->tag, remainSize, tag.data(), tag.size())) {
54            std::cerr << "Can't copy tag info of Drop Info message\n";
55        }
56
57        remainSize -= tag.size();
58        auto logTextPtr = dropMsg->tag + tag.size(); // log text is behind tag data
59        if (memcpy_s(logTextPtr, remainSize, dropLog.data(), dropLog.size() + 1)) {
60            std::cerr << "Can't copy log text info of Drop Info message\n";
61        }
62
63        InsertLogToBuffer(*dropMsg);
64    }
65}
66#ifndef __RECV_MSG_WITH_UCRED_
67void LogCollector::onDataRecv(std::vector<char>& data, int dataLen)
68#else
69void LogCollector::onDataRecv(const ucred& cred, std::vector<char>& data, int dataLen)
70#endif
71{
72    if (dataLen < sizeof(HilogMsg)) {
73        return;
74    }
75    HilogMsg& msg = *(reinterpret_cast<HilogMsg *>(data.data()));
76    if (dataLen != msg.len) {
77        return;
78    }
79    // check domain id
80    if (IsValidDomain(static_cast<LogType>(msg.type), msg.domain) == false) {
81        return;
82    }
83#ifdef __RECV_MSG_WITH_UCRED_
84    msg.pid = cred.pid;
85#endif
86    bool dropped = false;
87    // Domain flow control
88    do {
89        int ret = 0;
90        if (msg.type != static_cast<uint16_t>(LOG_APP) && flowControl && !debug) {
91            ret = FlowCtrlDomain(msg);
92        }
93        if (ret < 0) {
94            // dropping message
95            dropped = true;
96            break;
97        } else if (ret > 0) {
98            // >0 means a new statistic period start, "ret" is the number of dropping lines in last period
99            InsertDropInfo(msg, ret);
100        }
101        // If insert msg fail, return 0
102        if (InsertLogToBuffer(msg) == 0) {
103            return;
104        }
105    } while (0);
106
107    // Log statistics
108    if (countEnable) {
109        if (*(msg.tag + msg.tagLen - 1) != '\0') {
110            return;
111        }
112        StatsInfo info = {
113            .level = msg.level,
114            .type = msg.type,
115            .len = (msg.len - sizeof(HilogMsg) - 1 - 1), // don't count '\0' of tag and content
116            .dropped = dropped ? 1 : 0,
117            .domain = msg.domain,
118            .pid = msg.pid,
119            .tv_sec = msg.tv_sec,
120            .tv_nsec = msg.tv_nsec,
121            .mono_sec = msg.mono_sec,
122            .tag = msg.tag
123        };
124        m_hilogBuffer.CountLog(info);
125    }
126}
127
128size_t LogCollector::InsertLogToBuffer(const HilogMsg& msg)
129{
130    bool isFull = false;
131    return m_hilogBuffer.Insert(msg, isFull);
132}
133
134void LogCollector::SetLogFlowControl(bool on)
135{
136    flowControl = on;
137}
138
139void LogCollector::SetDebuggable(bool on)
140{
141    debug = on;
142}
143} // namespace HiviewDFX
144} // namespace OHOS
145