It would help if you stated what language you are using...
If you're using managed code... be wary of the limitations (below quoted from the WiX documentation)
Before choosing to write a custom action in managed code instead of traditional native C++ code, you should carefully consider the following:
Obviously, it introduces a dependency on the .NET Framework. Your MSI package should probably have a LaunchCondition to check for the presence of the correct version of the .NET Framework before anything else happens.
If the custom action runs at uninstall time, then even the uninstall of your product may fail if the .NET Framework is not present. This means a user could run into a problem if they uninstall the .NET Framework before your product.
A managed custom action should be configured to run against a specific version of the .NET Framework, and that version should match the version your actual product runs against. Allowing the version to "float" to the latest installed .NET Framework is likely to lead to compatibility problems with future versions. The .NET Framework provides side-by-side functionality for good reason -- use it.
Additionally, you should also read why VBScript (and JScript) MSI CustomActions suck
Anyway, ignoring all that... here's some sample C++ code that I found somewhere a long time ago that I use for logging. You might be able to figure out the correct functions that should be called in your chosen language.
#define _USE_RTM_VERSION
void LogString(MSIHANDLE hInstall, TCHAR* szString)
{
PMSIHANDLE newHandle = ::MsiCreateRecord(2);
TCHAR szTemp[MAX_PATH * 2];
sprintf_s(szTemp, MAX_PATH * 2, "-- MSI_LOGGING -- %s", szString);
MsiRecordSetString(newHandle, 0, szTemp);
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_INFO), newHandle);
}
UINT __stdcall MyCustomAction ( MSIHANDLE hModule )
{
LogString(hModule, "Whoa! I am a custom action..");
return ERROR_SUCCESS;
}