Easier Logging Macro

Logging can be quite cumbersome to type every time, like:
UE_LOG(LogTemp, Warning, TEXT("Your message"));

It is easier to remember and faster to type like this:
GAME_LOG("Your message");
GAME_WARN("Your warning");
GAME_ERROR("Your error");
GAME_SCREENLOG("Your screen message");

To setup something like that, here’s how I’ve done it:

First, open the project main .h file (like BattleTank.h) and add this:

#if UE_BUILD_DEVELOPMENT

#define GAME_LOG_DEFINED 1

DECLARE_LOG_CATEGORY_EXTERN(GameLog, Log, All);

#define NETMODE_WORLD (((GEngine == nullptr) || (GetWorld() == nullptr)) ? TEXT("") \
        : (GEngine->GetNetMode(GetWorld()) == NM_Client) ? TEXT("[Client]") \
        : (GEngine->GetNetMode(GetWorld()) == NM_ListenServer) ? TEXT("[ListenServer]") \
        : (GEngine->GetNetMode(GetWorld()) == NM_DedicatedServer) ? TEXT("[DedicatedServer]") \
        : TEXT("[Standalone]"))

#if _MSC_VER
#define FUNC_NAME    TEXT(__FUNCTION__)
#else // FIXME - GCC?
#define FUNC_NAME    TEXT(__func__)
#endif

#define GAME_LOG(Message, ...) \
{ \
	const FString Msg = FString::Printf(TEXT(Message), ##__VA_ARGS__); \
	UE_LOG(GameLog, Log, TEXT("::::::: %s %s : %s :::::::"), NETMODE_WORLD, FUNC_NAME, *Msg); \
}

#define GAME_SCREENLOG(Message, ...) \
{ \
	const FString Msg = FString::Printf(TEXT(Message), ##__VA_ARGS__); \
	GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::White, Msg); \
}

#define GAME_WARN(Message, ...) \
{ \
	const FString Msg = FString::Printf(TEXT(Message), ##__VA_ARGS__); \
	UE_LOG(GameLog, Warning, TEXT("::::::: %s %s : %s :::::::"), NETMODE_WORLD, FUNC_NAME, *Msg); \
	GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Yellow, Msg); \
}

#define GAME_ERROR(Message, ...) \
{ \
	const FString Msg = FString::Printf(TEXT(Message), ##__VA_ARGS__); \
	UE_LOG(GameLog, Error, TEXT("::::::: %s %s : %s :::::::"), NETMODE_WORLD, FUNC_NAME, *Msg); \
	GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, Msg); \
}

#define GAME_HALT(Message, ...) \
{ \
	const FString Msg = FString::Printf(TEXT(Message), ##__VA_ARGS__); \
	UE_LOG(GameLog, Fatal, TEXT("====== %s %s : %s ======"), NETMODE_WORLD, FUNC_NAME, *Msg); \
}

#else
#define GAME_LOG(Message, ...)
#define GAME_SCREENLOG(Message, ...)
#define GAME_WARN(Message, ...)
#define GAME_ERROR(Message, ...)
#define GAME_HALT(Message, ...)
#endif

Now, open the .cpp file (BattleTank.cpp) and write:

#if GAME_LOG_DEFINED
DEFINE_LOG_CATEGORY(GameLog);
#endif

And that’s it!
I made the warn and the error logs to also print to the screen to make sure I don’t miss them since they are important.

Another advantage to this setup is that the file and the line number from where the log is coming will also be printing, along side with the current netmode.

Having your own log category will make it easier to spot your message and you can filter for them by typing GameLog in the search field.

I wanted to have a custom color for the logs, but the documented way of doing that doesn’t work anymore unfortunately. So, I’ve added a bunch of “:::::” to the message to make it easier to find them along the engine own logs.

All this was possible by reading these tutorials:
https://wiki.unrealengine.com/Logs,_Printing_Messages_To_Yourself_During_Runtime
https://wiki.unrealengine.com/Log_Macro_with_Netmode_and_Colour

3 Likes

Thank you, I will consider either this, or using code snippets or a text expansion tool like Phrase Express to expand

UE_LOG(

into

UE_LOG(LogTemp, Warning, TEXT())

ready to be filled in.

Lifesaver thanks. Making C++ coding in Unreal a bit more comfortable, although it still feels as a bed of nails. I guess once you reach jedi status you can turn the nails into marshmallows :stuck_out_tongue: