Банановый улов
Вы можете ловить исключения с помощью try-catch
и передавать / выбрасывать их во внешнюю область видимости, где должны существовать такие же вещи.Это, кстати, позволяет собирать call-stack
.Это решение может быть реализовано, если вы работаете только через сохраненные программы.Каждый процесс должен иметь такой шаблон:
begin try
end try
begin catch
if @@trancount > 0
rollback
insert into <log> (...)
values (...)
throw
end catch
Таким образом, самая верхняя процедура успешно вставит строку в таблицу журнала.
Минусы:
- с глубокимиерархия - слишком много «фиктивных» вставок для отката
- все еще возможно ничего не регистрировать, если:
- серьезность слишком высока
- SP не соответствует этому шаблону
- есть внешнее / "клиентское" управление транзакциями
Плюсы:
- Не идеально, но выполнимо и не слишкомтрудно реализовать.
Обратная связь:
- Я использовал этот подход на производственном сервере небольшого проекта, собирал стек вызовов и так далее.Это было бэк-офисное программное обеспечение с ~ 50-100 онлайн-пользователями, с некоторым количеством работающих роботов, далеко не "высоконагруженным".Работало нормально, помогло исправить многие проблемы.Накладные расходы никого не беспокоили.
неуловимый бандит
Вы можете создать CLR-сборку, которая вставляется в таблицу журнала и ничего более ... Но!Можно указать отдельное соединение, чтобы эта сборка работала с БД через это отдельное соединение.Что означает - в отдельной области.Таким образом, метод этой сборки вызывается из транзакции, однако выполняется независимо от области транзакции.
Таким образом, вместо:
using(SqlConnection connection = new SqlConnection("context connection=true"))
просто укажите обычную строку соединения.После его вызова - сгенерируйте исключение с измененным ERROR_STATUS
, чтобы избежать дополнительной регистрации той же ошибки.
begin try
end try
begin catch
if @@trancount > 0
rollback
if @@ERRROR_STATUS != @done_with_logging
exec asm.log(...)
raiserror @err_msg, @severity, @done_with_logging
end catch
Минусы:
- может привести к проблемам в пуле соединений
- немного более длинный способ получить тривиальную вставку
- может вызвать дополнительные проблемы, связанные с установлением соединения и самой сборки (+ разрешения, владение и т. д.)
Плюсы:
- идея немного волнующая
- может войти в файл вместо db
Обратная связь:
- Я не могупомните, использовал ли я этот подход на prod (хотя я вспоминаю это как более недавний опыт ... или просто как попытку реализовать это в целях тестирования)
knock, knock, admin
Этот простой оператор (на самом деле это просто дополнительная опция WITH LOG
) запишет любое сообщение об ошибке, которое вы хотите, в журнал событий SQL SERVER:
RAISERROR(...) WITH LOG
Это не тот способ, которым SQL SERVERЖурнал должен быть использован, но это самый быстрый способзаписать что-то важное (для разрешения проблемы).Записанное событие можно просмотреть в окнах агента SSMS.
Минусы:
- могут быть соображения относительно разрешений
- плохой поиск и нулевые возможности настройки
- dba возненавидит вас (если он, конечно, будет проверять журналы сервера)
Плюсы:
Обратная связь:
- Я сталкивался с таким способом регистрации только в одной компании.Я предполагаю, что некоторое время назад он использовался несколькими разработчиками для выявления незначительных ошибок, но позже получил распространение по всему коду и стал «стандартом».Итак, через некоторое время стало почти невозможно найти что-то конкретное в журнале событий ... и фактически лишь немногие коллеги имели доступ к журналу сервера Prod.Так что буквально а) вредно б) бесполезно.Так что я избавился от этого из управляемой части системы, как только нашел время для.
летающего голландца
{места для основанных на мнении разговоров о построении системы на основеТриггеры DML}
Мне кажется, что вы не используете хранимые процедуры в своем проекте и вместо этого выполняете специальные запросы.Если у вас есть бэкэнд-приложение с ORM или чем-то в этом роде - напишите в него лог.Более того, возможно, это бэкэнд-приложение - лучшее место, чтобы делать то, что вы делаете внутри этого триггера.
Если ваш проект представляет собой клиент-серверное приложение без приложения appserver / backend, и все, что у вас есть, - это специальный запрос итриггер, то не так много данных для входа.Нет стека вызовов (на стороне сервера).И будет трудно определить, как вы (пользователь, приложение) пришли к этому конкретному исключению.Таким образом, регистрация на стороне клиента может быть более полезной в этом случае.