Инженер диагностики рано или поздно встречается с ситуацией, когда приложение упало, пользователь ничего внятного сказать не может, а единственный след происшествия лежит в журнале событий и в паре файлов, оставленных службой Windows Error Reporting. Эта служба, известная по сокращению WER, пришла на смену доктору Ватсону ещё во времена Windows XP и с тех пор тихо собирает факты о каждом необработанном исключении в системе. Понимание того, что именно она фиксирует, куда отправляет и где хранит локальные копии, превращает мистику случайных падений в обычную инженерную задачу с воспроизводимой методикой. Дальше разбирается устройство конвейера отчётов о сбоях, содержимое мини-дампов, механика отправки, границы приватности, управление через реестр и практическая гигиена каталогов с дампами, чтобы читатель мог уверенно работать с этим материалом на любой машине под своей ответственностью.

От доктора Ватсона до современного конвейера отчётов

Доктор Ватсон в Windows NT и Windows 2000 был простым отладчиком постмортем, который при фатальной ошибке процесса записывал текстовый журнал и мог снять дамп памяти. Инструмент решал локальную задачу и ничего никуда не передавал. С выходом Windows XP появилась инфраструктура отчётов об ошибках, а пользователь начал видеть знаменитый диалог с предложением отправить сведения в Microsoft. Этот диалог стал визитной карточкой эпохи: система спрашивала разрешения, и человек нажимал кнопку либо отказывался, после чего отчёт умирал локально.

Современный WER в Windows 10 и Windows 11 устроен иначе. Диалогов с вопросами почти не осталось, потому что политика сбора диагностических данных перевела большинство отчётов в разряд агрегированной телеметрии. Служба Wermgr и библиотека WerFault перехватывают необработанное исключение, формируют пакет сведений и ставят его в очередь. Смысл отправки изменился концептуально: данных не ищут конкретного виновника на конкретной машине, а собирают статистику встречаемости. Если тысяча установок одной версии драйвера падает в одной точке кода, этот сбой получает высокий приоритет в очереди исправлений. Одиночный экзотический крах может не получить реакции вовсе, и это осознанная экономика внимания, а не небрежность.

Отчёт проходит через стадии классификации. Система вычисляет сигнатуру сбоя из имени приложения, версии, имени модуля, его версии и смещения инструкции, вызвавшей исключение. Эта сигнатура видна в журнале событий под именем параметров P1 через P10. По ним серверная сторона понимает, известен сбой или нов, есть ли для него исправление и стоит ли запросить у машины дополнительный дамп. Таким образом пользовательский отчёт превращается в точку на графике надёжности, а накопленный массив точек определяет, какие дефекты чинятся в ближайшем обновлении.

Как устроен путь отчёта от сбоя до сервера

Механика конвейера заслуживает отдельного взгляда, потому что именно она объясняет, почему одни крахи оставляют богатый след, а другие исчезают бесследно. Когда поток процесса совершает недопустимую операцию, ядро передаёт управление обработчику необработанных исключений. Системный обработчик запускает WerFault как отдельный процесс, чтобы сбор сведений не зависел от уже повреждённого адресного пространства погибающего приложения. WerFault читает память жертвы извне, формирует временный отчёт в каталоге очереди и решает по политике, что делать дальше: молча отправить, спросить пользователя или просто заархивировать локально. Разделение на живой сборщик и мёртвую цель это ключевая инженерная идея, унаследованная ещё от доктора Ватсона, который тоже запускался как внешний отладчик.

Политика согласия определяется уровнем диагностических данных, выбранным при настройке системы или заданным администратором через параметр AllowTelemetry в ветке реестра DataCollection. На минимальном уровне отчёты покидают машину в урезанном виде, на расширенном допускается передача мини-дампов, а корпоративные политики способны перенаправить весь поток на внутренний сервер организации через параметр CorporateWERServer. Последний вариант используется в закрытых сетях: отчёты складываются на общий файловый ресурс, откуда их забирают собственные аналитики. Для инженера это означает простую проверку: если отчёты не уходят, сначала смотрят на политику согласия и только потом на сеть.

Отдельного упоминания стоят .wer файлы в каталогах очереди. Это открытый текст в формате пар ключ значение, где записаны версия операционной системы, сигнатура сбоя, пути модулей и имена вложений. Файл читается обычным блокнотом и даёт быстрый ответ на вопрос, был ли сбой в коде приложения, в сторонней библиотеке или в системном модуле. Когда файл сопровождается вложением internalreport с расширением .mdmp, появляется материал для полноценного отладочного сеанса. Связка текстового описания и двоичного слепка делает каталог WER самодостаточным архивом инцидента, и грамотный диагност начинает расследование именно с него, а не с воспроизведения сценария вслепую.

Анатомия того, что попадает в отчёт и мини-дамп

Когда процесс умирает от необработанного исключения, WER фиксирует строго очерченный набор фактов. Первым делом записывается идентичность погибшего: полный путь исполняемого файла, версия файла, метка времени и код исключения. Код вида c0000005 означает нарушение доступа к памяти, а сопутствующие параметры сообщают, читал процесс или писал и по какому адресу. Смещение внутри модуля позволяет при наличии символов опуститься до конкретной функции.

Дальше в дело вступает срезок процессорного состояния. В отчёт попадает контекст потока на момент исключения, то есть значения регистров и верхушка стека вызовов. Связка стека с таблицей модулей даёт разработчику главное: видно, через какие библиотеки прошёл вызов, какие версии библиотек загружены и где цепочка оборвалась. Список модулей с версиями особенно ценен, когда падение вызвано конфликтом чужого кода, внедрённого в процесс, например антивирусным фильтром или устаревшим плагином.

Мини-дамп формата minidump занимает обычно десятки или сотни килобайт и содержит контекст потоков, участки памяти вокруг указателей стека, таблицу загруженных образов и служебные потоки системы. Иногда в него добавляют частицы кучи, если эвристика решает, что причина в повреждении динамической памяти. Полезно перечислить, что входит в типичный пакет при отправке:

  1. сигнатура сбоя с именами и версиями приложения и модуля;
  2. код исключения, адрес и параметры сбоя;
  3. контекст регистров и стек проблемного потока;
  4. перечень загруженных модулей с версиями;
  5. мини-дамп ограниченного состава при запросе сервера.

Такого набора достаточно, чтобы вычислить топ стека, сопоставить его с известными сигнатурами и принять решение о запросе полного дампа при повторном проявлении. Разработчик на внутреннем портале видит жёлтые карточки failure с числом попаданий, динамикой по версиям и гистограммой по конфигурациям оборудования. Именно по этим карточкам распределяется инженерное время.

Что не отправляется и почему границы проведены именно там

Границы содержимого определяются двумя силами: приватностью и размером. Содержимое открытых документов, поля ввода паролей, тела писем и иные пользовательские данные осознанно исключаются из автоматических отчётов. Целые кучи процесса не передаются, потому что в них вперемешку лежат строки интерфейса, фрагменты файлов кэши и то, что пользователь вовсе не планировал никому показывать. Крупный дамп в сотни мегабайт к тому же неподъёмен для массовой телеметрии и не нужен для статистической классификации.

Важно понимать контракт распределения данных. Локальный файл дампа и отправленный отчёт это разные сущности. На машине в каталоге ProgramData\Microsoft\Windows\WER могут накапливаться ReportArchive и ReportQueue с метаданными и вложениями, а в профиле пользователя путь %LOCALAPPDATA%\CrashDumps становится домом для дампов, если администратор включил механизм LocalDumps. Эти локальные файлы не уезжают автоматически. Они живут на диске для разработчика или службы поддержки, пока человек сам не передаст их вендору или не удалит. Телеметрия и локальная диагностика движутся параллельными рельсами, и путать их не следует.

Из этого контракта вытекает рабочая практика. Когда поставщик прикладного ПО просит прислать файлы WER после краша, речь идёт именно о локальных артефактах: файле .wer с открытым текстом, вложенном мини-дампе и иногда файле .hdmp с расширенной памятью. Служба поддержки вендора загружает их в отладчик, сопоставляет с символами своей сборки и получает место сбоя без доступа к машине клиента. Это удобный и относительно безопасный канал, потому что передача происходит осознанно и содержимое можно предварительно просмотреть.

Приватный угол дампа и осознанность диагноста

Даже урезанный мини-дамп способен рассказать больше, чем кажется. Стек потока хранит локальные переменные, а среди них встречаются фрагменты строк, которые пользователь только что вводил: куски пути к файлу, остатки поискового запроса, части сообщения из редактора. Полный дамп кучи умножает эту осведомлённость на порядок, потому что в куче лежат пароли до очистки буферов, расшифрованные поля форм и кэши документов. Инженер, который просит дамп у пользователя, должен помнить, что получает не абстрактную телеметрию, а срез чужой памяти с личными остатками.

Отсюда следуют простые правила этики диагностики. Дамп передаётся по доверенному каналу и только тому, кто реально чинит сбой. Перед отправкой стоит оценить тип дампа: minidump без кучи почти безопасен, а full dump обращается как конфиденциальный документ. После завершения расследования дамп подлежит удалению у стороны, которая его получала, и на собственной машине. Осознанность здесь важнее формальностей, потому что формально файл выглядит невинным двоичным объектом, а по сути является слепком рабочего контекста человека.

Управление через реестр и трассировку

Поведение WER настраивается без сторонних средств, через ветки реестра и стандартные задания. Диалоговый интерфейс подавляется значением DontShowUI в ветке HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting, что полезно на серверах и киосках, где некому нажимать кнопки. Отдельные приложения можно исключить из отчётности списком ExcludedApplications, чтобы шумная служебная утилита не генерировала очередь отчётов ежечасно.

Механизм LocalDumps включается в ветке HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps и принимает три ключевых параметра. DumpFolder задаёт каталог сбора, DumpCount ограничивает число хранимых дампов на приложение, а DumpType выбирает формат: значение 1 даёт мини-дамп, значение 2 полный дамп памяти. Для приложения с устойчивым трудно ловимым сбоем полный дамп, включённый точечно под конкретный исполняемый файл, экономит недели переписки с пользователями. После поимки дефекта настройку полезно выключить, потому что полные дампы разрастаются быстро.

Живая картина движения отчётов доступна через ETL-трассировку: журналы Microsoft-Windows-WER-SystemErrorReporting и связанные каналы фиксируют создание отчёта, попытку отправки и код результата. Просмотр через Event Viewer или сбор средствами xperf и Windows Performance Analyzer показывает, почему отчёт не ушёл например из-за политики согласия или сетевой задержки. Для среды с ограниченным доступом наружу это единственный способ доказать, что служба работает корректно и упирается в политику, а не в дефект агента.

Гигиена каталогов с дампами и рабочий процесс диагноста

Дампы имеют свойство копиться молча. Папка ProgramData\Microsoft\Windows\WER с подкаталогами ReportArchive и ReportQueue на активной машине за год набирает гигабайты, а LocalDumps с полным типом дампа без ограничения счётчика заполнит системный диск при серийных падениях. Гигиена сводится к трём привычкам: периодическая очистка архивов через Disk Cleanup или прямым удалением устаревших каталогов, контроль DumpCount при включении LocalDumps и проверка свободного места перед длительной охотой за воспроизводимым крашем. Планировщик заданий содержит стандартные задачи обслуживания, но полагаться на них слепо не стоит на машинах с нестандартным профилем нагрузки.

Рабочий процесс диагноста при повторяющемся падении выглядит так. Сначала по журналу событий Application выясняется сигнатура сбоя и модуль-виновник. Затем проверяется наличие локальных дампов в стандартных путях; если их нет и сбой редкий, включается LocalDumps с нужным типом. Полученный дамп открывается в WinDbg, где команда анализа показывает стек и состояние регистров, а настройка пути к символам превращает смещения в имена функций. Найденное место сбоя сопоставляется с историей изменений кода или списком известных проблем вендора. После исправления дампы удаляются, настройка сворачивается, а в базу знаний команды уходит короткая заметка со сигнатурой и решением. Такая дисциплина превращает WER из источника тревоги в надёжного поставщика улик, и наследник доктора Ватсона наконец работает на инженера, а не против него.