1b1994897Sopenharmony_ci/**
2b1994897Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License.
5b1994897Sopenharmony_ci * You may obtain a copy of the License at
6b1994897Sopenharmony_ci *
7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8b1994897Sopenharmony_ci *
9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and
13b1994897Sopenharmony_ci * limitations under the License.
14b1994897Sopenharmony_ci */
15b1994897Sopenharmony_ci
16b1994897Sopenharmony_ci#include "logger.h"
17b1994897Sopenharmony_ci#include "os/filesystem.h"
18b1994897Sopenharmony_ci#include "os/thread.h"
19b1994897Sopenharmony_ci#include "string_helpers.h"
20b1994897Sopenharmony_ci#include "generated/base_options.h"
21b1994897Sopenharmony_ci
22b1994897Sopenharmony_ci#include <cstdarg>
23b1994897Sopenharmony_ci#include <cstdlib>
24b1994897Sopenharmony_ci#include <cstring>
25b1994897Sopenharmony_ci
26b1994897Sopenharmony_ci#include <fstream>
27b1994897Sopenharmony_ci#include <iostream>
28b1994897Sopenharmony_ci#include <string_view>
29b1994897Sopenharmony_ci
30b1994897Sopenharmony_cinamespace panda {
31b1994897Sopenharmony_ci
32b1994897Sopenharmony_ciLogger *Logger::logger = nullptr;
33b1994897Sopenharmony_cithread_local int Logger::nesting = 0;
34b1994897Sopenharmony_ci
35b1994897Sopenharmony_ci#include <logger_impl_gen.inc>
36b1994897Sopenharmony_ci
37b1994897Sopenharmony_civoid Logger::Initialize(const base_options::Options &options)
38b1994897Sopenharmony_ci{
39b1994897Sopenharmony_ci    panda::Logger::ComponentMask component_mask;
40b1994897Sopenharmony_ci    auto load_components = [&component_mask](auto components) {
41b1994897Sopenharmony_ci        for (const auto &s : components) {
42b1994897Sopenharmony_ci            component_mask |= Logger::ComponentMaskFromString(s);
43b1994897Sopenharmony_ci        }
44b1994897Sopenharmony_ci    };
45b1994897Sopenharmony_ci    Level level = Level::LAST;
46b1994897Sopenharmony_ci
47b1994897Sopenharmony_ci    if (options.WasSetLogFatal()) {
48b1994897Sopenharmony_ci        ASSERT_PRINT(level == Level::LAST, "There are conflicting logger options");
49b1994897Sopenharmony_ci        load_components(options.GetLogFatal());
50b1994897Sopenharmony_ci        level = Level::FATAL;
51b1994897Sopenharmony_ci    } else if (options.WasSetLogError()) {
52b1994897Sopenharmony_ci        ASSERT_PRINT(level == Level::LAST, "There are conflicting logger options");
53b1994897Sopenharmony_ci        load_components(options.GetLogError());
54b1994897Sopenharmony_ci        level = Level::ERROR;
55b1994897Sopenharmony_ci    } else if (options.WasSetLogWarning()) {
56b1994897Sopenharmony_ci        ASSERT_PRINT(level == Level::LAST, "There are conflicting logger options");
57b1994897Sopenharmony_ci        load_components(options.GetLogWarning());
58b1994897Sopenharmony_ci        level = Level::WARNING;
59b1994897Sopenharmony_ci    } else if (options.WasSetLogInfo()) {
60b1994897Sopenharmony_ci        ASSERT_PRINT(level == Level::LAST, "There are conflicting logger options");
61b1994897Sopenharmony_ci        load_components(options.GetLogInfo());
62b1994897Sopenharmony_ci        level = Level::INFO;
63b1994897Sopenharmony_ci    } else if (options.WasSetLogDebug()) {
64b1994897Sopenharmony_ci        ASSERT_PRINT(level == Level::LAST, "There are conflicting logger options");
65b1994897Sopenharmony_ci        load_components(options.GetLogDebug());
66b1994897Sopenharmony_ci        level = Level::DEBUG;
67b1994897Sopenharmony_ci    } else {
68b1994897Sopenharmony_ci        ASSERT_PRINT(level == Level::LAST, "There are conflicting logger options");
69b1994897Sopenharmony_ci        load_components(options.GetLogComponents());
70b1994897Sopenharmony_ci        level = Logger::LevelFromString(options.GetLogLevel());
71b1994897Sopenharmony_ci    }
72b1994897Sopenharmony_ci
73b1994897Sopenharmony_ci#ifdef ENABLE_HILOG
74b1994897Sopenharmony_ci    Logger::InitializeHiLogging(level, component_mask);
75b1994897Sopenharmony_ci    return;
76b1994897Sopenharmony_ci#endif
77b1994897Sopenharmony_ci
78b1994897Sopenharmony_ci    if (options.GetLogStream() == "std") {
79b1994897Sopenharmony_ci        Logger::InitializeStdLogging(level, component_mask);
80b1994897Sopenharmony_ci    } else if (options.GetLogStream() == "file" || options.GetLogStream() == "fast-file") {
81b1994897Sopenharmony_ci        const std::string &file_name = options.GetLogFile();
82b1994897Sopenharmony_ci        Logger::InitializeFileLogging(file_name, level, component_mask, options.GetLogStream() == "fast-file");
83b1994897Sopenharmony_ci    } else if (options.GetLogStream() == "dummy") {
84b1994897Sopenharmony_ci        Logger::InitializeDummyLogging(level, component_mask);
85b1994897Sopenharmony_ci    } else {
86b1994897Sopenharmony_ci        UNREACHABLE();
87b1994897Sopenharmony_ci    }
88b1994897Sopenharmony_ci}
89b1994897Sopenharmony_ci
90b1994897Sopenharmony_ci#ifndef NDEBUG
91b1994897Sopenharmony_ci/**
92b1994897Sopenharmony_ci * In debug builds this function allowes or disallowes proceeding with actual logging (i.e. creating Message{})
93b1994897Sopenharmony_ci */
94b1994897Sopenharmony_ci/* static */
95b1994897Sopenharmony_cibool Logger::IsMessageSuppressed([[maybe_unused]] Level level, [[maybe_unused]] Component component)
96b1994897Sopenharmony_ci{
97b1994897Sopenharmony_ci    // Allowing only to log if it's not a nested log, or it's nested and it's severity is suitable
98b1994897Sopenharmony_ci    return level >= Logger::logger->nested_allowed_level_ && nesting > 0;
99b1994897Sopenharmony_ci}
100b1994897Sopenharmony_ci
101b1994897Sopenharmony_ci/**
102b1994897Sopenharmony_ci * Increases log nesting (i.e. depth, or how many instances of Message{} is active atm) in a given thread
103b1994897Sopenharmony_ci */
104b1994897Sopenharmony_ci/* static */
105b1994897Sopenharmony_civoid Logger::LogNestingInc()
106b1994897Sopenharmony_ci{
107b1994897Sopenharmony_ci    nesting++;
108b1994897Sopenharmony_ci}
109b1994897Sopenharmony_ci
110b1994897Sopenharmony_ci/**
111b1994897Sopenharmony_ci * Decreases log nesting (i.e. depth, or how many instances of Message{} is active atm) in a given thread
112b1994897Sopenharmony_ci */
113b1994897Sopenharmony_ci/* static */
114b1994897Sopenharmony_civoid Logger::LogNestingDec()
115b1994897Sopenharmony_ci{
116b1994897Sopenharmony_ci    nesting--;
117b1994897Sopenharmony_ci}
118b1994897Sopenharmony_ci#endif  // NDEBUG
119b1994897Sopenharmony_ci
120b1994897Sopenharmony_ciauto Logger::Buffer::printf(const char *format, ...) -> Buffer &
121b1994897Sopenharmony_ci{
122b1994897Sopenharmony_ci    va_list args;
123b1994897Sopenharmony_ci    va_start(args, format);  // NOLINT(cppcoreguidelines-pro-type-vararg)
124b1994897Sopenharmony_ci
125b1994897Sopenharmony_ci    [[maybe_unused]] int put = vsnprintf_s(this->data(), this->size(), this->size() - 1, format, args);
126b1994897Sopenharmony_ci    ASSERT(put >= 0 && static_cast<size_t>(put) < BUFFER_SIZE);
127b1994897Sopenharmony_ci
128b1994897Sopenharmony_ci    va_end(args);
129b1994897Sopenharmony_ci    return *this;
130b1994897Sopenharmony_ci}
131b1994897Sopenharmony_ci
132b1994897Sopenharmony_cios::memory::Mutex Logger::mutex;  // NOLINT(fuchsia-statically-constructed-objects)
133b1994897Sopenharmony_ciFUNC_MOBILE_LOG_PRINT mlog_buf_print = nullptr;
134b1994897Sopenharmony_ci
135b1994897Sopenharmony_ciLogger::Message::~Message()
136b1994897Sopenharmony_ci{
137b1994897Sopenharmony_ci    if (print_system_error_) {
138b1994897Sopenharmony_ci        stream_ << ": " << os::Error(errno).ToString();
139b1994897Sopenharmony_ci    }
140b1994897Sopenharmony_ci
141b1994897Sopenharmony_ci    Logger::Log(level_, component_, stream_.str());
142b1994897Sopenharmony_ci#ifndef NDEBUG
143b1994897Sopenharmony_ci    panda::Logger::LogNestingDec();
144b1994897Sopenharmony_ci#endif
145b1994897Sopenharmony_ci
146b1994897Sopenharmony_ci    if (level_ == Level::FATAL) {
147b1994897Sopenharmony_ci        std::cerr << "FATAL ERROR" << std::endl;
148b1994897Sopenharmony_ci        std::cerr << "Backtrace [tid=" << os::thread::GetCurrentThreadId() << "]:\n";
149b1994897Sopenharmony_ci        PrintStack(std::cerr);
150b1994897Sopenharmony_ci        std::abort();
151b1994897Sopenharmony_ci    }
152b1994897Sopenharmony_ci}
153b1994897Sopenharmony_ci
154b1994897Sopenharmony_ci/* static */
155b1994897Sopenharmony_civoid Logger::Log(Level level, Component component, const std::string &str)
156b1994897Sopenharmony_ci{
157b1994897Sopenharmony_ci    if (!IsLoggingOn(level, component)) {
158b1994897Sopenharmony_ci        return;
159b1994897Sopenharmony_ci    }
160b1994897Sopenharmony_ci
161b1994897Sopenharmony_ci    os::memory::LockHolder<os::memory::Mutex> lock(mutex);
162b1994897Sopenharmony_ci    if (!IsLoggingOn(level, component)) {
163b1994897Sopenharmony_ci        return;
164b1994897Sopenharmony_ci    }
165b1994897Sopenharmony_ci
166b1994897Sopenharmony_ci    size_t nl = str.find('\n');
167b1994897Sopenharmony_ci    if (nl == std::string::npos) {
168b1994897Sopenharmony_ci        logger->LogLineInternal(level, component, str);
169b1994897Sopenharmony_ci        logger->WriteMobileLog(level, GetComponentTag(component), str.c_str());
170b1994897Sopenharmony_ci    } else {
171b1994897Sopenharmony_ci        size_t i = 0;
172b1994897Sopenharmony_ci        while (nl != std::string::npos) {
173b1994897Sopenharmony_ci            std::string line = str.substr(i, nl - i);
174b1994897Sopenharmony_ci            logger->LogLineInternal(level, component, line);
175b1994897Sopenharmony_ci            logger->WriteMobileLog(level, GetComponentTag(component), line.c_str());
176b1994897Sopenharmony_ci            i = nl + 1;
177b1994897Sopenharmony_ci            nl = str.find('\n', i);
178b1994897Sopenharmony_ci        }
179b1994897Sopenharmony_ci
180b1994897Sopenharmony_ci        logger->LogLineInternal(level, component, str.substr(i));
181b1994897Sopenharmony_ci        logger->WriteMobileLog(level, GetComponentTag(component), str.substr(i).c_str());
182b1994897Sopenharmony_ci    }
183b1994897Sopenharmony_ci}
184b1994897Sopenharmony_ci
185b1994897Sopenharmony_ci/* static */
186b1994897Sopenharmony_cistd::string GetPrefix(Logger::Level level, Logger::Component component)
187b1994897Sopenharmony_ci{
188b1994897Sopenharmony_ci    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
189b1994897Sopenharmony_ci    return helpers::string::Format("[TID %06x] %s/%s: ", os::thread::GetCurrentThreadId(), GetLevelTag(level),
190b1994897Sopenharmony_ci                                   GetComponentTag(component));
191b1994897Sopenharmony_ci}
192b1994897Sopenharmony_ci
193b1994897Sopenharmony_ci/* static */
194b1994897Sopenharmony_civoid Logger::InitializeFileLogging(const std::string &log_file, Level level, const ComponentMask &component_mask,
195b1994897Sopenharmony_ci                                   bool is_fast_logging)
196b1994897Sopenharmony_ci{
197b1994897Sopenharmony_ci    if (IsInitialized()) {
198b1994897Sopenharmony_ci        return;
199b1994897Sopenharmony_ci    }
200b1994897Sopenharmony_ci
201b1994897Sopenharmony_ci    os::memory::LockHolder<os::memory::Mutex> lock(mutex);
202b1994897Sopenharmony_ci
203b1994897Sopenharmony_ci    if (IsInitialized()) {
204b1994897Sopenharmony_ci        return;
205b1994897Sopenharmony_ci    }
206b1994897Sopenharmony_ci
207b1994897Sopenharmony_ci    auto path = os::GetAbsolutePath(log_file);
208b1994897Sopenharmony_ci    if (path == "") {
209b1994897Sopenharmony_ci        logger = new StderrLogger(level, component_mask);
210b1994897Sopenharmony_ci        std::string msg = helpers::string::Format("Fallback to stderr logging: resolve file path error");
211b1994897Sopenharmony_ci        logger->LogLineInternal(Level::ERROR, Component::COMMON, msg);
212b1994897Sopenharmony_ci        return;
213b1994897Sopenharmony_ci    }
214b1994897Sopenharmony_ci
215b1994897Sopenharmony_ci    std::ofstream stream(path);
216b1994897Sopenharmony_ci    if (stream) {
217b1994897Sopenharmony_ci        if (is_fast_logging) {
218b1994897Sopenharmony_ci            logger = new FastFileLogger(std::move(stream), level, component_mask);
219b1994897Sopenharmony_ci        } else {
220b1994897Sopenharmony_ci            logger = new FileLogger(std::move(stream), level, component_mask);
221b1994897Sopenharmony_ci        }
222b1994897Sopenharmony_ci    } else {
223b1994897Sopenharmony_ci        logger = new StderrLogger(level, component_mask);
224b1994897Sopenharmony_ci        // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
225b1994897Sopenharmony_ci        std::string msg = helpers::string::Format("Fallback to stderr logging: cannot open log file '%s': %s",
226b1994897Sopenharmony_ci                                                  log_file.c_str(), os::Error(errno).ToString().c_str());
227b1994897Sopenharmony_ci        logger->LogLineInternal(Level::ERROR, Component::COMMON, msg);
228b1994897Sopenharmony_ci    }
229b1994897Sopenharmony_ci}
230b1994897Sopenharmony_ci
231b1994897Sopenharmony_ci#ifdef ENABLE_HILOG
232b1994897Sopenharmony_ci/* static */
233b1994897Sopenharmony_civoid Logger::InitializeHiLogging(Level level, const ComponentMask &component_mask)
234b1994897Sopenharmony_ci{
235b1994897Sopenharmony_ci    if (IsInitialized()) {
236b1994897Sopenharmony_ci        return;
237b1994897Sopenharmony_ci    }
238b1994897Sopenharmony_ci
239b1994897Sopenharmony_ci    {
240b1994897Sopenharmony_ci        os::memory::LockHolder<os::memory::Mutex> lock(mutex);
241b1994897Sopenharmony_ci
242b1994897Sopenharmony_ci        if (IsInitialized()) {
243b1994897Sopenharmony_ci            return;
244b1994897Sopenharmony_ci        }
245b1994897Sopenharmony_ci
246b1994897Sopenharmony_ci        logger = new HiLogger(level, component_mask);
247b1994897Sopenharmony_ci    }
248b1994897Sopenharmony_ci}
249b1994897Sopenharmony_ci#endif
250b1994897Sopenharmony_ci
251b1994897Sopenharmony_ci/* static */
252b1994897Sopenharmony_civoid Logger::InitializeStdLogging(Level level, const ComponentMask &component_mask)
253b1994897Sopenharmony_ci{
254b1994897Sopenharmony_ci    if (IsInitialized()) {
255b1994897Sopenharmony_ci        return;
256b1994897Sopenharmony_ci    }
257b1994897Sopenharmony_ci
258b1994897Sopenharmony_ci    {
259b1994897Sopenharmony_ci        os::memory::LockHolder<os::memory::Mutex> lock(mutex);
260b1994897Sopenharmony_ci
261b1994897Sopenharmony_ci        if (IsInitialized()) {
262b1994897Sopenharmony_ci            return;
263b1994897Sopenharmony_ci        }
264b1994897Sopenharmony_ci
265b1994897Sopenharmony_ci        logger = new StderrLogger(level, component_mask);
266b1994897Sopenharmony_ci    }
267b1994897Sopenharmony_ci}
268b1994897Sopenharmony_ci
269b1994897Sopenharmony_ci/* static */
270b1994897Sopenharmony_civoid Logger::InitializeDummyLogging(Level level, const ComponentMask &component_mask)
271b1994897Sopenharmony_ci{
272b1994897Sopenharmony_ci    if (IsInitialized()) {
273b1994897Sopenharmony_ci        return;
274b1994897Sopenharmony_ci    }
275b1994897Sopenharmony_ci
276b1994897Sopenharmony_ci    {
277b1994897Sopenharmony_ci        os::memory::LockHolder<os::memory::Mutex> lock(mutex);
278b1994897Sopenharmony_ci
279b1994897Sopenharmony_ci        if (IsInitialized()) {
280b1994897Sopenharmony_ci            return;
281b1994897Sopenharmony_ci        }
282b1994897Sopenharmony_ci
283b1994897Sopenharmony_ci        logger = new DummyLogger(level, component_mask);
284b1994897Sopenharmony_ci    }
285b1994897Sopenharmony_ci}
286b1994897Sopenharmony_ci
287b1994897Sopenharmony_ci/* static */
288b1994897Sopenharmony_civoid Logger::Destroy()
289b1994897Sopenharmony_ci{
290b1994897Sopenharmony_ci    if (!IsInitialized()) {
291b1994897Sopenharmony_ci        return;
292b1994897Sopenharmony_ci    }
293b1994897Sopenharmony_ci
294b1994897Sopenharmony_ci    Logger *l = nullptr;
295b1994897Sopenharmony_ci
296b1994897Sopenharmony_ci    {
297b1994897Sopenharmony_ci        os::memory::LockHolder<os::memory::Mutex> lock(mutex);
298b1994897Sopenharmony_ci
299b1994897Sopenharmony_ci        if (!IsInitialized()) {
300b1994897Sopenharmony_ci            return;
301b1994897Sopenharmony_ci        }
302b1994897Sopenharmony_ci
303b1994897Sopenharmony_ci        l = logger;
304b1994897Sopenharmony_ci        logger = nullptr;
305b1994897Sopenharmony_ci    }
306b1994897Sopenharmony_ci
307b1994897Sopenharmony_ci    delete l;
308b1994897Sopenharmony_ci}
309b1994897Sopenharmony_ci
310b1994897Sopenharmony_ci/* static */
311b1994897Sopenharmony_civoid Logger::ProcessLogLevelFromString(std::string_view s)
312b1994897Sopenharmony_ci{
313b1994897Sopenharmony_ci    if (Logger::IsInLevelList(s)) {
314b1994897Sopenharmony_ci        Logger::SetLevel(Logger::LevelFromString(s));
315b1994897Sopenharmony_ci    } else {
316b1994897Sopenharmony_ci        LOG(ERROR, RUNTIME) << "Unknown level " << s;
317b1994897Sopenharmony_ci    }
318b1994897Sopenharmony_ci}
319b1994897Sopenharmony_ci
320b1994897Sopenharmony_ci/* static */
321b1994897Sopenharmony_civoid Logger::ProcessLogComponentsFromString(std::string_view s)
322b1994897Sopenharmony_ci{
323b1994897Sopenharmony_ci    Logger::ResetComponentMask();
324b1994897Sopenharmony_ci    size_t last_pos = s.find_first_not_of(',', 0);
325b1994897Sopenharmony_ci    size_t pos = s.find(',', last_pos);
326b1994897Sopenharmony_ci    while (last_pos != std::string_view::npos) {
327b1994897Sopenharmony_ci        std::string_view component_str = s.substr(last_pos, pos - last_pos);
328b1994897Sopenharmony_ci        last_pos = s.find_first_not_of(',', pos);
329b1994897Sopenharmony_ci        pos = s.find(',', last_pos);
330b1994897Sopenharmony_ci        if (Logger::IsInComponentList(component_str)) {
331b1994897Sopenharmony_ci            Logger::EnableComponent(Logger::ComponentMaskFromString(component_str));
332b1994897Sopenharmony_ci        } else {
333b1994897Sopenharmony_ci            LOG(ERROR, RUNTIME) << "Unknown component " << component_str;
334b1994897Sopenharmony_ci        }
335b1994897Sopenharmony_ci    }
336b1994897Sopenharmony_ci}
337b1994897Sopenharmony_ci
338b1994897Sopenharmony_civoid FileLogger::LogLineInternal(Level level, Component component, const std::string &str)
339b1994897Sopenharmony_ci{
340b1994897Sopenharmony_ci    std::string prefix = GetPrefix(level, component);
341b1994897Sopenharmony_ci    stream_ << prefix << str << std::endl << std::flush;
342b1994897Sopenharmony_ci}
343b1994897Sopenharmony_ci
344b1994897Sopenharmony_civoid FastFileLogger::LogLineInternal(Level level, Component component, const std::string &str)
345b1994897Sopenharmony_ci{
346b1994897Sopenharmony_ci    std::string prefix = GetPrefix(level, component);
347b1994897Sopenharmony_ci    stream_ << prefix << str << '\n';
348b1994897Sopenharmony_ci}
349b1994897Sopenharmony_ci
350b1994897Sopenharmony_ci#ifdef ENABLE_HILOG
351b1994897Sopenharmony_civoid HiLogger::LogLineInternal(Level level, Component component, const std::string &str)
352b1994897Sopenharmony_ci{
353b1994897Sopenharmony_ci    std::string prefix = GetPrefix(level, component);
354b1994897Sopenharmony_ci    stream_ << prefix << str;
355b1994897Sopenharmony_ci    switch (level) {
356b1994897Sopenharmony_ci        case Level::DEBUG:
357b1994897Sopenharmony_ci            HILOG_DEBUG(LOG_CORE, "%{public}s", stream_.str().c_str());
358b1994897Sopenharmony_ci            break;
359b1994897Sopenharmony_ci        case Level::INFO:
360b1994897Sopenharmony_ci            HILOG_INFO(LOG_CORE, "%{public}s", stream_.str().c_str());
361b1994897Sopenharmony_ci            break;
362b1994897Sopenharmony_ci        case Level::ERROR:
363b1994897Sopenharmony_ci            HILOG_ERROR(LOG_CORE, "%{public}s", stream_.str().c_str());
364b1994897Sopenharmony_ci            break;
365b1994897Sopenharmony_ci        case Level::FATAL:
366b1994897Sopenharmony_ci            HILOG_FATAL(LOG_CORE, "%{public}s", stream_.str().c_str());
367b1994897Sopenharmony_ci            break;
368b1994897Sopenharmony_ci        case Level::WARNING:
369b1994897Sopenharmony_ci            HILOG_WARN(LOG_CORE, "%{public}s", stream_.str().c_str());
370b1994897Sopenharmony_ci            break;
371b1994897Sopenharmony_ci        default:
372b1994897Sopenharmony_ci            UNREACHABLE();
373b1994897Sopenharmony_ci    }
374b1994897Sopenharmony_ci}
375b1994897Sopenharmony_ci#endif
376b1994897Sopenharmony_ci
377b1994897Sopenharmony_civoid StderrLogger::LogLineInternal(Level level, Component component, const std::string &str)
378b1994897Sopenharmony_ci{
379b1994897Sopenharmony_ci    std::string prefix = GetPrefix(level, component);
380b1994897Sopenharmony_ci    std::cerr << prefix << str << std::endl << std::flush;
381b1994897Sopenharmony_ci}
382b1994897Sopenharmony_ci
383b1994897Sopenharmony_civoid FastFileLogger::SyncOutputResource()
384b1994897Sopenharmony_ci{
385b1994897Sopenharmony_ci    stream_ << std::flush;
386b1994897Sopenharmony_ci}
387b1994897Sopenharmony_ci
388b1994897Sopenharmony_ci}  // namespace panda
389