SDL_LOG_CATEGORY_ERROR makes message not appear in the terminal.

Hi! I wanted to use a SDL replacement for fprintf(stderr,..), so I decided to use SDL_LogError(SDL_LOG_CATEGORY_ERROR,...) hoping that it would output to stderr if available. Looking at the code, I think I saw for some platform that it uses fprintf.

But there was no output in my terminal.

To check, I used SDL_Log(), and it outputted “INFO: Message”. After deducing it uses a different category and priority, I started blindly checking where the problem is.

I used SDL_LogMessage() with random combinations, and saw that SDL_LOG_CATEGORY_ERROR does not make output appear in the terminal, and
SDL_LOG_CATEGORY_APPLICATION, and SDL_LOG_CATEGORY_ASSERT do. SDL_LOG_CATEGORY_SYSTEM doesn’t.

Now, can you tell me what’s wrong, and where I can find info about these things which will explain to me what is wrong?

Thank you!

If you’re using SDL_Log from your application then I think you’re supposed to use SDL_LOG_CATEGORY_APPLICATION. The priority controls whether or not the message should be printed, with VERBOSE being the lowest priority, and CRITICAL being the highest.

The idea seems to be that you can write your code logging anything and everything, and then at runtime adjust the priority of SDL_LOG_CATEGORY_APPLICATION to control just how much output your app actually prints out. Like if the user passes a “–verbose” command line flag or something.

// APPLICATION category default priority is INFO, so this will print
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "Something went wrong!\n");
// Change APPLICATION category's priority so nothing with that category below CRITICAL will print
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_CRITICAL);
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "You won't see this message!");

There are also helper functions for individual priorities, so you can do

SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, "Some junk nobody cares about\n");
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Uh-oh!\n");
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "HAIR IS ON FIRE!\n");

There’s more info on the Wiki and in SDL_log.h

Thanks. I didn’t realize that it works like that.
I did a little research:

printf( "APPLICATION: %d\n"
            "ERROR: %d\n"
            "ASSERT: %d\n"
            "SYSTEM: %d\n"
            "AUDIO: %d\n"
            "VIDEO: %d\n"
            "RENDER: %d\n"
            "INPUT: %d\n"
            "TEST: %d\n",
            (int)SDL_LogGetPriority(SDL_LOG_CATEGORY_APPLICATION),
            (int)SDL_LogGetPriority(SDL_LOG_CATEGORY_ERROR),
            (int)SDL_LogGetPriority(SDL_LOG_CATEGORY_ASSERT),
            (int)SDL_LogGetPriority(SDL_LOG_CATEGORY_SYSTEM),
            (int)SDL_LogGetPriority(SDL_LOG_CATEGORY_AUDIO),
            (int)SDL_LogGetPriority(SDL_LOG_CATEGORY_VIDEO),
            (int)SDL_LogGetPriority(SDL_LOG_CATEGORY_RENDER),
            (int)SDL_LogGetPriority(SDL_LOG_CATEGORY_INPUT),
            (int)SDL_LogGetPriority(SDL_LOG_CATEGORY_TEST)    
    );

And got the results:
APPLICATION: 3
ERROR: 6
ASSERT: 4
SYSTEM: 6
AUDIO: 6
VIDEO: 6
RENDER: 6
INPUT: 6
TEST: 1

It is very weird how none of them are defaulted to their respective number, so the SDL_LogError() function is basically useless for printing errors unless you change the priority of the error category.

Is it possible that this is a bug? Because it makes no sense to me.

What do you mean by “defaulted to their respective number”?

Like I said, for messages generated by your own application use SDL_LOG_CATEGORY_APPLICATION. For errors, for warnings, for debug, for everything. The rest of the categories are used by SDL internally, and if you change their priority you’ll also see a bunch of stuff from SDL (try SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE); if you want to see). So the category is more like “Where does the message come from?”

The priority is how you specify what kind of message it is / how severe it is. That way you can decide at run time how much logging your application actually does, by changing the priority of the SDL_LOG_CATEGORY_APPLICATION category.

So you could have a bunch of stuff like

SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Value of X is %d\n", x);
SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, "Loading level %d\n", levelNumber);
// Oops level loading failed
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Level loading failed!\n");

And set APPLICATION category’s priority to DEBUG when testing, and then raise it to ERROR or CRITICAL when shipping. You could even have a command line option (say, --log-level) that lets users specify what priority the APPLICATION category should be set to, so you can ask users to set it to DEBUG and attach the log output when submitting a bug report.

Take a peek inside SDL_log.h

I wrote this demo app to show how to do it.

/* build this with
   cc log.c -o log `sdl2-config --cflags --libs`

   run with
   ./log -l <loglevel>

   And you will only see log messages that are at least that priority.
*/

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>

#include <SDL2/SDL.h>

static void setLogPriority(const char *arg);

int main(int argc, char **argv)
{
	(void)SDL_Init(SDL_INIT_VIDEO);

	int option;
	while((option = getopt(argc, argv, "l:")) != -1) {
		switch(option) {
		case 'l':
			setLogPriority(optarg);
			break;
		case '?':
			fprintf(stderr, "unknown option '%c'\n", optopt);
			break;
		}
	}

	/* These are all in the APPLICATION category, but we can still log errors etc */
	SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Critical\n");
	SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error\n");
	SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning\n");
	SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Info\n");
	SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Debug\n");
	SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, "Verbose\n");

	SDL_Quit();
	return 0;
}

static void setLogPriority(const char *arg)
{
	SDL_LogPriority priority = SDL_LOG_PRIORITY_VERBOSE;

	if(strncasecmp("debug", arg, strlen("debug")) == 0) {
		priority = SDL_LOG_PRIORITY_DEBUG;
	} else if(strncasecmp("info", arg, strlen("info")) == 0) {
		priority = SDL_LOG_PRIORITY_INFO;
	} else if(strncasecmp("warn", arg, strlen("warn")) == 0) {
		priority = SDL_LOG_PRIORITY_WARN;
	} else if(strncasecmp("error", arg, strlen("error")) == 0) {
		priority = SDL_LOG_PRIORITY_ERROR;
	} else if(strncasecmp("critical", arg, strlen("critical")) == 0) {
		priority = SDL_LOG_PRIORITY_CRITICAL;
	}

	SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, priority);
}

For the record

I don’t use SDL’s logging stuff. Wrote my own system than logs everything to disk on a separate thread, so if the user has a problem they can just send me the log file.