Как запустить SQL profiler trace, когда проблему надо ловить с 3:00 до 3:30 утра? Делать это можно с помощью трейса на стороне сервера, но это крайне неудобно. Именно не сложно, а неудобно, и всегда лень. Наконец я решился автоматизировать это раз и навсегда. Вот так:
Jenkins тут, кстати, совсем необязателен и служит лишь интерфейсом, чтобы вызвать скрипт с нужными параметрами:
Решение я покажу крупными мазками, все равно там много специфики, связанных именно с нашей инфраструктурой. То есть я выполню то, что показано слева:
Итак, bat файл кое что делает и переносит действие уже в PowerShell script, которому передает все параметры и еще две переменные — '%BUILD_USER_ID%','%BUILD_USER_EMAIL%' — полученные от Jenkins. Они нам пригодятся позднее:
Как ни странно, в самом ps1 мало что происходит действительно ценного: там вызывается некая процедура, которая по имени сервера создает и возвращает имя директории на специальной share, куда будет положен этот файл. Сервер, где будет создана эта директория зависит от datacenter, где находится сервер, на котором будет запущен трейс. Кроме того, юзеру выдаются права на чтение трейса, и есть процесс который через пару дней чистит эти директории. Как видите, вам это может не понадобится и все это вы можете спокойно пропустить.
Теперь действие переносится уже на сервер, где будет запущен трейс, в SQL файл. loc это как раз параметр, содержащий путь, куда будет скопирован готовый трейс. Вы можете заменить его константой.
Вначале мы должны найти место, куда будем писать трейс файл локально. Например, так:
Далее небольшая чистка. Вдруг такой файл уже есть или трейс ктото запустил раньше? Вам надо будет покверить sys.traces и остановить/удалить трейс пишущий в %jenkinsTraceSch%, если такой уже есть. Дальше создаем трейс (ограничьте его размер!) и немного занудства с вызовами sp_trace_setevent. Вы можете облегчить себе жизнь, сделав CROSS JOIN между events и columns:
Теперь добавим фильтры по вкусу. Тут как раз вы дорисовываете свою сову. Это первое место, где мы используем параметры скрипта — тип фильтра и имя базы:
Теперь пошел трэш:
В @j вы формируем команду для Job, которая будет:
- Ждать нужного времени с помощью WAITFOR
- Запускать трейс
- Выждать заказанное время
- Остановить трейс
- Подождать еще секунду на всякий случай — операции асинхронные
- Формировать команду на копирование трейса в нужное место
- Выполнять ее
- Формировать Subject и body письма
- Отправлять письмо заказчику через sp_send_dbmail со ссылкой на трейс
Теперь надо создать Job с шагом 1, описанным в @j. Однако я еще добавляю к этой Job самоубийство, чтобы джоба исчезала бесследно по завершении работы:
Я тут слышу крики про xp_cmdshell… Не хочу это комментировать. В конце концов, никто же не должен свидетельствовать на суде против самого себя. Но вы можете поступить иначе. Вряд ли у вас получится отправить трейс по почте — он большой. Хотя вы можете запаковать его. Ну или оставить его на самом сервере и предоставить юзеру забрать его самостоятельно или вытянуть по UNC в доступное для пользователя место
Итак, вы имеем:
- Jenkins вызывает bat
- bat вызывает powershell
- powershell вызывает скрипт SQL через sqlcmd
- Скрипт создает Job
- Job создает трейс и, перед самойбийством посылает почту:
Никогда бы не подумал, что такая длинная цепочка будет работать. Но она работает…
P.S.: И да, даже если xp_cmdshell запрещен и вы не можете его включить, у вас есть по крайней мере 2 способа написать my_xp_cmdshell. Так что эта «защита» не защищает ни от чего.
Автор: Tzimie