Часть 2. Идентификация событий происходящих в Oracle PL/SQL

Убедительная просьба, рассматривать данный текст только как продолжение к статье о «Событийной модели логирования». Эта статья будет полезна тем, у кого уже реализовано логирование событий в БД и кто хотел бы осуществлять сбор статистики и начать проводить аналитику этих событий. Только представьте, что ваша БД сможет информировать вас о критичных сбоях системы, накапливать информацию о событиях в БД (кол-во повторений, период повторений и т. д.). И всё это без использования стороннего ПО силами одного PL/SQL.

Введение

Модель логирования позволяет реализовать:

Единый подход в обработке и хранении событий (статья)

Собственную нумерацию и идентификацию событий происходящих в БД

Единый мониторинг событий (статья в разработке)

Анализ событий происходящих в БД (статья в разработке)

Описанные выше характеристики указаны в порядке нумерации и каждый следующий пункт (шаг) есть улучшение и усложнение существующей модели. Описание этой модели будет сложно выполнить в рамках одной статьи, поэтому опишем их последовательно. В этой (второй) статье создадим собственную нумерацию кодов для событий, а также создадим функционал идентификации событий происходящих в БД.

Для чего это нужно?

Для начала давайте рассмотрим пример. Вы реализовали логирование ошибок в вашей БД. С течением времени в ваш лог «прилетают» самые разнообразные ошибки. Предположим, имеются две ошибки вида «no_data_found» возникшие в двух разных процедурах при двух разных запросах (select). Первая ошибка возникла при попытке найти «email» клиента, что в принципе не является критичной ошибкой. Вторая ошибка возникла при попытке найти номер лицевого счета клиента, что вполне может являться критичной ошибкой. При этом если мы посмотрим в таблицу лога (из статьи), то увидим, что указанные ошибки будут храниться с одинаковым кодом 1403 (ORA-01403) в столбце msgcode. Более того, текст указанных ошибок будет практически аналогичным (текст полученный с помощью функции SQLERRM) за исключением имен объектов, на которых произошла ошибка. Для того чтобы понять является ли критичной конкретная ошибка, разработчику необходимо вникать в текст ошибки, смотреть в каком объекте возникла ошибка и на основе этой информации сделать вывод о срочности исправления. При этом, если мы сможем задать более четкое описание ошибки отличное от текста Oracle (SQLERRM), то это позволит упростить понимание причин возникновения и способов решения ошибки.

Как должно быть (в идеале)

Не найдена запись в таблице содержащей адреса электронной почты клиентов

ORA-01403: данные не найдены

USR0001: Не найден адрес электронной почты клиента (идентификатор клиента)

Не найдена запись в таблице содержащей лицевые счета клиентов

ORA-01403: данные не найдены

USR0002: Не найден лицевой счет клиента (идентификатор клиента)

Из этого примера видно, что одна и та же ошибка «no_data_found» (ORA-01403: данные не найдены) может иметь совершенно разное значение с точки зрения бизнес логики, а значит нам необходимо разработать механизм, который позволит идентифицировать каждое событие происходящее в БД как отдельное событие с нашим внутренним уникальным кодом и текстом события (отличную от Oracle). Таким образом мы решаем две проблемы:

1) В месте возникновения ошибки мы устанавливаем уникальный код ошибки. В будущем это позволяет достаточно быстро найти место возникновения ошибки. Также, наличие уникальных кодов позволяет нам произвести точечный подсчет повторений и на основании этой информации принять решение об устранении данной ошибки.

2) Дополнительный «читаемый» текст позволяет сильно упростить понимание ошибки. В таблице выше показано, как одна и та же ошибка может запутать или разъяснить пользователю сведения об ошибке.

Надеюсь мне удалось объяснить зачем необходимо кодировать события в таблице логов. Далее по тексту, будут введены термины «Архитектурный лог» и «Пользовательский лог». На примере процедуры поиска активного номера телефона клиента будет показано как и зачем создано разделение на архитектурный и пользовательский лог.

Архитектурное логирование событий

