12498b56bSopenharmony_ci/*
22498b56bSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
32498b56bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
42498b56bSopenharmony_ci * you may not use this file except in compliance with the License.
52498b56bSopenharmony_ci * You may obtain a copy of the License at
62498b56bSopenharmony_ci *
72498b56bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
82498b56bSopenharmony_ci *
92498b56bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
102498b56bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
112498b56bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
122498b56bSopenharmony_ci * See the License for the specific language governing permissions and
132498b56bSopenharmony_ci * limitations under the License.
142498b56bSopenharmony_ci */
152498b56bSopenharmony_ci
162498b56bSopenharmony_ci#include <cstdlib>
172498b56bSopenharmony_ci#include <cstring>
182498b56bSopenharmony_ci#include <cinttypes>
192498b56bSopenharmony_ci#include <iostream>
202498b56bSopenharmony_ci#include <string>
212498b56bSopenharmony_ci#include <thread>
222498b56bSopenharmony_ci#include <string_view>
232498b56bSopenharmony_ci
242498b56bSopenharmony_ci#include "log_kmsg.h"
252498b56bSopenharmony_ci#include "flow_control.h"
262498b56bSopenharmony_ci#include "log_domains.h"
272498b56bSopenharmony_ci#include "log_collector.h"
282498b56bSopenharmony_ci
292498b56bSopenharmony_cinamespace OHOS {
302498b56bSopenharmony_cinamespace HiviewDFX {
312498b56bSopenharmony_ciusing namespace std;
322498b56bSopenharmony_ci
332498b56bSopenharmony_civoid LogCollector::InsertDropInfo(const HilogMsg &msg, int droppedCount)
342498b56bSopenharmony_ci{
352498b56bSopenharmony_ci    string dropLog = to_string(droppedCount) + " line(s) dropped!";
362498b56bSopenharmony_ci    constexpr auto tag = "LOGLIMITD"sv;
372498b56bSopenharmony_ci    std::vector<char> buffer(sizeof(HilogMsg) + tag.size() + dropLog.size() + 1, '\0');
382498b56bSopenharmony_ci    HilogMsg *dropMsg = reinterpret_cast<HilogMsg *>(buffer.data());
392498b56bSopenharmony_ci    if (dropMsg != nullptr) {
402498b56bSopenharmony_ci        dropMsg->len     = buffer.size();
412498b56bSopenharmony_ci        dropMsg->version = msg.version;
422498b56bSopenharmony_ci        dropMsg->type    = msg.type;
432498b56bSopenharmony_ci        dropMsg->level   = msg.level;
442498b56bSopenharmony_ci        dropMsg->tagLen = tag.size();
452498b56bSopenharmony_ci        dropMsg->tv_sec  = msg.tv_sec;
462498b56bSopenharmony_ci        dropMsg->tv_nsec = msg.tv_nsec;
472498b56bSopenharmony_ci        dropMsg->mono_sec = msg.mono_sec;
482498b56bSopenharmony_ci        dropMsg->pid     = msg.pid;
492498b56bSopenharmony_ci        dropMsg->tid     = msg.tid;
502498b56bSopenharmony_ci        dropMsg->domain  = msg.domain;
512498b56bSopenharmony_ci
522498b56bSopenharmony_ci        auto remainSize = buffer.size() - sizeof(HilogMsg);
532498b56bSopenharmony_ci        if (memcpy_s(dropMsg->tag, remainSize, tag.data(), tag.size())) {
542498b56bSopenharmony_ci            std::cerr << "Can't copy tag info of Drop Info message\n";
552498b56bSopenharmony_ci        }
562498b56bSopenharmony_ci
572498b56bSopenharmony_ci        remainSize -= tag.size();
582498b56bSopenharmony_ci        auto logTextPtr = dropMsg->tag + tag.size(); // log text is behind tag data
592498b56bSopenharmony_ci        if (memcpy_s(logTextPtr, remainSize, dropLog.data(), dropLog.size() + 1)) {
602498b56bSopenharmony_ci            std::cerr << "Can't copy log text info of Drop Info message\n";
612498b56bSopenharmony_ci        }
622498b56bSopenharmony_ci
632498b56bSopenharmony_ci        InsertLogToBuffer(*dropMsg);
642498b56bSopenharmony_ci    }
652498b56bSopenharmony_ci}
662498b56bSopenharmony_ci#ifndef __RECV_MSG_WITH_UCRED_
672498b56bSopenharmony_civoid LogCollector::onDataRecv(std::vector<char>& data, int dataLen)
682498b56bSopenharmony_ci#else
692498b56bSopenharmony_civoid LogCollector::onDataRecv(const ucred& cred, std::vector<char>& data, int dataLen)
702498b56bSopenharmony_ci#endif
712498b56bSopenharmony_ci{
722498b56bSopenharmony_ci    if (dataLen < sizeof(HilogMsg)) {
732498b56bSopenharmony_ci        return;
742498b56bSopenharmony_ci    }
752498b56bSopenharmony_ci    HilogMsg& msg = *(reinterpret_cast<HilogMsg *>(data.data()));
762498b56bSopenharmony_ci    if (dataLen != msg.len) {
772498b56bSopenharmony_ci        return;
782498b56bSopenharmony_ci    }
792498b56bSopenharmony_ci    // check domain id
802498b56bSopenharmony_ci    if (IsValidDomain(static_cast<LogType>(msg.type), msg.domain) == false) {
812498b56bSopenharmony_ci        return;
822498b56bSopenharmony_ci    }
832498b56bSopenharmony_ci#ifdef __RECV_MSG_WITH_UCRED_
842498b56bSopenharmony_ci    msg.pid = cred.pid;
852498b56bSopenharmony_ci#endif
862498b56bSopenharmony_ci    bool dropped = false;
872498b56bSopenharmony_ci    // Domain flow control
882498b56bSopenharmony_ci    do {
892498b56bSopenharmony_ci        int ret = 0;
902498b56bSopenharmony_ci        if (msg.type != static_cast<uint16_t>(LOG_APP) && flowControl && !debug) {
912498b56bSopenharmony_ci            ret = FlowCtrlDomain(msg);
922498b56bSopenharmony_ci        }
932498b56bSopenharmony_ci        if (ret < 0) {
942498b56bSopenharmony_ci            // dropping message
952498b56bSopenharmony_ci            dropped = true;
962498b56bSopenharmony_ci            break;
972498b56bSopenharmony_ci        } else if (ret > 0) {
982498b56bSopenharmony_ci            // >0 means a new statistic period start, "ret" is the number of dropping lines in last period
992498b56bSopenharmony_ci            InsertDropInfo(msg, ret);
1002498b56bSopenharmony_ci        }
1012498b56bSopenharmony_ci        // If insert msg fail, return 0
1022498b56bSopenharmony_ci        if (InsertLogToBuffer(msg) == 0) {
1032498b56bSopenharmony_ci            return;
1042498b56bSopenharmony_ci        }
1052498b56bSopenharmony_ci    } while (0);
1062498b56bSopenharmony_ci
1072498b56bSopenharmony_ci    // Log statistics
1082498b56bSopenharmony_ci    if (countEnable) {
1092498b56bSopenharmony_ci        if (*(msg.tag + msg.tagLen - 1) != '\0') {
1102498b56bSopenharmony_ci            return;
1112498b56bSopenharmony_ci        }
1122498b56bSopenharmony_ci        StatsInfo info = {
1132498b56bSopenharmony_ci            .level = msg.level,
1142498b56bSopenharmony_ci            .type = msg.type,
1152498b56bSopenharmony_ci            .len = (msg.len - sizeof(HilogMsg) - 1 - 1), // don't count '\0' of tag and content
1162498b56bSopenharmony_ci            .dropped = dropped ? 1 : 0,
1172498b56bSopenharmony_ci            .domain = msg.domain,
1182498b56bSopenharmony_ci            .pid = msg.pid,
1192498b56bSopenharmony_ci            .tv_sec = msg.tv_sec,
1202498b56bSopenharmony_ci            .tv_nsec = msg.tv_nsec,
1212498b56bSopenharmony_ci            .mono_sec = msg.mono_sec,
1222498b56bSopenharmony_ci            .tag = msg.tag
1232498b56bSopenharmony_ci        };
1242498b56bSopenharmony_ci        m_hilogBuffer.CountLog(info);
1252498b56bSopenharmony_ci    }
1262498b56bSopenharmony_ci}
1272498b56bSopenharmony_ci
1282498b56bSopenharmony_cisize_t LogCollector::InsertLogToBuffer(const HilogMsg& msg)
1292498b56bSopenharmony_ci{
1302498b56bSopenharmony_ci    bool isFull = false;
1312498b56bSopenharmony_ci    return m_hilogBuffer.Insert(msg, isFull);
1322498b56bSopenharmony_ci}
1332498b56bSopenharmony_ci
1342498b56bSopenharmony_civoid LogCollector::SetLogFlowControl(bool on)
1352498b56bSopenharmony_ci{
1362498b56bSopenharmony_ci    flowControl = on;
1372498b56bSopenharmony_ci}
1382498b56bSopenharmony_ci
1392498b56bSopenharmony_civoid LogCollector::SetDebuggable(bool on)
1402498b56bSopenharmony_ci{
1412498b56bSopenharmony_ci    debug = on;
1422498b56bSopenharmony_ci}
1432498b56bSopenharmony_ci} // namespace HiviewDFX
1442498b56bSopenharmony_ci} // namespace OHOS
145