Aurore
A Switch-like interface for your app, on every screen
Loading...
Searching...
No Matches
logger.hpp
Go to the documentation of this file.
1/*
2 Copyright 2019 natinusala
3 Copyright 2019 p-sam
4
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16*/
17
18#pragma once
19
20#ifdef ANDROID
21#include <android/log.h>
22#endif
23
24#ifdef __PSV__
25#include <psp2/kernel/clib.h>
26#endif
27
28#ifdef PS4
29#include <orbis/libkernel.h>
30#include <aurore/platforms/ps4/ps4_sysmodule.hpp>
31#endif
32
33#include <fmt/chrono.h>
34#include <fmt/format.h>
35
36#include <ctime>
37#include <mutex>
38#include <string>
39#include <aurore/core/event.hpp>
40#include <aurore/core/time.hpp>
41
42namespace aurore
43{
44
45enum class LogLevel
46{
47 LOG_ERROR = 0,
52};
53
54#ifdef IOS
55#define AURORE_ERROR_COLOR "🔴"
56#define AURORE_WARNING_COLOR "🟠"
57#define AURORE_INFO_COLOR "🔵"
58#define AURORE_DEBUG_COLOR "🟢"
59#define AURORE_VERBOSE_COLOR "⚪️"
60#else
61#define AURORE_ERROR_COLOR "[0;31m"
62#define AURORE_WARNING_COLOR "[0;33m"
63#define AURORE_INFO_COLOR "[0;34m"
64#define AURORE_DEBUG_COLOR "[0;32m"
65#define AURORE_VERBOSE_COLOR "[0;37m"
66#endif
67
68#define AURORE_LOG_ERROR(format, ...) aurore::Logger::error("{}:{} " format, __FILE__, __LINE__, ##__VA_ARGS__)
69#define AURORE_LOG_WARNING(format, ...) aurore::Logger::warning("{}:{} " format, __FILE__, __LINE__, ##__VA_ARGS__)
70#define AURORE_LOG_INFO(format, ...) aurore::Logger::info("{}:{} " format, __FILE__, __LINE__, ##__VA_ARGS__)
71#define AURORE_LOG_DEBUG(format, ...) aurore::Logger::debug("{}:{} " format, __FILE__, __LINE__, ##__VA_ARGS__)
72#define AURORE_LOG_VERBOSE(format, ...) aurore::Logger::verbose("{}:{} " format, __FILE__, __LINE__, ##__VA_ARGS__)
73
74class Logger
75{
76 public:
77 using TimePoint = std::chrono::system_clock::time_point;
78
79 static void setLogLevel(LogLevel logLevel);
80
82
83 static void setLogOutput(std::FILE* logOut);
84
88 static void setThreadSafeLogging(bool threadSafeLogging);
89
90 template <typename... Args>
91 inline static void log(LogLevel level, std::string prefix, std::string color, fmt::format_string<Args...> format, Args&&... args)
92 {
93 if (Logger::logLevel < level)
94 return;
95
96 TimePoint now = std::chrono::system_clock::now();
97 uint64_t ms = std::chrono::duration_cast<std::chrono::milliseconds>(
98 now.time_since_epoch())
99 .count()
100 % 1000;
101#ifdef PS4
102 OrbisDateTime lt {};
103 if (sceRtcGetCurrentClockLocalTime)
104 sceRtcGetCurrentClockLocalTime(&lt);
105#else
106 std::time_t tt = std::chrono::system_clock::to_time_t(now);
107 std::tm time_tm = localTime(tt);
108#endif
109 std::unique_lock<std::mutex> lock;
110 if (Logger::threadSafeLogging)
111 lock = std::unique_lock { logMtx };
112
113 std::FILE* out = resolveLogOutput();
114
115 try
116 {
117 // In C++17 fmt checks the format string when the line is
118 // written, not when it is compiled: a wrong one throws here,
119 // caught below rather than ending the program.
120 std::string log = fmt::format(format, std::forward<Args>(args)...);
121
122#ifdef IOS
123 if (out)
124 fmt::print(out, "{:%H:%M:%S}.{:03d} {} {}\n", time_tm, (int)ms, color, log);
125#elif defined(ANDROID)
126 __android_log_print(6 - (int)level, "aurore", "%02d:%02d:%02d.%03d %s\n", time_tm.tm_hour, time_tm.tm_min, time_tm.tm_sec, (int)ms, log.c_str());
127#elif defined(__PSV__)
128 sceClibPrintf("%02d:%02d:%02d.%03d\033%s[%s]\033[0m %s\n", time_tm.tm_hour, time_tm.tm_min, time_tm.tm_sec, (int)ms, color.c_str(), prefix.c_str(), log.c_str());
129#elif defined(PS4)
130 sceKernelDebugOutText(0, fmt::format("{:02d}:{:02d}:{:02d}.{:03d}\033{}[{}]\033[0m {}\n", lt.hour, lt.minute, lt.second, (int)ms, color, prefix, log).c_str());
131#else
132 if (out)
133 fmt::print(out, "{:%H:%M:%S}.{:03d}\033{}[{}]\033[0m {}\n", time_tm, (int)ms, color, prefix, log);
134#endif
135
136 logEvent.fire(now, level, log);
137 }
138 catch (const std::exception& e)
139 {
140 // will be printed after the first fmt::print (so after the log tag)
141 printf("! Invalid log format string: \"%s\": %s\n", format.get().data(), e.what());
142 }
143
144 // Flush on every platform: once the output is not a terminal (nxlink
145 // socket, file, pipe) stdio buffers it fully, and the lines a crash
146 // leaves in the buffer are the ones needed to diagnose it.
147 if (out)
148 fflush(out);
149 }
150
151 template <typename... Args>
152 inline static void error(fmt::format_string<Args...> format, Args&&... args)
153 {
154 Logger::log(LogLevel::LOG_ERROR, "ERROR", AURORE_ERROR_COLOR, format, std::forward<Args>(args)...);
155 }
156
157 template <typename... Args>
158 inline static void warning(fmt::format_string<Args...> format, Args&&... args)
159 {
160 Logger::log(LogLevel::LOG_WARNING, "WARNING", AURORE_WARNING_COLOR, format, std::forward<Args>(args)...);
161 }
162
163 template <typename... Args>
164 inline static void info(fmt::format_string<Args...> format, Args&&... args)
165 {
166 Logger::log(LogLevel::LOG_INFO, "INFO", AURORE_INFO_COLOR, format, std::forward<Args>(args)...);
167 }
168
169 template <typename... Args>
170 inline static void debug(fmt::format_string<Args...> format, Args&&... args)
171 {
172 Logger::log(LogLevel::LOG_DEBUG, "DEBUG", AURORE_DEBUG_COLOR, format, std::forward<Args>(args)...);
173 }
174
175 template <typename... Args>
176 inline static void verbose(fmt::format_string<Args...> format, Args&&... args)
177 {
178 Logger::log(LogLevel::LOG_VERBOSE, "VERBOSE", AURORE_VERBOSE_COLOR, format, std::forward<Args>(args)...);
179 }
180
182 {
183 return &logEvent;
184 }
185
186 private:
187 inline static std::mutex logMtx;
188 inline static bool threadSafeLogging = true;
189 inline static Event<TimePoint, LogLevel, std::string> logEvent;
190 // Resolved on first use, not by a static initialiser: on newlib
191 // (devkitPro) stdout can still be null when statics are initialised.
192 static std::FILE* resolveLogOutput()
193 {
194 if (!logOutSet)
195 {
196 logOut = stdout;
197 logOutSet = true;
198 }
199 return logOut;
200 }
201
202 inline static std::FILE* logOut = nullptr;
203 inline static bool logOutSet = false;
204 inline static LogLevel logLevel = LogLevel::LOG_INFO;
205};
206
207} // namespace aurore
Definition event.hpp:41
bool fire(Ts... args)
Definition event.hpp:104
Definition logger.hpp:75
static void info(fmt::format_string< Args... > format, Args &&... args)
Definition logger.hpp:164
std::chrono::system_clock::time_point TimePoint
Definition logger.hpp:77
static void debug(fmt::format_string< Args... > format, Args &&... args)
Definition logger.hpp:170
static Event< TimePoint, LogLevel, std::string > * getLogEvent()
Definition logger.hpp:181
static void setLogOutput(std::FILE *logOut)
static LogLevel getLogLevel()
static void warning(fmt::format_string< Args... > format, Args &&... args)
Definition logger.hpp:158
static void setThreadSafeLogging(bool threadSafeLogging)
static void setLogLevel(LogLevel logLevel)
static void log(LogLevel level, std::string prefix, std::string color, fmt::format_string< Args... > format, Args &&... args)
Definition logger.hpp:91
static void verbose(fmt::format_string< Args... > format, Args &&... args)
Definition logger.hpp:176
static void error(fmt::format_string< Args... > format, Args &&... args)
Definition logger.hpp:152
#define AURORE_INFO_COLOR
Definition logger.hpp:63
#define AURORE_WARNING_COLOR
Definition logger.hpp:62
#define AURORE_ERROR_COLOR
Definition logger.hpp:61
#define AURORE_VERBOSE_COLOR
Definition logger.hpp:65
#define AURORE_DEBUG_COLOR
Definition logger.hpp:64
Definition actions.hpp:25
LogLevel
Definition logger.hpp:46
std::tm localTime(std::time_t time)
Definition time.hpp:104