Вопрос очень интересный, попробую предложить решение, хотя не уверен, то ли это, что видится автору вопроса.
На мой взгляд, хороший логгер должен выводить весь путь вызовов к точке вывода
сообщения, наподобие вывода команды where в интерактивном отладчике gdb .
В принципе, такую информацию можно извлечь, совместно рассматривая стек выполнения
(там адреса возврата) и таблицу символов загрузочного модуля (там есть адреса точек входа в функции и их имена (конечно, если модуль не стрипнут). Для лабораторки это, конечно, крутовато.
Можно, наверное, предложить 'ручной' вариант. При входе в функцию, имя которой должно появиться в списке логгера, вызовем My_set_fname(fname), а для печати My_logger(message); fname ДОЛЖНА быть локальной переменной (располагаться в стеке программы).
My_set_fname(fname) будет вести свой стек (например, связанный список в куче или достаточно большой статический массив (собственно большой - это если My_set_fname() будут вызываться из рекурсии)). В этот стек надо помещать адрес параметра (fname). Здесь надо иметь в виду, что стек исполнения программы растет от больших адресов к меньшим, поэтому при очередном вызове My_set_fname() будем корректировать (путем удаления) верхнюю часть своего стека, так чтобы в нем содержались только адреса больше, чем адрес нашего аргумента. Эти соображения определяют требование к размещению аргумента.
Константы и куча не подходят.
Ну, логика My_logger(), по-моему, уже очевидна (или скажем так: формат вывода - дело вкуса).