Displaying Logs: Unreal Engine 4

This post is a continuation of the series where we are looking into creating a C++ plugin that is meant to store data in SQLite3 database for both Unity3D and Unreal Engine 4.

In the previous post, we have set up the plugin DLL such that we can register a delegate that can be invoked from the plugin when a log needs to be sent to Unity3D project.

We have already imported the C++ DLL into the project in an earlier post in the series. We will use the same project to import the new DLL.

Import DLL

Let’s start by opening the Unreal Project from the earlier post. If you don’t have it already you can even download the project from the repository. We will now need to replace the DLL in the “DataStorageSample\Plugins\DataStorage” folder from the newly created DLL with logging class from the previous post. If you are unsure about where to get the DLL from or how it needs to be imported check out the “Import the Plugin” section from this post.

Create Delegate to Receive and Print Logs

First, we start by defining the function pointer that will be invoked by the DLL whenever it needs to send a log to the engine. Let’s add this definition in the header file cDataStorageWrapper.h

typedef std::function<void(int, const char*)> LogCallback;

The function pointer defines a function that will receive an integer value which contains the information regarding the type of the log. We will mirror the enum that was defined in the plugin this will help with the readability of code on both sides. Let’s define the enum in the same header file: cDataStorageWrapper.h

UENUM()
enum class eLogType : uint8
{
	iLOG = 0,
	iWARNING = 1,
	iERROR = 2
};

The other argument will contain the message that is being sent from the DLL which we will print to the output window later in the tutorial.

Register For Logs

Let’s now start with importing the function that we will use to register the delegate with the DLL. So we can start receiving the logs.

First, we will begin by defining the function in the cDataStorageWrapper.h header file. The explanation for all of this is in a lot more detail in the earlier post. Please read through that for more details.

typedef void(*__RegisterForLogs)(LogCallback a_delOnLogGenerated);

Next, we create a pointer to this function and declare the functions that will be used to import the functions from the DLL. We will also need a method that will register the delegate with the plugin. The definitions to these are shown below. These need to be added in the cDataStorageWrapper.h header file.

//Pointer to the function exposed in the DLL
__RegisterForLogs m_funcRegisterForLogs;

//Method to import the function from the plugin
UFUNCTION(BlueprintCallable, Category = "CPP Utilities")
		bool ImportMethod_RegisterForLogs();

//Method registers the delegate with the DLL
UFUNCTION(BlueprintCallable, Category = "CPP Utilities")
		void RegisterForLogs();

Let’s now look into the implementation of these methods in the cpp file cDataStorageWrapper.cpp. Here is the import method and this is same as the earlier post.

bool UcDataStorageWrapper::ImportMethod_RegisterForLogs()
{
	if (v_dllHandle != NULL)
	{
		m_funcRegisterForLogs = NULL;
		FString procName = "RegisterForLogs";	// Needs to be the exact name of the DLL method.
		m_funcRegisterForLogs = (__RegisterForLogs)FPlatformProcess::GetDllExport(v_dllHandle, *procName);
		if (m_funcRegisterForLogs != NULL)
		{
			return true;
		}
	}
	return false;	// Return an error.
}

Here is the implementation of the RegisterForLogs method. In this menthod we see what happens when the delegate is invoked by the DLL.

void UcDataStorageWrapper::RegisterForLogs()
{
	if (m_funcRegisterForLogs == NULL)
	{
		UE_LOG(LogTemp, Error, TEXT("Register for Logs function was not initialized"));
		return;
	}

	m_funcRegisterForLogs([=](int a_iLogType, const char* a_strLog)
	{
		FString strLog(a_strLog);
		eLogType type = (eLogType)a_iLogType;
		switch (type)
		{
		case eLogType::iLOG:
			UE_LOG(LogTemp, Log, TEXT("%s"), *strLog);
			break;
		case eLogType::iWARNING:
			UE_LOG(LogTemp, Warning, TEXT("%s"), *strLog);
			break;
		case eLogType::iERROR:
			UE_LOG(LogTemp, Error, TEXT("%s"), *strLog);
			break;
		default:
			break;
		}

	});
}

The delegate for now only prints the received log into the output window. Based on the type of the message received, either a log, warning or error is printed in the output window.

Now everything is set up in the wrapper class. All that is left to do next is to call the methods and check the output window. In the game instance class that we have created in the earlier post, we add the following lines of code in the “ImportDataStorageLibrary” method.

if (!m_refDataStorageUtil->ImportMethod_RegisterForLogs())
{
	UE_LOG(LogTemp, Error, TEXT("Could not import the RegisterForLogs Method from the Data Storage Library"));
	return false;
}

m_refDataStorageUtil->RegisterForLogs();

That is it! We can now hit play in the editor to see the log that is added in the SumOf function in the DLL. You should see the output as shown below.

Log displayed in Output window of the editor

You can download the entire source code from the repository here.

6 thoughts on “Displaying Logs: Unreal Engine 4

Leave a Reply to dliubash Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.