Давайте рассмотрим пример, имеется процедура поиска активного номера телефона принадлежащего конкретному клиенту (для примера его Предположим, что при постановке задачи для разработчика не было описания каких-либо особых условий т. е. по условиям задачи предполагалось, что для конкретного пользователя (id = 43, идентификатор передается в качестве параметра) в таблице client_telnumbers всегда будет хотя бы одна запись с номером телефона клиента и признаком «активный» (значение поля enddate равно дате 31.12.5999 23:59:59, что означает что номер используется клиентом. В случае, любой другой даты в указанном поле означает, что номер перестал быть активным и более не используется), поэтому наша процедура будет выглядеть примерно так:

Исходный код демонстрационной процедуры

Важно! Представленный код является примерным (примитивным) и служит только для демонстрации логирования в рамках данной статьи. В своих статьях я не выкладываю текст кода из реально действующих БД. Надеюсь, вы понимаете, что в реальности указанная процедура написана гораздо сложнее.

*Исходный код других используемых объектов смотрите в Git

Если мы будем использовать логирование ошибок как показано в предыдущей статье, то с течением времени обнаружим, что идентифицировать ошибки из данной процедуры будет сложно. Поэтому для всех ошибок попадающих в обработку исключения «WHEN OTHERS» реализована процедура pkg_msglog. p_log_archerr, которая при первом возникновении ошибки автоматически присваивает ей уникальный код и сохраняет ошибку в таблице лога. В дальнейшем, при повторении данной ошибки процедура найдет ранее созданный код и использует его при логировании в таблице лога.

В итоге, после добавления блока «архитектурного» логирования (строки с 18 по 24), наша процедура будет выглядеть следующим образом:

Исходный код демонстрационной процедуры

*Исходный код других используемых объектов смотрите в Git

Исходный код таблицы

Ограничение в таблице на комбинацию (Имя объекта, код ошибки SQLCODE). При первом появлении ошибки создается запись в таблице и генерируется код ошибки «SYS0000» + счетчик ошибок. При повторном появлении указанной ошибки будет взят уже сгенерированный ранее код ошибки.

рис. Пример содержимого таблицы messagecodes_arch

рис. Пример содержимого таблицы messagecodes_arch

*Исходный код других используемых объектов смотрите в Git

Обратите внимание, что при использовании описанной модели «архитектурного» логирования у вас появляется функционал позволяющий максимально быстро реагировать на первое появление ошибки (в конкретной функции/процедуре). Для этого необходимо реализовать отдельный мониторинг архитектурных ошибок, который постараюсь продемонстрировать в следующей (третьей) статье. Использование процедуры pkg_msglog. p_log_archerr не требует каких-либо действий кроме описания входных параметров.

Таким образом мы можем создать базовый шаблон процедуры (функции), использование которого позволит вам гарантированно отлавливать все архитектурные ошибки в вашем коде.

Шаблон процедуры/функции с архитектурным логированием

Рекомендую использовать данный шаблон для построения «Событийной модели логирования».

*Исходный код других используемых объектов смотрите в Git

В рамках событийной модели логирования, предполагается, что все архитектурные ошибки будут исправляться отдельной задачей т. е. основная цель это устранить повторное появление ошибок с кодом «SYS****» в таблице лога. В указанной задаче вам необходимо либо устранить причины возникновения данной ошибки, либо добавить отдельную обработку ошибки отличную от «when others», которую в дальнейшем будем назвать «пользовательское» логирование (в рамках данного цикла статей).

Пользовательское логирование событий

Предположим, что однажды в нашей процедуре get_telnumber произошла «архитектурная ошибка». В частности, для конкретного пользователя в таблице client_telnumbers хранится два номера телефона с признаком «активный». В таком случае, процедура «упадёт» с ошибкой «ORA-01422: too_many_rows». При этом, наш функционал архитектурного логирования сгенерировал новый код ошибки «SYS0061» и создал запись в таблице лога.

рис. Код архитектурной ошибки SYS0061

рис. Код архитектурной ошибки SYS0061

Самое важно в такой ситуации это не откладывать «на потом» исправление архитектурных ошибок. В идеале, необходимо создать отдельную задачу (баг) и в рамках неё устранить ошибку.

Для этого в процедуре get_telnumber добавлено исключение (exception) «too_many_rows» пользовательского логирования. Также, был создан справочник пользовательских ошибок отличный от архитектурного справочника, тем что в него все записи добавляются разработчиком «вручную». Наверное это самое слабое место во всей архитектуре логирования. Предполагается, что разработчик должен описать исключение (exception) и создать для него уникальный код ошибки. Также, желательно к указанной ошибке сформулировать читаемый текст ошибки (для своих коллег, пользователя, техподдержки и т. д.), что бывает иногда очень сложным (из личного опыта).

Таблица пользовательских ошибок и процедура их «регистрации» будет выглядеть следующим образом:

Исходный код таблицы пользовательских ошибок и процедуры регистрации

Регистрация пользовательских ошибок производится процедурой p_insert_msgcode. На вход подается код и текст ошибки. В случае, если по указанному коду нет записей в справочнике messagecodes, то создается новая запись (производится регистрация). В случае, если по коду ошибки найдена запись, то производится сравнение текстов ошибки, в случае расхождений производится обновление текста, иначе работа процедуры завершается без изменений. Таким образом мы всегда можем корректировать текст ошибок.

Итого, содержимое справочника пользовательских ошибок будет выглядеть следующим образом:

рис. Пример содержимого справочника пользовательских ошибок

рис. Пример содержимого справочника пользовательских ошибок

*Исходный код других используемых объектов смотрите в Git

После того, как мы «зарегистрировали» пользовательскую ошибку «USR0003» и добавив отдельную обработку пользовательского логирования (строки с 19 по 28), наша процедура get_telnumber будет выглядеть следующим образом:

Исходный код демонстрационной процедуры

*Исходный код других используемых объектов смотрите в Git

Давайте рассмотрим еще один пример (кейс из реального случая), в момент когда процедура get_telnumber по id клиента находит один «активный» номер телефона иногда возникает ситуация, что номер телефона не принадлежит мобильному оператору. Ситуации бывают разные иногда указанный номер мог быть номером городской телефонной сети, иногда номером международного оператора, а иногда вообще набор из нескольких цифр и т. д. Основным требованием от бизнес-заказчика было использование номера телефона российских операторов мобильной связи. Поэтому было решено добавить проверку соответствия найденного номера некому «корректному» шаблону (строки с 18 по 29). В случае обнаружения некорректного номера, логировать данное событие отдельным кодом «USR0004» и типом «WRN». Добавим функцию проверки корректности номера телефона, если номер соответствует шаблону (требованиям), то вернем номер телефона, иначе пустое значение.

Исходный код демонстрационной процедуры

*Исходный код других используемых объектов смотрите в Git

После сбора статистических данных по конкретной ошибке с кодом «USR0004», руководству стало понятно, что ошибка актуальна и количество ошибок с течением времени не только не уменьшается, а наоборот растет с линейной прогрессией. В дальнейшем, были выявлены источники «кривых» данных и были установлены внутренние требования по первичной обработке номера телефона клиентов. В итоге, со временем количество ошибок уменьшилось до нуля. И этого нельзя было добиться до тех пор, пока у всех участвующих лиц не возникло понимание о масштабе проблемы.

Выполняя самый банальный запрос в таблицу лога с группировкой по типу сообщения (msgtype), имени объекта (objname) и вашему внутреннему коду ошибки (msgcode) за отдельный квартал, вы сможете увидеть реальную картинку частоты возникновения той или иной ошибки. Как только в вашей БД появляется ошибка с большим количеством повторений вы всегда сможете выявить это событие и принять решение об устранении.

Исходный код запроса

рис. Пример результата запроса с группировкой

рис. Пример результата запроса с группировкой

*Исходный код других используемых объектов смотрите в Git

Заключение

В заключении наверное скажу банальную вещь, о том что ваша БД является сложным механизмом ежесекундно выполняющая рутинные операции. Прямо сейчас в БД могут происходить различные ошибки. Критичные, которые вы исправляете практически сразу или некритичные, о которых вы можете вообще не знать. И если у вас нет информации о подобных ошибках, то возникает вопрос: «Нужно ли их вообще исправлять? Или можно подождать до тех пор, пока проблема не всплывёт?». Вопрос наверное «риторический».

Я же данной статьей хотел показать один из способов ведения логирования с кодированием отдельных событий. Данный метод требует некоторых «обязательств» от разработчика и в нынешнее время этого тяжело добиться. В следующей статье постараюсь показать один из способов мониторинга ошибок основанный напрямую по кодам ошибок созданных в текущей статье.

И в завершении, функционал «Событийной модели логирования» без ведения собственных кодов ошибок описанных в данной статье или логирование только «нужных» (по мнению разработчика) участков кода я бы сравнил с «пустым (просроченным) огнетушителем в легковом автомобиле». Вы возите с собой пустой огнетушитель с мнимым ощущением защищенности лишь бы был, лишь бы не штрафовали. Если случится возгорание, то он вам не поможет и все сгорит. Если же вы используете полноценный работоспособный огнетушитель и у вас случилось возгорание, то его полезность определяется тем как быстро выявится факт возгорания. Если возгорание на начальном этапе, то огнетушитель вполне справиться и потушит огонь, если же автомобиль сгорел чуть менее чем на половину, то скорее всего он не поможет. Также с вашей БД, если вы используете логирование событий не в полном объеме, то вы не сможете вовремя выявить проблему. Не сможете выявить нарастание повторений ошибок, их количества и т. д. И рано или поздно может возникнуть одна очень критичная ошибка, которая приведет к большим проблемам, но вы не сможете вовремя на неё среагировать. Потому что полезность всего логирования определяется тем, как быстро вы можете заметить возможную ошибку и постараться предотвратить её.

Иногда вы видите ошибку ora-00942 при выполнении оператора SQL. У него есть несколько причин, и, как обычно, синтаксис ошибок не является наиболее описательным. Если вы сталкиваетесь с этим и хотите знать, как исправить ошибку ora-00942, читайте дальше.

Насколько я знаю, есть три основные причины ошибки ora-00942:

Я покажу вам, как обратиться к каждому.

Исправьте ошибку ora-00942

Прежде всего, небольшой отказ от ответственности. Я не администратор баз данных, я администратор Windows, а также специалист по аппаратному и настольному оборудованию. Я знаю, как запустить SQL, но не до какой-то степени опыта и, конечно, не до уровня, который может устранять проблемы. Я должен был попросить моего друга Oracle DBA о помощи, поэтому, пока я писал эту часть, все умные биты принадлежали ему.

Этот список из трех причин ошибки ora-00942 не является исчерпывающим. Есть, очевидно, другие случайные причины этого, но эти три, по-видимому, наиболее распространены.

Недостаточно прав пользователя

Одной из основных причин ошибки ora-00942 является то, что у пользователя недостаточно прав для доступа к рассматриваемой таблице. Вы можете проверить это, выполнив два запроса.

— список привилегий объекта для пользователя или роли

Эти двое скажут вам, имеет ли данный пользователь правильные привилегии для запуска команды. Если пользователь имеет правильные привилегии, переходите к следующему. Если пользователь не имеет правильных привилегий, предоставьте их им или попросите администратора БД сделать это.

Ошибка ora-00942 также может возникнуть, если пользователь используемой схемы имеет привилегии INSERT, но не привилегии SELECT. Опять же, проверьте уровень привилегий и добавьте SELECT в список или попросите администратора БД сделать это. Очевидно, что каждой схеме должна быть предоставлена ​​определенная привилегия SELECT, в противном случае вы все равно увидите ошибку ora-00942.

Таблица или представление на самом деле не существуют

Причиной ошибки ora-00942 может быть неправильный синтаксис запроса или отсутствие таблицы. Хотя это может показаться логичным для начала, я уверен, что привилегия пользователя является причиной ошибки номер один. Таблица, которой там нет или используется неверный синтаксис таблицы, занимает второе место.

Чтобы проверить, существует ли таблица, сначала проверьте синтаксис запроса. Если синтаксис правильный, запустите этот запрос.

В последней строке вставьте фактическое имя таблицы, где вы видите «YOUR_TABLE_NAME». Это должно точно сказать вам, существует ли таблица, к которой вы пытаетесь обратиться, или нет. Если он возвращается без таблицы, запрашиваемая вами таблица не существует в схеме или базе данных.

Если в используемой вами системе есть меню «Таблицы», вы можете вручную проверить таблицу, если хотите, но вышеуказанный запрос выполняет свою работу.

Таблица или представление находятся в другой схеме

Если у пользователя есть права, и таблица существует, но вы все еще видите ошибку ora-00942, скорее всего, это связано со схемой. Если вы управляете несколькими схемами, легко выполнить запрос к схеме, которая не принадлежит вам. Когда вы заняты и против этого, это простая ошибка, чтобы сделать.

Проверьте схему вручную, если можно или добавьте имя схемы в строке ОТ вашего запроса. Если у вас нет правильных привилегий для новой схемы, вы снова увидите ошибку ora-00942. Вернитесь к первому исправлению привилегий пользователя и проверьте соответствующую схему или попросите своего администратора базы данных сделать это за вас.

Как упомянуто выше, я проконсультировался с моим приятелем по DBA Oracle для этой работы, так что вся заслуга ему в тяжелой работе. Если вы обнаружите здесь какие-либо ошибки или упущения, они одни. Дайте мне знать в разделе комментариев, если я что-то пропустил или ошибся, и я исправлю это.

Если вам известен какой-либо другой способ исправить ошибку ora-00942, сообщите нам об этом ниже!

Источники:

https://habr. com/ru/post/555622/

https://milestone-club. ru/kak-ispravit-oshibku-ora-00942

Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: