+ 1 для log4net.
Что касается (b), я склонен определять свои собственные пользовательские исключения (все они происходят из одного и того же базового класса, например, «BusinessException»), которые вызываются BLL для ошибок, которые необходимо сообщить пользователю (ввод данных нарушает бизнес-правило). , авторизация пользователя не удалась, ...). Если BLL развернут как веб-служба, такие исключения включаются в ошибку SOAP с кодом ошибки клиента (SOAP 1.1) / отправителя (SOAP 1.2).
Затем на уровне пользовательского интерфейса любое BusinessException или FaultException с FaultCode.IsSenderFault = true указывает, что сообщение об ошибке должно отображаться для конечного пользователя. Любые другие исключения регистрируются, и конечному пользователю показывается общее сообщение («что-то плохое произошло»).
Лично я считаю, что различение сообщений, которые должны быть показаны пользователю, может быть разумно осуществлено только в зависимости от приложения, как указано выше.
Относительно (c) вы могли бы написать пользовательское приложение log4net, которое отправляет серьезные ошибки вашему веб-сервису (возможно, асинхронно через MSMQ).
EDIT
В ответ на комментарий я не знаю ни одного стороннего фреймворка, который бы это делал; мы делаем это с помощью очень легкой внутренней структуры (которая также имеет другие базовые вещи, такие как тонкий API-модель провайдера, вокруг log4net, так что наш внутренний код не зависит явно от log4net, и мы сможем переключиться на другую каркас журналирования, если появится лучшее или если наше приложение развернуто на сайтах, где администраторы предпочитают другое).