Автоматизация трассировки Sentry в TypeScript с помощью декораторов!
Эта статья посвящена следующим темам:
- Что такое Сентри
- Обзор Sentry Tracing
- Понимание декораторов методов TypeScript
- Проектирование декоратора трассировки Sentry
- Выполнение
- Тестирование и проверка
- Преимущества и соображения
- Заключение и рабочая демонстрация
1. Что такое Сентри
Sentry — это популярная платформа для отслеживания и регистрации ошибок, которая позволяет разработчикам отслеживать и устранять проблемы в своих приложениях. Одной из мощных функций Sentry является возможность отслеживания, которая позволяет разработчикам видеть точный поток запросов через свое приложение и определять, где возникают проблемы.
Давайте посмотрим, что именно представляет собой сентри-трейсинг:
2. Обзор Sentry Tracing
Sentry Tracing — это функция, которая позволяет разработчикам отслеживать поток запросов или транзакций через свое приложение путем сбора и связывания нескольких событий (таких как вызовы функций, запросы к базе данных и HTTP-запросы), которые произошли во время транзакции. Это может помочь разработчикам понять, как различные части их приложения взаимодействуют друг с другом, и упростить определение основной причины ошибки или если что-то требует много времени для завершения.
Визуально трассировка выглядит так:
Не буду вдаваться в подробности, но вот краткий обзор транзакций и спанов в трассировке Sentry:
- Транзакция. Транзакция — это самый высокий уровень операций в вашем приложении, который вы хотите измерять и отслеживать. Он представляет собой единую логическую единицу работы, которую выполняет ваше приложение, например, обработку веб-запроса, обработку фонового задания или выполнение запроса к базе данных. Транзакции могут быть вложены друг в друга, образуя древовидную структуру, представляющую полный путь выполнения.
- Span. Диапазон представляет собой одну операцию внутри транзакции. Это способ измерить время, затрачиваемое определенной частью вашего кода, например, вызовом функции, запросом к базе данных или HTTP-запросом. Промежутки могут быть вложены друг в друга, чтобы представить полный стек вызовов вашего приложения.
если вы хотите прочитать более подробное руководство, ознакомьтесь с официальной документацией по трассировке здесь:
https://docs.sentry.io/product/sentry-basics/tracing/distributed-tracing/
3. Понимание декораторов методов TypeScript
Декораторы методов TypeScript применяются к методам внутри класса. Декораторы методов получают три параметра: целевой объект (прототип), имя метода и дескриптор свойства.
Они предоставляют способ расширить или изменить поведение метода без изменения его исходной реализации.
Чтобы определить декоратор метода, вы используете символ @
, за которым следует имя декоратора непосредственно перед объявлением метода. Вот пример:
4. Дизайн декоратора трассировки Sentry
Хотя Sentry Tracing имеет обширный список функций, наиболее важной из них является возможность отслеживать и синхронизировать поток вызовов различных функций с помощью декораторов и вложенным образом. Для этого мы создадим декоратор @SentryTraced()
, который будет использоваться для аннотирования всех методов, которые нам нужно отслеживать, вот простой пример:
5. Реализация
Во-первых, как следует из названия, нам нужно начать с создания шаблона декоратора, и вот он:
Я не буду вдаваться в подробности, но этот исходный код заставляет декоратор работать,
Кроме того, при запуске этого кода обязательно установите “experimentalDecorators”: true
в файле ts-config.json.
Теперь пришло время добавить основную логику в декоратор, то есть трассировку Sentry.
Объединение двух представленных выше концепций, логики трассировки часового и стандартного шаблона декоратора метода приведет к следующей реализации:
Разберем все подробно:
const className = this.constructor.name; const methodName = propertyKey; const op = `Operation ${className}#${methodName}`; const description = `Description for ${className}#${methodName}`;
Эти строки извлекают имя класса (className
) и имя метода (methodName
), к которому применяется декоратор. Они используются для создания операции (op
) и описания (description
) диапазона или транзакции, которые будут использоваться в целях отслеживания.
const intermediaryFunction = async () => { // ... };
Это определяет промежуточную асинхронную функцию, которая завершит выполнение исходного метода. Цель этой функции — настроить контекст трассировки и выполнить исходный метод, фиксируя любые ошибки.
const scope = Sentry.getCurrentHub().getScope(); const contextTransaction = scope?.getSpan() || scope?.getTransaction(); const transactionOrSpan = contextTransaction || Sentry.startTransaction({ op, description, name: `Transaction for ${className}#${methodName}`, }); const newSpan = transactionOrSpan?.startChild({ op, description, }); Sentry.configureScope((scope) => { scope.setSpan(newSpan); });
Эти строки извлекают текущую область действия из системы отслеживания ошибок Sentry. Область содержит информацию о текущем активном диапазоне или транзакции. Если текущей области, диапазона или транзакции нет, новая транзакция (корневой узел) создается с использованием метода Sentry.startTransaction()
. Новый диапазон запускается как дочерний элемент текущей транзакции или диапазона с использованием метода startChild()
. Затем метод setSpan()
используется для установки вновь созданного диапазона в качестве текущего диапазона в области Sentry.
const result = original.apply(this, args); if (isPromise(result)) { // in case the function is a promise we need to resolve it and also // reset the current context to the parent node for the next sibling function call return result.then((resultFromFunction: any) => { Sentry.configureScope((scope) => { scope.setSpan(transactionOrSpan); }); newSpan?.finish(); // finish the transaction if it's a root node if (!contextTransaction) { transactionOrSpan.finish(); } // return the result of the original function return resultFromFunction; }); } else { // same for a normal function but we just do it before returning the value // context to the parent node for the next sibling function call Sentry.configureScope((scope) => { scope.setSpan(transactionOrSpan); }); newSpan?.finish(); // finish the transaction if it's a root node if (!contextTransaction) { transactionOrSpan.finish(); } return result; }
Эта часть вызывает исходный метод (без ожидания), а затем проверяет, является ли ответ обещанием или нет. Мы делаем это потому, что методы, которые будут декорированы, могут либо возвращать обещание, либо просто значение, например:
@SentryTraced() async method1(){ return 'something'; } // returns a promise @SentryTraced() method2(){ return 'something'; } // returns a value
Чтобы иметь возможность остановить транзакцию после того, как функция завершит выполнение, нам нужно либо дождаться разрешения промиса и затемзавершить транзакцию, либо немедленно завершить ее. если функция простая синхронная.
Тестирование реализации
Для тестирования нам нужно создать класс с кучей декорированных методов, вот пример:
Запуск этого кода генерирует следующие выходные данные трассировки часового:
Заключение и рабочая демонстрация
Этот код позволяет отслеживать и контролировать выполнение методов с помощью системы отслеживания и мониторинга ошибок Sentry. Он устанавливает диапазоны и транзакции, фиксирует ошибки и предоставляет структурированный способ отслеживания потока вызовов методов.
Этот декоратор можно упаковать в библиотеку npm и использовать в любой кодовой базе, требующей трассировки. Вы можете найти реализацию на моей странице GitHub здесь: https://github.com/alexcambose/sentry-traced
Сообщество открытого исходного кода — это динамичная экосистема, постоянно развивающаяся и движимая коллективными усилиями увлеченных людей, поэтому я призываю вас проверить ее и сообщить мне, что вы думаете.
Если вы нашли статью полезной, пожалуйста, похлопайте ей на Medium. Ваши аплодисменты служат способом выразить признательность и помочь другим узнать о статье. Кроме того, я буду очень рад, если вы поставите звездочку в репозитории GitHub, связанном с этой статьей. Ваша звезда будет поощрять других разработчиков к изучению кода и внесению ценного вклада.
Дополнительные материалы на PlainEnglish.io.
Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .