Skip to content

Instantly share code, notes, and snippets.

@Solessfir
Last active April 14, 2023 16:08
Show Gist options
  • Save Solessfir/eb0df57297f8a61f0c598629b0a78865 to your computer and use it in GitHub Desktop.
Save Solessfir/eb0df57297f8a61f0c598629b0a78865 to your computer and use it in GitHub Desktop.
Unreal Engine Advanced Log with automatic type deduction
#pragma once
/** Current Class and Line Number where this is called */
#define LOG_FUNC_LINE (FString(__FUNCTION__) + " (Line: " + FString::FromInt(__LINE__) + ")")
/**
* Usage:
* ADVANCED_LOG("Actor name is: {0}", AnyActorPointer);
* No need for GetName() or ToString(), etc. Type will be automatically deduced
*/
#define ADVANCED_LOG(Format, ...) AdvancedLog(ELogVerbosity::Display, LOG_FUNC_LINE, TEXT(Format), ##__VA_ARGS__)
#define ADVANCED_WARNING(Format, ...) AdvancedLog(ELogVerbosity::Warning, LOG_FUNC_LINE, TEXT(Format), ##__VA_ARGS__)
#define ADVANCED_ERROR(Format, ...) AdvancedLog(ELogVerbosity::Error, LOG_FUNC_LINE, TEXT(Format), ##__VA_ARGS__)
/** Templates for Logging */
template<typename T, typename = int>
struct THasToString : std::false_type {};
template<typename T>
struct THasToString<T, decltype(std::declval<T>().ToString(), 0)> : std::true_type {};
template<typename T, typename = int>
struct THasActorNameOrLabel : std::false_type {};
template<typename T>
struct THasActorNameOrLabel<T, decltype(std::declval<T>()->ActorNameOrLabel(), 0)> : std::true_type {};
template<typename T, typename = int>
struct THasGetName : std::false_type {};
template<typename T>
struct THasGetName<T, decltype(std::declval<T>()->GetName(), 0)> : std::true_type {};
template<typename T, typename = int>
struct THasLexToString : std::false_type {};
template<typename T>
struct THasLexToString<T, decltype(LexToString(std::declval<T>()), 0)> : std::true_type {};
template<typename... T>
void FillArgs(FStringFormatOrderedArguments& Arguments, T&&... Parameters)
{
([&]<typename F>(F&& Argument)
{
if constexpr (std::is_constructible_v<FStringFormatArg, F>)
{
Arguments.Add(Forward<F>(Argument));
}
else if constexpr (THasToString<F>::value)
{
Arguments.Add(Argument.ToString());
}
else if constexpr (THasActorNameOrLabel<F>::value)
{
Arguments.Add(Argument->ActorNameOrLabel());
}
else if constexpr (THasGetName<F>::value)
{
Arguments.Add(Argument->GetName());
}
else if constexpr (THasLexToString<F>::value)
{
Arguments.Add(LexToString(Forward<F>(Argument)));
}
else
{
static_assert(std::is_void_v<F> && false);
}
}
(Forward<T>(Parameters)), ...);
}
template<typename... T>
void AdvancedLog(const ELogVerbosity::Type Verbosity, const FString Log, const TCHAR* Format, T&&... Arguments)
{
FStringFormatOrderedArguments OrderedArguments;
FillArgs(OrderedArguments, Forward<T>(Arguments)...);
const FString Message = FString::Format(Format, MoveTemp(OrderedArguments));
switch (Verbosity)
{
case ELogVerbosity::Display:
{
if (GEngine && GAreScreenMessagesEnabled)
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::White, Message);
}
UE_LOG(LogTemp, Display, TEXT("%s | %s"), *Message, *Log)
break;
}
case ELogVerbosity::Warning:
{
if (GEngine && GAreScreenMessagesEnabled)
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Orange, Message);
}
UE_LOG(LogTemp, Warning, TEXT("%s | %s"), *Message, *Log)
break;
}
case ELogVerbosity::Error:
{
if (GEngine && GAreScreenMessagesEnabled)
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Red, Message);
}
UE_LOG(LogTemp, Error, TEXT("%s | %s"), *Message, *Log)
break;
}
default:;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment