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.