Troubleshooting PubNub POSIX C SDK

How to enable logging

C-core has a simple and efficient, yet flexible logging system. There are several levels from which to choose. Also, the user can set the function that will do the actual writing of data to an output.

Log LevelPreprocessor SymbolDescription
nonePUBNUB_LOG_LEVEL_NONEall checks disabled
errorsPUBNUB_LOG_LEVEL_ERRORonly errors reported
warningsPUBNUB_LOG_LEVEL_WARNINGignored invalid conditions are reported, too
regularPUBNUB_LOG_LEVEL_INFOsignificant events reported, too
debugPUBNUB_LOG_LEVEL_DEBUGvarious reports useful in debugging reported, too
detailPUBNUB_LOG_LEVEL_TRACEall logs enabled (compiled in)

To choose a level, define preprocessor symbol PUBNUB_LOG_LEVEL to one of the symbols from the table above. If you don't define it, the default used is PUBNUB_LOG_LEVEL_INFO.

You will see that some of our samples Makefiles define this symbol and some don't, depending on their purpose.

Keep in mind that debug and detail levels produce a lot of output that is hard to decypher by the uninitiated. So, it's best to use them only when looking for causes of some bugs - for example, if you report a suspected issue to Pubnub support.

Even though C-core logging system is designed for its own purpose, you're free to use it in your code too, if it suits your needs. The interface is in the pubnub_log.h header.

The actual writing of the log reports to an output is done by using the preprocessor macro PUBNUB_LOG_PRINTF - define it to have printf-like semantics. If you don't define this symbol, the default used is printf. For example, here's a simple way to define a function that will output (append) to a file:

int my_logger(char const *fmt, ...)
{
va_list args;
int result;
FILE *f = foppen("mylog.txt", "at");
if (NULL == f) {
return -1;
}
va_start(args, fmt);
result = vfprintf(f, fmt, args);
va_end(args);
fclose(f);

return result;
}

At some header or in the makefile or project define PUBNUB_LOG_PRINTF to this function, for example:

#define PUBNUB_LOG_PRINTF my_logger

Using the PUBNUB_ASSERT subsystem

C-core has its own ASSERT module/subsystem. It's interface is in the header pubnub_assert.h. It is used in C-core modules themselves, but you can also use it in your code if you wish. It provides several levels of ASSERTs:

LevelPreprocessor SymbolDescription
highestPUBNUB_ASSERT_LEVEL_EXAll checks enabled (compiled).
regularPUBNUB_ASSERT_LEVELOnly the long lasting checks are disabled, other are compiled.
lowestPUBNUB_ASSERT_LEVEL_OPTOnly the checks with negligible execution length are enabled.
nonePUBNUB_ASSERT_LEVEL_NONEAll checks disabled.

The default level is regular, and that is the level used in our sample Makefiles.
So, if you want the highest level for troubleshooting, define PUBNUB_ASSERT_LEVEL_EX preprocessor symbol when compiling. Also, if you want to troubleshoot performance by disabling checks, define PUBNUB_ASSERT_LEVEL_NONE.

Also, you can control what happens when an assertion fails. To do that, you set a callback function to be called, by using pubnub_assert_set_handler(), which should be called as early as possible in the execution of your program.

There are a few ready-made handlers which you can use and the default is pubnub_assert_handler_abort, which provides a similar operation as the C standard assert() macro - prints a report of the place and expression of the assertion and then aborts.

If you wish to provide your own handler, you need to define a function that conforms to the following typedef:

typedef void (*pubnub_assert_handler_t)(char const *s, char const *file, long line);

For example:

void dbg_break_assert_handler(char const *s, char const *file, long line)
{
printf("Will hit breakpoint for '%s' in %s line %d\n", s, file, line);
BREAK_IN_DEBUGGER; /* assuming you have such a macro */
}
Last updated on