1/*
2 * Copyright (c) 2024 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 "log/logger_output.h"
17
18#include <chrono>
19#include <ctime>
20#include <fstream>
21#include <iomanip>
22#include <string_view>
23
24#include <base/containers/string_view.h>
25#include <base/namespace.h>
26#include <core/namespace.h>
27
28#include "log/logger.h"
29
30namespace LoggerUtils {
31BASE_NS::string_view GetFilename(BASE_NS::string_view path)
32{
33    if (auto const pos = path.find_last_of("\\/"); pos != BASE_NS::string_view::npos) {
34        return path.substr(pos + 1);
35    }
36    return path;
37}
38
39void PrintTimeStamp(std::ostream& outputStream)
40{
41    const auto now = std::chrono::system_clock::now();
42    const auto time = std::chrono::system_clock::to_time_t(now);
43    const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) -
44                    std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
45
46    outputStream << std::put_time(std::localtime(&time), "%D %H:%M:%S.");
47    outputStream << std::right << std::setfill('0') << std::setw(3) // 3: alignment
48                 << ms.count() << std::setfill(' ');
49}
50} // namespace LoggerUtils
51
52CORE_BEGIN_NAMESPACE()
53using BASE_NS::string_view;
54
55class FileOutput final : public ILogger::IOutput {
56public:
57    explicit FileOutput(const string_view filePath) : IOutput(), outputStream_(filePath.data(), std::ios::app) {}
58
59    void Write(
60        ILogger::LogLevel logLevel, const string_view filename, int linenumber, const string_view message) override
61    {
62        if (outputStream_.is_open()) {
63            auto& outputStream = outputStream_;
64
65            LoggerUtils::PrintTimeStamp(outputStream);
66            const auto levelString = Logger::GetLogLevelName(logLevel, true);
67            outputStream << ' ' << std::string_view(levelString.data(), levelString.size());
68
69            if (!filename.empty()) {
70                outputStream << " (" << std::string_view(filename.data(), filename.size()) << ':' << linenumber
71                             << "): ";
72            } else {
73                outputStream << ": ";
74            }
75
76            outputStream << std::string_view(message.data(), message.size()) << std::endl;
77        }
78    }
79
80protected:
81    void Destroy() override
82    {
83        delete this;
84    }
85
86private:
87    std::ofstream outputStream_;
88};
89
90ILogger::IOutput::Ptr CreateLoggerFileOutput(const string_view filename)
91{
92    return ILogger::IOutput::Ptr { new FileOutput(filename) };
93}
94CORE_END_NAMESPACE()
95