mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 07:55:29 +03:00
Make Logger
class static and introduce LoggerContext
A thread local LoggerContext is now used to hold the output file stream instead of the `Logger` class. Before doing any logging operations, a LoggerContext must be initialized. This commit will not build successfully on purpose.
This commit is contained in:
parent
69ef93bfa8
commit
769e6c933d
@ -106,6 +106,7 @@ add_library(skyline SHARED
|
|||||||
${source_DIR}/emu_jni.cpp
|
${source_DIR}/emu_jni.cpp
|
||||||
${source_DIR}/loader_jni.cpp
|
${source_DIR}/loader_jni.cpp
|
||||||
${source_DIR}/skyline/common.cpp
|
${source_DIR}/skyline/common.cpp
|
||||||
|
${source_DIR}/skyline/common/logger.cpp
|
||||||
${source_DIR}/skyline/common/settings.cpp
|
${source_DIR}/skyline/common/settings.cpp
|
||||||
${source_DIR}/skyline/common/signal.cpp
|
${source_DIR}/skyline/common/signal.cpp
|
||||||
${source_DIR}/skyline/common/uuid.cpp
|
${source_DIR}/skyline/common/uuid.cpp
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <android/log.h>
|
|
||||||
#include <android/asset_manager_jni.h>
|
#include <android/asset_manager_jni.h>
|
||||||
#include <sys/system_properties.h>
|
#include <sys/system_properties.h>
|
||||||
#include "skyline/common.h"
|
#include "skyline/common.h"
|
||||||
|
#include "skyline/common/logger.h"
|
||||||
#include "skyline/common/language.h"
|
#include "skyline/common/language.h"
|
||||||
#include "skyline/common/signal.h"
|
#include "skyline/common/signal.h"
|
||||||
#include "skyline/common/settings.h"
|
#include "skyline/common/settings.h"
|
||||||
@ -55,6 +55,17 @@ static std::string GetTimeZoneName() {
|
|||||||
return "GMT";
|
return "GMT";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void Java_emu_skyline_SkylineApplication_initializeLog(
|
||||||
|
JNIEnv *env,
|
||||||
|
jobject,
|
||||||
|
jstring appFilesPathJstring,
|
||||||
|
jint logLevel
|
||||||
|
) {
|
||||||
|
std::string appFilesPath{env->GetStringUTFChars(appFilesPathJstring, nullptr)};
|
||||||
|
skyline::Logger::configLevel = static_cast<skyline::Logger::LogLevel>(logLevel);
|
||||||
|
skyline::Logger::LoaderContext.Initialize(appFilesPath + "loader.log");
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
||||||
JNIEnv *env,
|
JNIEnv *env,
|
||||||
jobject instance,
|
jobject instance,
|
||||||
@ -77,7 +88,7 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
|||||||
close(preferenceFd);
|
close(preferenceFd);
|
||||||
|
|
||||||
skyline::JniString appFilesPath(env, appFilesPathJstring);
|
skyline::JniString appFilesPath(env, appFilesPathJstring);
|
||||||
auto logger{std::make_shared<skyline::Logger>(appFilesPath + "skyline.log", settings->logLevel)};
|
skyline::Logger::EmulationContext.Initialize(appFilesPath + "emulation.log");
|
||||||
|
|
||||||
auto start{std::chrono::steady_clock::now()};
|
auto start{std::chrono::steady_clock::now()};
|
||||||
|
|
||||||
@ -90,7 +101,6 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
|||||||
try {
|
try {
|
||||||
auto os{std::make_shared<skyline::kernel::OS>(
|
auto os{std::make_shared<skyline::kernel::OS>(
|
||||||
jvmManager,
|
jvmManager,
|
||||||
logger,
|
|
||||||
settings,
|
settings,
|
||||||
appFilesPath,
|
appFilesPath,
|
||||||
GetTimeZoneName(),
|
GetTimeZoneName(),
|
||||||
@ -121,6 +131,7 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
|||||||
auto end{std::chrono::steady_clock::now()};
|
auto end{std::chrono::steady_clock::now()};
|
||||||
logger->Write(skyline::Logger::LogLevel::Info, fmt::format("Emulation has ended in {}ms", std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()));
|
logger->Write(skyline::Logger::LogLevel::Info, fmt::format("Emulation has ended in {}ms", std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()));
|
||||||
|
|
||||||
|
skyline::Logger::EmulationContext.Finalize();
|
||||||
close(romFd);
|
close(romFd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#include "skyline/common/logger.h"
|
||||||
#include "skyline/crypto/key_store.h"
|
#include "skyline/crypto/key_store.h"
|
||||||
#include "skyline/vfs/nca.h"
|
#include "skyline/vfs/nca.h"
|
||||||
#include "skyline/vfs/os_backing.h"
|
#include "skyline/vfs/os_backing.h"
|
||||||
@ -14,6 +15,8 @@
|
|||||||
extern "C" JNIEXPORT jint JNICALL Java_emu_skyline_loader_RomFile_populate(JNIEnv *env, jobject thiz, jint jformat, jint fd, jstring appFilesPathJstring, jint systemLanguage) {
|
extern "C" JNIEXPORT jint JNICALL Java_emu_skyline_loader_RomFile_populate(JNIEnv *env, jobject thiz, jint jformat, jint fd, jstring appFilesPathJstring, jint systemLanguage) {
|
||||||
skyline::loader::RomFormat format{static_cast<skyline::loader::RomFormat>(jformat)};
|
skyline::loader::RomFormat format{static_cast<skyline::loader::RomFormat>(jformat)};
|
||||||
|
|
||||||
|
skyline::Logger::SetContext(&skyline::Logger::LoaderContext);
|
||||||
|
|
||||||
auto keyStore{std::make_shared<skyline::crypto::KeyStore>(skyline::JniString(env, appFilesPathJstring))};
|
auto keyStore{std::make_shared<skyline::crypto::KeyStore>(skyline::JniString(env, appFilesPathJstring))};
|
||||||
std::unique_ptr<skyline::loader::Loader> loader;
|
std::unique_ptr<skyline::loader::Loader> loader;
|
||||||
try {
|
try {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
#include <android/log.h>
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "nce.h"
|
#include "nce.h"
|
||||||
#include "soc.h"
|
#include "soc.h"
|
||||||
@ -11,45 +10,8 @@
|
|||||||
#include "kernel/types/KProcess.h"
|
#include "kernel/types/KProcess.h"
|
||||||
|
|
||||||
namespace skyline {
|
namespace skyline {
|
||||||
Logger::Logger(const std::string &path, LogLevel configLevel)
|
DeviceState::DeviceState(kernel::OS *os, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings)
|
||||||
: configLevel(configLevel),
|
: os(os), jvm(std::move(jvmManager)), settings(std::move(settings)) {
|
||||||
start(util::GetTimeNs() / constant::NsInMillisecond) {
|
|
||||||
logFile.open(path, std::ios::trunc);
|
|
||||||
UpdateTag();
|
|
||||||
Write(LogLevel::Info, "Logging started");
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::~Logger() {
|
|
||||||
Write(LogLevel::Info, "Logging ended");
|
|
||||||
logFile.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
thread_local static std::string logTag, threadName;
|
|
||||||
|
|
||||||
void Logger::UpdateTag() {
|
|
||||||
std::array<char, 16> name;
|
|
||||||
if (!pthread_getname_np(pthread_self(), name.data(), name.size()))
|
|
||||||
threadName = name.data();
|
|
||||||
else
|
|
||||||
threadName = "unk";
|
|
||||||
logTag = std::string("emu-cpp-") + threadName;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::Write(LogLevel level, const std::string &str) {
|
|
||||||
constexpr std::array<char, 5> levelCharacter{'E', 'W', 'I', 'D', 'V'}; // The LogLevel as written out to a file
|
|
||||||
constexpr std::array<int, 5> levelAlog{ANDROID_LOG_ERROR, ANDROID_LOG_WARN, ANDROID_LOG_INFO, ANDROID_LOG_DEBUG, ANDROID_LOG_VERBOSE}; // This corresponds to LogLevel and provides its equivalent for NDK Logging
|
|
||||||
|
|
||||||
if (logTag.empty())
|
|
||||||
UpdateTag();
|
|
||||||
|
|
||||||
__android_log_write(levelAlog[static_cast<u8>(level)], logTag.c_str(), str.c_str());
|
|
||||||
|
|
||||||
std::lock_guard guard(mutex);
|
|
||||||
logFile << '\036' << levelCharacter[static_cast<u8>(level)] << '\035' << std::dec << (util::GetTimeNs() / constant::NsInMillisecond) - start << '\035' << threadName << '\035' << str << '\n'; // We use RS (\036) and GS (\035) as our delimiters
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceState::DeviceState(kernel::OS *os, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger)
|
|
||||||
: os(os), jvm(std::move(jvmManager)), settings(std::move(settings)), logger(std::move(logger)) {
|
|
||||||
// We assign these later as they use the state in their constructor and we don't want null pointers
|
// We assign these later as they use the state in their constructor and we don't want null pointers
|
||||||
gpu = std::make_shared<gpu::GPU>(*this);
|
gpu = std::make_shared<gpu::GPU>(*this);
|
||||||
soc = std::make_shared<soc::SOC>(*this);
|
soc = std::make_shared<soc::SOC>(*this);
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <fstream>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -21,152 +20,6 @@
|
|||||||
#include <common/result.h>
|
#include <common/result.h>
|
||||||
|
|
||||||
namespace skyline {
|
namespace skyline {
|
||||||
/**
|
|
||||||
* @brief A wrapper around writing logs into a log file and logcat using Android Log APIs
|
|
||||||
*/
|
|
||||||
class Logger {
|
|
||||||
private:
|
|
||||||
std::mutex mutex; //!< Synchronizes all output I/O to ensure there are no races
|
|
||||||
std::ofstream logFile; //!< An output stream to the log file
|
|
||||||
i64 start; //!< A timestamp in milliseconds for when the logger was started, this is used as the base for all log timestamps
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum class LogLevel {
|
|
||||||
Error,
|
|
||||||
Warn,
|
|
||||||
Info,
|
|
||||||
Debug,
|
|
||||||
Verbose,
|
|
||||||
};
|
|
||||||
|
|
||||||
LogLevel configLevel; //!< The minimum level of logs to write
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param path The path of the log file
|
|
||||||
* @param configLevel The minimum level of logs to write
|
|
||||||
*/
|
|
||||||
Logger(const std::string &path, LogLevel configLevel);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Writes the termination message to the log file
|
|
||||||
*/
|
|
||||||
~Logger();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Update the tag in log messages with a new thread name
|
|
||||||
*/
|
|
||||||
static void UpdateTag();
|
|
||||||
|
|
||||||
void Write(LogLevel level, const std::string &str);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A wrapper around a string which captures the calling function using Clang source location builtins
|
|
||||||
* @note A function needs to be declared for every argument template specialization as CTAD cannot work with implicit casting
|
|
||||||
* @url https://clang.llvm.org/docs/LanguageExtensions.html#source-location-builtins
|
|
||||||
*/
|
|
||||||
template<typename S>
|
|
||||||
struct FunctionString {
|
|
||||||
S string;
|
|
||||||
const char *function;
|
|
||||||
|
|
||||||
constexpr FunctionString(S string, const char *function = __builtin_FUNCTION()) : string(std::move(string)), function(function) {}
|
|
||||||
|
|
||||||
std::string operator*() {
|
|
||||||
return std::string(function) + ": " + std::string(string);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void Error(FunctionString<const char*> formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Error <= configLevel)
|
|
||||||
Write(LogLevel::Error, util::Format(*formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void Error(FunctionString<std::string> formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Error <= configLevel)
|
|
||||||
Write(LogLevel::Error, util::Format(*formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S, typename... Args>
|
|
||||||
void ErrorNoPrefix(S formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Error <= configLevel)
|
|
||||||
Write(LogLevel::Error, util::Format(formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void Warn(FunctionString<const char*> formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Warn <= configLevel)
|
|
||||||
Write(LogLevel::Warn, util::Format(*formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void Warn(FunctionString<std::string> formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Warn <= configLevel)
|
|
||||||
Write(LogLevel::Warn, util::Format(*formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S, typename... Args>
|
|
||||||
void WarnNoPrefix(S formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Warn <= configLevel)
|
|
||||||
Write(LogLevel::Warn, util::Format(formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void Info(FunctionString<const char*> formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Info <= configLevel)
|
|
||||||
Write(LogLevel::Info, util::Format(*formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void Info(FunctionString<std::string> formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Info <= configLevel)
|
|
||||||
Write(LogLevel::Info, util::Format(*formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S, typename... Args>
|
|
||||||
void InfoNoPrefix(S formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Info <= configLevel)
|
|
||||||
Write(LogLevel::Info, util::Format(formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void Debug(FunctionString<const char*> formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Debug <= configLevel)
|
|
||||||
Write(LogLevel::Debug, util::Format(*formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void Debug(FunctionString<std::string> formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Debug <= configLevel)
|
|
||||||
Write(LogLevel::Debug, util::Format(*formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S, typename... Args>
|
|
||||||
void DebugNoPrefix(S formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Debug <= configLevel)
|
|
||||||
Write(LogLevel::Debug, util::Format(formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void Verbose(FunctionString<const char*> formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Verbose <= configLevel)
|
|
||||||
Write(LogLevel::Verbose, util::Format(*formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
void Verbose(FunctionString<std::string> formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Verbose <= configLevel)
|
|
||||||
Write(LogLevel::Verbose, util::Format(*formatString, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S, typename... Args>
|
|
||||||
void VerboseNoPrefix(S formatString, Args &&... args) {
|
|
||||||
if (LogLevel::Verbose <= configLevel)
|
|
||||||
Write(LogLevel::Verbose, util::Format(formatString, args...));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Settings;
|
class Settings;
|
||||||
namespace nce {
|
namespace nce {
|
||||||
class NCE;
|
class NCE;
|
||||||
@ -201,14 +54,13 @@ namespace skyline {
|
|||||||
* @brief The state of the entire emulator is contained within this class, all objects related to emulation are tied into it
|
* @brief The state of the entire emulator is contained within this class, all objects related to emulation are tied into it
|
||||||
*/
|
*/
|
||||||
struct DeviceState {
|
struct DeviceState {
|
||||||
DeviceState(kernel::OS *os, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger);
|
DeviceState(kernel::OS *os, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings);
|
||||||
|
|
||||||
~DeviceState();
|
~DeviceState();
|
||||||
|
|
||||||
kernel::OS *os;
|
kernel::OS *os;
|
||||||
std::shared_ptr<JvmManager> jvm;
|
std::shared_ptr<JvmManager> jvm;
|
||||||
std::shared_ptr<Settings> settings;
|
std::shared_ptr<Settings> settings;
|
||||||
std::shared_ptr<Logger> logger;
|
|
||||||
std::shared_ptr<loader::Loader> loader;
|
std::shared_ptr<loader::Loader> loader;
|
||||||
std::shared_ptr<kernel::type::KProcess> process{};
|
std::shared_ptr<kernel::type::KProcess> process{};
|
||||||
static thread_local inline std::shared_ptr<kernel::type::KThread> thread{}; //!< The KThread of the thread which accesses this object
|
static thread_local inline std::shared_ptr<kernel::type::KThread> thread{}; //!< The KThread of the thread which accesses this object
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
#include <bitset>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
namespace fmt {
|
namespace fmt {
|
||||||
|
62
app/src/main/cpp/skyline/common/logger.cpp
Normal file
62
app/src/main/cpp/skyline/common/logger.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
namespace skyline {
|
||||||
|
void Logger::LoggerContext::Initialize(const std::string &path) {
|
||||||
|
start = util::GetTimeNs() / constant::NsInMillisecond;
|
||||||
|
logFile.open(path, std::ios::trunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::LoggerContext::Finalize() {
|
||||||
|
logFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::LoggerContext::Flush() {
|
||||||
|
logFile.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_local static std::string logTag, threadName;
|
||||||
|
thread_local static Logger::LoggerContext *context{&Logger::EmulationContext};
|
||||||
|
|
||||||
|
void Logger::UpdateTag() {
|
||||||
|
std::array<char, 16> name;
|
||||||
|
if (!pthread_getname_np(pthread_self(), name.data(), name.size()))
|
||||||
|
threadName = name.data();
|
||||||
|
else
|
||||||
|
threadName = "unk";
|
||||||
|
logTag = std::string("emu-cpp-") + threadName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::LoggerContext *Logger::GetContext() {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::SetContext(LoggerContext *pContext) {
|
||||||
|
context = pContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::WriteAndroid(LogLevel level, const std::string &str) {
|
||||||
|
constexpr std::array<int, 5> levelAlog{ANDROID_LOG_ERROR, ANDROID_LOG_WARN, ANDROID_LOG_INFO, ANDROID_LOG_DEBUG, ANDROID_LOG_VERBOSE}; // This corresponds to LogLevel and provides its equivalent for NDK Logging
|
||||||
|
if (logTag.empty())
|
||||||
|
UpdateTag();
|
||||||
|
|
||||||
|
__android_log_write(levelAlog[static_cast<u8>(level)], logTag.c_str(), str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Write(LogLevel level, const std::string &str) {
|
||||||
|
constexpr std::array<char, 5> levelCharacter{'E', 'W', 'I', 'D', 'V'}; // The LogLevel as written out to a file
|
||||||
|
WriteAndroid(level, str);
|
||||||
|
|
||||||
|
if (context)
|
||||||
|
// We use RS (\036) and GS (\035) as our delimiters
|
||||||
|
context->Write(fmt::format("\036{}\035{}\035{}\035{}\n", levelCharacter[static_cast<u8>(level)], (util::GetTimeNs() / constant::NsInMillisecond) - context->start, threadName, str));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::LoggerContext::Write(const std::string &str) {
|
||||||
|
std::lock_guard guard(mutex);
|
||||||
|
logFile << str;
|
||||||
|
}
|
||||||
|
}
|
169
app/src/main/cpp/skyline/common/logger.h
Normal file
169
app/src/main/cpp/skyline/common/logger.h
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <mutex>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
namespace skyline {
|
||||||
|
/**
|
||||||
|
* @brief A wrapper around writing logs into a log file and logcat using Android Log APIs
|
||||||
|
*/
|
||||||
|
class Logger {
|
||||||
|
private:
|
||||||
|
Logger() {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class LogLevel {
|
||||||
|
Error,
|
||||||
|
Warn,
|
||||||
|
Info,
|
||||||
|
Debug,
|
||||||
|
Verbose,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline LogLevel configLevel{LogLevel::Verbose}; //!< The minimum level of logs to write
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Holds logger variables that cannot be static
|
||||||
|
*/
|
||||||
|
struct LoggerContext {
|
||||||
|
std::mutex mutex; //!< Synchronizes all output I/O to ensure there are no races
|
||||||
|
std::ofstream logFile; //!< An output stream to the log file
|
||||||
|
i64 start; //!< A timestamp in milliseconds for when the logger was started, this is used as the base for all log timestamps
|
||||||
|
|
||||||
|
LoggerContext() {}
|
||||||
|
|
||||||
|
void Initialize(const std::string &path);
|
||||||
|
|
||||||
|
void Finalize();
|
||||||
|
|
||||||
|
void Flush();
|
||||||
|
|
||||||
|
void Write(const std::string &str);
|
||||||
|
};
|
||||||
|
static inline LoggerContext EmulationContext, LoaderContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the tag in log messages with a new thread name
|
||||||
|
*/
|
||||||
|
static void UpdateTag();
|
||||||
|
|
||||||
|
static LoggerContext *GetContext();
|
||||||
|
|
||||||
|
static void SetContext(LoggerContext *context);
|
||||||
|
|
||||||
|
static void WriteAndroid(LogLevel level, const std::string &str);
|
||||||
|
|
||||||
|
static void Write(LogLevel level, const std::string &str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A wrapper around a string which captures the calling function using Clang source location builtins
|
||||||
|
* @note A function needs to be declared for every argument template specialization as CTAD cannot work with implicit casting
|
||||||
|
* @url https://clang.llvm.org/docs/LanguageExtensions.html#source-location-builtins
|
||||||
|
*/
|
||||||
|
template<typename S>
|
||||||
|
struct FunctionString {
|
||||||
|
S string;
|
||||||
|
const char *function;
|
||||||
|
|
||||||
|
FunctionString(S string, const char *function = __builtin_FUNCTION()) : string(std::move(string)), function(function) {}
|
||||||
|
|
||||||
|
std::string operator*() {
|
||||||
|
return std::string(function) + ": " + std::string(string);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void Error(FunctionString<const char *> formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Error <= configLevel)
|
||||||
|
Write(LogLevel::Error, util::Format(*formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void Error(FunctionString<std::string> formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Error <= configLevel)
|
||||||
|
Write(LogLevel::Error, util::Format(*formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename S, typename... Args>
|
||||||
|
static void ErrorNoPrefix(S formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Error <= configLevel)
|
||||||
|
Write(LogLevel::Error, util::Format(formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void Warn(FunctionString<const char *> formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Warn <= configLevel)
|
||||||
|
Write(LogLevel::Warn, util::Format(*formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void Warn(FunctionString<std::string> formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Warn <= configLevel)
|
||||||
|
Write(LogLevel::Warn, util::Format(*formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename S, typename... Args>
|
||||||
|
static void WarnNoPrefix(S formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Warn <= configLevel)
|
||||||
|
Write(LogLevel::Warn, util::Format(formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void Info(FunctionString<const char *> formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Info <= configLevel)
|
||||||
|
Write(LogLevel::Info, util::Format(*formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void Info(FunctionString<std::string> formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Info <= configLevel)
|
||||||
|
Write(LogLevel::Info, util::Format(*formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename S, typename... Args>
|
||||||
|
static void InfoNoPrefix(S formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Info <= configLevel)
|
||||||
|
Write(LogLevel::Info, util::Format(formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void Debug(FunctionString<const char *> formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Debug <= configLevel)
|
||||||
|
Write(LogLevel::Debug, util::Format(*formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void Debug(FunctionString<std::string> formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Debug <= configLevel)
|
||||||
|
Write(LogLevel::Debug, util::Format(*formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename S, typename... Args>
|
||||||
|
static void DebugNoPrefix(S formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Debug <= configLevel)
|
||||||
|
Write(LogLevel::Debug, util::Format(formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void Verbose(FunctionString<const char *> formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Verbose <= configLevel)
|
||||||
|
Write(LogLevel::Verbose, util::Format(*formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void Verbose(FunctionString<std::string> formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Verbose <= configLevel)
|
||||||
|
Write(LogLevel::Verbose, util::Format(*formatString, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename S, typename... Args>
|
||||||
|
static void VerboseNoPrefix(S formatString, Args &&... args) {
|
||||||
|
if (LogLevel::Verbose <= configLevel)
|
||||||
|
Write(LogLevel::Verbose, util::Format(formatString, args...));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <span>
|
||||||
#include <frozen/unordered_map.h>
|
#include <frozen/unordered_map.h>
|
||||||
#include <frozen/string.h>
|
#include <frozen/string.h>
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
@ -15,13 +15,12 @@
|
|||||||
namespace skyline::kernel {
|
namespace skyline::kernel {
|
||||||
OS::OS(
|
OS::OS(
|
||||||
std::shared_ptr<JvmManager> &jvmManager,
|
std::shared_ptr<JvmManager> &jvmManager,
|
||||||
std::shared_ptr<Logger> &logger,
|
|
||||||
std::shared_ptr<Settings> &settings,
|
std::shared_ptr<Settings> &settings,
|
||||||
std::string appFilesPath,
|
std::string appFilesPath,
|
||||||
std::string deviceTimeZone,
|
std::string deviceTimeZone,
|
||||||
language::SystemLanguage systemLanguage,
|
language::SystemLanguage systemLanguage,
|
||||||
std::shared_ptr<vfs::FileSystem> assetFileSystem)
|
std::shared_ptr<vfs::FileSystem> assetFileSystem)
|
||||||
: state(this, jvmManager, settings, logger),
|
: state(this, jvmManager, settings),
|
||||||
appFilesPath(std::move(appFilesPath)),
|
appFilesPath(std::move(appFilesPath)),
|
||||||
deviceTimeZone(std::move(deviceTimeZone)),
|
deviceTimeZone(std::move(deviceTimeZone)),
|
||||||
assetFileSystem(std::move(assetFileSystem)),
|
assetFileSystem(std::move(assetFileSystem)),
|
||||||
|
@ -22,13 +22,11 @@ namespace skyline::kernel {
|
|||||||
language::SystemLanguage systemLanguage;
|
language::SystemLanguage systemLanguage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param logger An instance of the Logger class
|
|
||||||
* @param settings An instance of the Settings class
|
* @param settings An instance of the Settings class
|
||||||
* @param window The ANativeWindow object to draw the screen to
|
* @param window The ANativeWindow object to draw the screen to
|
||||||
*/
|
*/
|
||||||
OS(
|
OS(
|
||||||
std::shared_ptr<JvmManager> &jvmManager,
|
std::shared_ptr<JvmManager> &jvmManager,
|
||||||
std::shared_ptr<Logger> &logger,
|
|
||||||
std::shared_ptr<Settings> &settings,
|
std::shared_ptr<Settings> &settings,
|
||||||
std::string appFilesPath,
|
std::string appFilesPath,
|
||||||
std::string deviceTimeZone,
|
std::string deviceTimeZone,
|
||||||
|
@ -37,10 +37,6 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
private var emulationThread : Thread? = null
|
private var emulationThread : Thread? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
|
||||||
System.loadLibrary("skyline") // libskyline.so
|
|
||||||
}
|
|
||||||
|
|
||||||
private val binding by lazy { EmuActivityBinding.inflate(layoutInflater) }
|
private val binding by lazy { EmuActivityBinding.inflate(layoutInflater) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,6 +7,15 @@ package emu.skyline
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import dagger.hilt.android.HiltAndroidApp
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
|
import emu.skyline.di.getSettings
|
||||||
|
|
||||||
@HiltAndroidApp
|
@HiltAndroidApp
|
||||||
class SkylineApplication : Application()
|
class SkylineApplication : Application() {
|
||||||
|
private external fun initializeLog(appFilesPath : String, logLevel : Int)
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
System.loadLibrary("skyline")
|
||||||
|
initializeLog(applicationContext.filesDir.canonicalPath + "/", getSettings().logLevel.toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -127,8 +127,6 @@ internal class RomFile(context : Context, format : RomFormat, uri : Uri, systemL
|
|||||||
get() = result == LoaderResult.Success
|
get() = result == LoaderResult.Success
|
||||||
|
|
||||||
init {
|
init {
|
||||||
System.loadLibrary("skyline")
|
|
||||||
|
|
||||||
context.contentResolver.openFileDescriptor(uri, "r")!!.use {
|
context.contentResolver.openFileDescriptor(uri, "r")!!.use {
|
||||||
result = LoaderResult.get(populate(format.ordinal, it.fd, context.filesDir.canonicalPath + "/", systemLanguage))
|
result = LoaderResult.get(populate(format.ordinal, it.fd, context.filesDir.canonicalPath + "/", systemLanguage))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user