All I want to do is pass a variable into the 3rd parameter of UE_LOG. No matter what I do, whether I pass an FString, const char*, or even a TCHAR*, it still complains.
UE_LOG(LogTemp, Warning, ???, FString(TEXT("text here")));
All I want to do is pass a variable into the 3rd parameter of UE_LOG. No matter what I do, whether I pass an FString, const char*, or even a TCHAR*, it still complains.
UE_LOG(LogTemp, Warning, ???, FString(TEXT("text here")));
If you read the documentation yourself, you’d see that it doesn’t answer my question.
My macro skills are weak. Passing a macro into a macro where the TEXT macro is putting an L in front of the “xxx” to make a unicode TCHAR array.
/**
* A macro that outputs a formatted message to log if a given logging category is active at a given verbosity level
* @param CategoryName name of the logging category
* @param Verbosity, verbosity level to test against
* @param Format, format text
***/
#define UE_LOG(CategoryName, Verbosity, Format, ...) \
{ \
static_assert(TIsArrayOrRefOfType<decltype(Format), TCHAR>::Value, "Formatting string must be a TCHAR array."); \
static_assert((ELogVerbosity::Verbosity & ELogVerbosity::VerbosityMask) < ELogVerbosity::NumVerbosity && ELogVerbosity::Verbosity > 0, "Verbosity must be constant and in range."); \
CA_CONSTANT_IF((ELogVerbosity::Verbosity & ELogVerbosity::VerbosityMask) <= ELogVerbosity::COMPILED_IN_MINIMUM_VERBOSITY && (ELogVerbosity::Warning & ELogVerbosity::VerbosityMask) <= FLogCategory##CategoryName::CompileTimeVerbosity) \
{ \
UE_LOG_EXPAND_IS_FATAL(Verbosity, PREPROCESSOR_NOTHING, if (!CategoryName.IsSuppressed(ELogVerbosity::Verbosity))) \
{ \
auto UE_LOG_noinline_lambda = ](const auto& LCategoryName, const auto& LFormat, const auto&... UE_LOG_Args) FORCENOINLINE \
{ \
TRACE_LOG_MESSAGE(LCategoryName, Verbosity, LFormat, UE_LOG_Args...) \
UE_LOG_EXPAND_IS_FATAL(Verbosity, \
{ \
FMsg::Logf_Internal(UE_LOG_SOURCE_FILE(__FILE__), __LINE__, LCategoryName.GetCategoryName(), ELogVerbosity::Verbosity, LFormat, UE_LOG_Args...); \
_DebugBreakAndPromptForRemote(); \
FDebug::ProcessFatalError(); \
}, \
{ \
FMsg::Logf_Internal(nullptr, 0, LCategoryName.GetCategoryName(), ELogVerbosity::Verbosity, LFormat, UE_LOG_Args...); \
} \
) \
}; \
UE_LOG_noinline_lambda(CategoryName, Format, ##__VA_ARGS__); \
UE_LOG_EXPAND_IS_FATAL(Verbosity, CA_ASSUME(false);, PREPROCESSOR_NOTHING) \
} \
} \
}
We use the following. The project is called “Sandbox”.
Put this in your ProjectName.h file:
// custom log category
DECLARE_LOG_CATEGORY_EXTERN(Sandbox, Log, All);
// custom log macro
#define LOG(x, ...) UE_LOG(Sandbox, Log, TEXT(x), __VA_ARGS__)
#define LOG_WARNING(x, ...) UE_LOG(Sandbox, Warning, TEXT(x), __VA_ARGS__)
#define LOG_ERROR(x, ...) UE_LOG(Sandbox, Error, TEXT(x), __VA_ARGS__)
Put this in your ProjectName.cpp file:
// custom log category
DEFINE_LOG_CATEGORY(Sandbox);
Now you can log like this anywhere you include “ProjectName.h”:
// simple text
LOG("Some stuff to put in the log");
// errors and warnings
LOG_WARNING("something bad happened!");
LOG_ERROR("something really bad happened!");
// log an fstring
LOG("AGameMode::ProcessLoadMapRequest(): %s", *requestedMapName);
// log int
LOG("AGameMode:: player %i has logged out!", playerId);
// log bool
bool myBool = false;
LOG("T or F? %s", *FString(myBool ? "True" : "False"));
// log multiple fstrings
FString cameraPos = cameraViewInfo.Location.ToString();
FString boomPos = _cameraBoom->GetComponentLocation().ToString();
LOG("AInteractiveCamera:: Camera:%s Boom:%s", *cameraPos, *boomPos);
This is about the simplest logging I’ve seen. If anyone knows of anything even more convenient please let us know.
this makes life easy, thank you very much for this
If someone get compile syntax error.
Use ##VA_ARGS instead of VA_ARGS in UE5
#define LOG(x, ...) UE_LOG(RTSGame, Log, TEXT(x), ##__VA_ARGS__)
#define LOG_WARNING(x, ...) UE_LOG(RTSGame, Warning, TEXT(x), ##__VA_ARGS__)
#define LOG_ERROR(x, ...) UE_LOG(RTSGame, Error, TEXT(x), ##__VA_ARGS__)
Hmm, just checked our UE5 code.
Looks like this “YourGame.h” file:
/**
* Custom log category.
* DECLARE_LOG_CATEGORY_EXTERN() in .h file.
* DEFINE_LOG_CATEGORY() in .cpp file.
*/
DECLARE_LOG_CATEGORY_EXTERN(MBT, Log, Log);
/**
* Custom logging macros.
*/
#define LOG(x, ...) UE_LOG(MBT, Log, TEXT(x), __VA_ARGS__)
#define LOG_FINE(x, ...) UE_LOG(MBT, Verbose, TEXT(x), __VA_ARGS__)
#define LOG_FINER(x, ...) UE_LOG(MBT, VeryVerbose, TEXT(x), __VA_ARGS__)
#define LOG_WARNING(x, ...) UE_LOG(MBT, Warning, TEXT(x), __VA_ARGS__)
#define LOG_ERROR(x, ...) UE_LOG(MBT, Error, TEXT(x), __VA_ARGS__)
And like this in “YourGame.cpp” file:
/**
* Custom log category.
* DECLARE_LOG_CATEGORY_EXTERN() in .h file.
* DEFINE_LOG_CATEGORY() in .cpp file.
*/
DEFINE_LOG_CATEGORY(MBT);
No pound signs needed that I am aware of? Is that a compiler other than Visual Studio? Or maybe not in Windows?
I compiled this on Windows with VS2022, probably because I’m using the engine source code version of UE5.31. The code for UE_LOG also utilizes ##VA_ARGS.
The way to log something dynamically with the UE_LOG
macro is by treating that third parameter as a format string, even if your format string is simply "%s"
.
If you’re not looking to create your own logging macros, this is how you would log the parameter of a function or some other FString
variable:
void UCheeseBacon::ShowDialogAndLogMessage(const FString& Message)
{
// Show dialog
UE_LOG(LogCheeseBacon, Display, TEXT("%s"), *Message);
}
There is no way to only pass 3 arguments to the UE_LOG
macro, even though FString
has publicly exposed methods that can provide the TCHAR
array the macro is looking for. It’s simply due to the way C++ macros work and the way this logging macro was written.