1/*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
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 <cstdio>
17#include <ctime>
18#include <sstream>
19
20#include <sys/time.h>
21
22
23#include "libbpf_logger.h"
24#include "hhlog.h"
25
26static constexpr int FILE_MODE = 0644;
27
28std::unique_ptr<LIBBPFLogger> LIBBPFLogger::MakeUnique(const std::string& logFile, int logLevel)
29{
30    std::unique_ptr<LIBBPFLogger> logger {new(std::nothrow) LIBBPFLogger {logLevel}};
31    if (logger == nullptr) {
32        return nullptr;
33    }
34#if defined(BPF_LOGGER_DEBUG) || defined(BPF_LOGGER_INFO) || defined(BPF_LOGGER_WARN) ||   \
35    defined(BPF_LOGGER_ERROR) || defined(BPF_LOGGER_FATAL)
36    if (logger->OpenLogFile(logFile) != 0) {
37        return nullptr;
38    }
39#endif
40    return logger;
41}
42
43int LIBBPFLogger::Printf(int logLevel, const char* format, va_list args)
44{
45    HHLOGI(true, "current libbpf log level = %d, target level = %d", logLevel, logLevel_);
46    if (logLevel > logLevel_) {
47        return 0;
48    }
49#if defined(BPF_LOGGER_DEBUG) || defined(BPF_LOGGER_INFO) || defined(BPF_LOGGER_WARN) ||   \
50    defined(BPF_LOGGER_ERROR) || defined(BPF_LOGGER_FATAL)
51    return vdprintf(fd_, format, args);
52#else
53    return 0;
54#endif
55}
56
57int LIBBPFLogger::OpenLogFile(const std::string& logFile)
58{
59    if (logFile.compare("stdout") == 0) {
60        if (fcntl(STDOUT_FILENO, F_GETFL)) {
61            fd_ = open("/dev/stdout", O_WRONLY);
62        } else {
63            fd_ = STDOUT_FILENO;
64        }
65        if (fd_ < 0) {
66            return -1;
67        }
68        return 0;
69    }
70    auto fileName = GetLogFileName();
71    if (fileName.length() == 0) {
72        return -1;
73    }
74    fileName = "/data/local/tmp/" + fileName;
75    fd_ = open(fileName.c_str(), O_WRONLY | O_CREAT, FILE_MODE);
76    if (fd_ < 0) {
77        return -1;
78    }
79    unlink(logFile.c_str());
80    if (link(fileName.c_str(), logFile.c_str()) != 0) {
81        return -1;
82    }
83
84    return 0;
85}
86
87std::string LIBBPFLogger::GetLogFileName() const
88{
89    struct timeval timer;
90    gettimeofday(&timer, nullptr);
91    time_t now = (time_t) timer.tv_sec;
92    struct tm* tmPtr {nullptr};
93    tmPtr = localtime(&now);
94    CHECK_NOTNULL(tmPtr, "", "GetLogFileName fail");
95    std::stringstream ss;
96    constexpr int yearStart {1900};
97    constexpr int monthStart {1};
98    ss << std::to_string(tmPtr->tm_year + yearStart) << ".";
99    ss << std::to_string(tmPtr->tm_mon + monthStart) << ".";
100    ss << std::to_string(tmPtr->tm_mday) << "_";
101    ss << std::to_string(tmPtr->tm_hour) << ".";
102    ss << std::to_string(tmPtr->tm_min) << ".";
103    ss << std::to_string(tmPtr->tm_sec) << ".libbpf.log";
104    return ss.str();
105}