Описанная вами потребность отлично подходит для события приложения / домена.
Когда пользователь входит в систему, должно возникать событие всего приложения, сигнализирующее о том, что событие (вход пользователя в систему) произошло. «Событие» - это сообщение, я всегда пишу их как пакеты данных без какого-либо поведения (ничего, кроме полностью открытых свойств), и я обычно заставляю их содержать весь контекст (данные), необходимый для обработчиков (который часто является просто единичным ID записи).
Отдельно напишите обработчик для события, который записывает соответствующую информацию в вашу базу данных. Обработчик должен быть классом с единственной ответственностью. Если в ответ на событие требуется выполнить больше действий, реализуйте их как отдельные обработчики.
Затем где-то при запуске приложения должны быть подключены обработчики для прослушивания событий приложения / домена.
Таким образом, для поддержки этого шаблона потребуется немного кода инфраструктуры, но это должен быть простой и короткий код, которому часто могут сильно помочь контейнеры DI / IoC. Существует также множество примеров реализаций, доступных, если вы регистрируете события в домене Google.
Этот шаблон событий приложений / доменов, как мне показалось, исключительно мощный. Использование этого шаблона значительно улучшило мой код. Я считаю, что гораздо проще расширить поведение систем без изменения любого существующего кода, и это поведение инкапсулируется благодаря наличию в вашем примере четкого места для кода, который регистрирует пользователя, и кода который записывает статистику о логинах приложений.
Наконец, я бы не использовал Log4Net для этого. Если вы реализуете событие, обработчик должен быть предельно простым и понятным, но если вы попытаетесь использовать Log4Net для поддержки настойчивости, ну ... похоже, вы в конечном итоге будете бороться со своим инструментом (Log4Net) хотя бы до некоторой степени. степень - и этого можно полностью избежать, просто не используя его.