Files
Plugin/Source/SenseGloveLog/Public/SGLog/SGLog.h
T

738 lines
17 KiB
C++

/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2025 SenseGlove
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @section DESCRIPTION
*
*
*/
#pragma once
#include <cstddef>
#include <cstdio>
#include <string>
#include "Containers/StringConv.h"
#include "Containers/UnrealString.h"
#include "GameFramework/Actor.h"
#include "Logging/LogVerbosity.h"
#include "Math/Rotator.h"
#include "Math/Transform.h"
#include "Math/Vector.h"
#include "Templates/SharedPointer.h"
#include "Templates/UnrealTemplate.h"
DECLARE_LOG_CATEGORY_EXTERN(LogEditor, All, All);
DECLARE_LOG_CATEGORY_EXTERN(LogGeneric, All, All);
template<typename T>
struct TFSGLogString
{
T T1;
FString T2;
static_assert(std::is_same<decltype(T1), decltype(T2)>::value, "Error: you are missing a template specialization!");
};
template<typename T, size_t L>
struct TFSGLogString<T[L]>
{
T T1;
FString T2;
static_assert(std::is_same<decltype(T1), decltype(T2)>::value, "Error: you are missing a template specialization!");
};
template<>
struct TFSGLogString<const AActor*>
{
static void Format(const AActor* Actor, FString& OutString)
{
ensureAlwaysMsgf(Actor, TEXT("FATAL: cannot log a NULL actor object!"));
OutString = FString::Printf(TEXT("%s"), Actor->GetName().GetCharArray().GetData());
}
};
template<>
struct TFSGLogString<AActor*>
{
static void Format(const AActor* Actor, FString& OutString)
{
ensureAlwaysMsgf(Actor, TEXT("FATAL: cannot log a NULL actor object!"));
OutString = FString::Printf(TEXT("%s"), Actor->GetName().GetCharArray().GetData());
}
};
template<>
struct TFSGLogString<const bool>
{
static void Format(const bool Value, FString& OutString)
{
OutString = Value ? TEXT("True") : TEXT("False");
}
};
template<>
struct TFSGLogString<bool>
{
static void Format(const bool Value, FString& OutString)
{
OutString = Value ? TEXT("True") : TEXT("False");
}
};
template<std::size_t L>
struct TFSGLogString<const char[L]>
{
static void Format(const char* Value, FString& OutString)
{
OutString = FString(UTF8_TO_TCHAR(Value));
}
};
template<std::size_t L>
struct TFSGLogString<char[L]>
{
static void Format(const char* Value, FString& OutString)
{
OutString = FString(UTF8_TO_TCHAR(Value));
}
};
template<>
struct TFSGLogString<const char*>
{
static void Format(const char* Value, FString& OutString)
{
OutString = FString(UTF8_TO_TCHAR(Value));
}
};
template<>
struct TFSGLogString<char*>
{
static void Format(const char* Value, FString& OutString)
{
OutString = FString(UTF8_TO_TCHAR(Value));
}
};
#if ! PLATFORM_ANDROID && PLATFORM_LINUX
template<std::size_t L>
struct TFSGLogString<const char16_t[L]>
{
static void Format(const char16_t* Value, FString& OutString)
{
OutString = FString(StringCast<TCHAR>(Value).Get());
}
};
#endif /* ! PLATFORM_ANDROID && PLATFORM_LINUX */
#if ! PLATFORM_ANDROID && PLATFORM_LINUX
template<std::size_t L>
struct TFSGLogString<char16_t[L]>
{
static void Format(const char16_t* Value, FString& OutString)
{
OutString = FString(StringCast<TCHAR>(Value).Get());
}
};
#endif /* ! PLATFORM_ANDROID && PLATFORM_LINUX */
#if ! PLATFORM_ANDROID && PLATFORM_LINUX
template<>
struct TFSGLogString<const char16_t*>
{
static void Format(const char16_t* Value, FString& OutString)
{
OutString = FString(StringCast<TCHAR>(Value).Get());
}
};
#endif /* ! PLATFORM_ANDROID && PLATFORM_LINUX */
#if ! PLATFORM_ANDROID && PLATFORM_LINUX
template<>
struct TFSGLogString<char16_t*>
{
static void Format(const char16_t* Value, FString& OutString)
{
OutString = FString(StringCast<TCHAR>(Value).Get());
}
};
#endif /* ! PLATFORM_ANDROID && PLATFORM_LINUX */
template<>
struct TFSGLogString<const double>
{
static void Format(const double Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<double>
{
static void Format(const double Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<const float>
{
static void Format(const float Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<float>
{
static void Format(const float Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<const FName>
{
static void Format(const FName& Value, FString& OutString)
{
OutString = Value.ToString();
}
};
template<>
struct TFSGLogString<FName>
{
static void Format(const FName& Value, FString& OutString)
{
OutString = Value.ToString();
}
};
template<>
struct TFSGLogString<const FQuat>
{
static void Format(const FQuat& Value, FString& OutString)
{
OutString = Value.ToString();
}
};
template<>
struct TFSGLogString<FQuat>
{
static void Format(const FQuat& Value, FString& OutString)
{
OutString = Value.ToString();
}
};
template<>
struct TFSGLogString<const FRotator>
{
static void Format(const FRotator& Value, FString& OutString)
{
OutString = Value.ToString();
}
};
template<>
struct TFSGLogString<FRotator>
{
static void Format(const FRotator& Value, FString& OutString)
{
OutString = Value.ToString();
}
};
template<>
struct TFSGLogString<const FString>
{
static void Format(const FString& Value, FString& OutString)
{
OutString = Value;
}
};
template<>
struct TFSGLogString<FString>
{
static void Format(const FString& Value, FString& OutString)
{
OutString = Value;
}
};
template<>
struct TFSGLogString<const FTransform>
{
static void Format(const FTransform& Value, FString& OutString)
{
OutString = Value.ToString();
}
};
template<>
struct TFSGLogString<FTransform>
{
static void Format(const FTransform& Value, FString& OutString)
{
OutString = Value.ToString();
}
};
template<>
struct TFSGLogString<const FVector>
{
static void Format(const FVector& Value, FString& OutString)
{
OutString = Value.ToString();
}
};
template<>
struct TFSGLogString<FVector>
{
static void Format(const FVector& Value, FString& OutString)
{
OutString = Value.ToString();
}
};
template<>
struct TFSGLogString<const int8>
{
static void Format(const int8 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<int8>
{
static void Format(const int8 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<const int16>
{
static void Format(const int16 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<int16>
{
static void Format(const int16 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<const int32>
{
static void Format(const int32 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<int32>
{
static void Format(const int32 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<const int64>
{
static void Format(const int64 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<int64>
{
static void Format(const int64 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<const long double>
{
static void Format(const long double Value, FString& OutString)
{
char Buffer[128];
std::snprintf(Buffer, sizeof(Buffer), "%Lf", Value);
OutString = FString(UTF8_TO_TCHAR(Buffer));
}
};
template<>
struct TFSGLogString<long double>
{
static void Format(const long double Value, FString& OutString)
{
char Buffer[128];
std::snprintf(Buffer, sizeof(Buffer), "%Lf", Value);
OutString = FString(UTF8_TO_TCHAR(Buffer));
}
};
#if ! PLATFORM_ANDROID && PLATFORM_LINUX
template<>
struct TFSGLogString<const std::size_t>
{
static void Format(const std::size_t Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
#endif /* ! PLATFORM_ANDROID && PLATFORM_LINUX */
#if ! PLATFORM_ANDROID && PLATFORM_LINUX
template<>
struct TFSGLogString<std::size_t>
{
static void Format(const std::size_t Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
#endif /* ! PLATFORM_ANDROID && PLATFORM_LINUX */
template<>
struct TFSGLogString<const uint8>
{
static void Format(const uint8 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<uint8>
{
static void Format(const uint8 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<const uint16>
{
static void Format(const uint16 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<uint16>
{
static void Format(const uint16 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<const uint32>
{
static void Format(const uint32 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<uint32>
{
static void Format(const uint32 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<const uint64>
{
static void Format(const uint64 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<uint64>
{
static void Format(const uint64 Value, FString& OutString)
{
OutString = LexToString(Value);
}
};
template<>
struct TFSGLogString<const std::string>
{
static void Format(const std::string& Value, FString& OutString)
{
OutString = FString(UTF8_TO_TCHAR(Value.c_str()));
}
};
template<>
struct TFSGLogString<std::string>
{
static void Format(const std::string& Value, FString& OutString)
{
OutString = FString(UTF8_TO_TCHAR(Value.c_str()));
}
};
template<std::size_t L>
struct TFSGLogString<const wchar_t[L]>
{
static void Format(const wchar_t* Value, FString& OutString)
{
OutString = FString(StringCast<TCHAR>(Value).Get());
}
};
template<std::size_t L>
struct TFSGLogString<wchar_t[L]>
{
static void Format(const wchar_t* Value, FString& OutString)
{
OutString = FString(StringCast<TCHAR>(Value).Get());
}
};
template<>
struct TFSGLogString<const wchar_t*>
{
static void Format(const wchar_t* Value, FString& OutString)
{
OutString = FString(StringCast<TCHAR>(Value).Get());
}
};
template<>
struct TFSGLogString<wchar_t*>
{
static void Format(const wchar_t* Value, FString& OutString)
{
OutString = FString(StringCast<TCHAR>(Value).Get());
}
};
template<>
struct TFSGLogString<const std::wstring>
{
static void Format(const std::wstring& Value, FString& OutString)
{
OutString = FString(StringCast<TCHAR>(Value.data(), Value.size()).Get(), Value.size());
}
};
template<>
struct TFSGLogString<std::wstring>
{
static void Format(const std::wstring& Value, FString& OutString)
{
OutString = FString(StringCast<TCHAR>(Value.data(), Value.size()).Get(), Value.size());
}
};
class SENSEGLOVELOG_API FSGLogCore
{
public:
enum class EVerbosity : uint8
{
/** Always prints s fatal error to console (and log file) and crashes (even if logging is disabled) */
Fatal,
/**
* Prints an error to console (and log file).
* Commandlets and the editor collect and report errors. Error messages result in commandlet failure.
*/
Error,
/**
* Prints a warning to console (and log file).
* Commandlets and the editor collect and report warnings. Warnings can be treated as an error.
*/
Warning,
/** Prints a message to console (and log file) */
Display,
/** Prints a message to a log file (does not print to console) */
Log,
/**
* Prints a verbose message to a log file (if Verbose logging is enabled for the given category,
* usually used for detailed logging)
*/
Verbose,
/**
* Prints a verbose message to a log file (if VeryVerbose logging is enabled,
* usually used for detailed logging that would otherwise spam output)
*/
VeryVerbose,
};
enum class ECategory
{
Editor,
Generic,
};
private:
struct FStaticImpl;
struct FStaticImplDeleter
{
void operator()(const FStaticImpl* Pointer) const;
};
static TUniquePtr<FStaticImpl, FStaticImplDeleter> SPimpl;
struct FImpl;
struct FImplDeleter
{
void operator()(const FImpl* Pointer) const;
};
TUniquePtr<FImpl, FImplDeleter> Pimpl;
FImplDeleter PimplDeleter;
private:
FString Buffer;
bool bAnyEntries;
public:
FSGLogCore(const EVerbosity& Verbosity, const ECategory& Category, const std::string& File,
const std::string& Function, const int32 Line);
virtual ~FSGLogCore();
public:
template<typename T>
FSGLogCore& operator,(const T& Argument)
{
if (bAnyEntries)
{
Buffer += FString(TEXT(" • "));
}
FString FormattedArgument;
TFSGLogString<T>::Format(Argument, FormattedArgument);
Buffer += FormattedArgument;
bAnyEntries = true;
return *this;
}
};
/* Generic */
#define SGLOG_FATAL( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Fatal, FSGLogCore::ECategory::Generic, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_ERROR( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Error, FSGLogCore::ECategory::Generic, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_WARNING( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Warning, FSGLogCore::ECategory::Generic, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_DISPLAY( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Display, FSGLogCore::ECategory::Generic, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_LOG( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Log, FSGLogCore::ECategory::Generic, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_VERBOSE( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Verbose, FSGLogCore::ECategory::Generic, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_VERY_VERBOSE( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::VeryVerbose, FSGLogCore::ECategory::Generic, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Log, FSGLogCore::ECategory::Generic, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
/* Editor */
#define SGLOG_EDITOR_FATAL( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Fatal, FSGLogCore::ECategory::Editor, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_EDITOR_ERROR( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Error, FSGLogCore::ECategory::Editor, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_EDITOR_WARNING( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Warning, FSGLogCore::ECategory::Editor, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_EDITOR_DISPLAY( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Display, FSGLogCore::ECategory::Editor, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_EDITOR_LOG( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Log, FSGLogCore::ECategory::Editor, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_EDITOR_VERBOSE( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Verbose, FSGLogCore::ECategory::Editor, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_EDITOR_VERY_VERBOSE( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::VeryVerbose, FSGLogCore::ECategory::Editor, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;
#define SGLOG_EDITOR( ... ) \
(FSGLogCore(FSGLogCore::EVerbosity::Log, FSGLogCore::ECategory::Editor, __FILE__, __FUNCTION__, __LINE__)), __VA_ARGS__;