Нужна поддержка эластичного APM для серверной части Ktor

#kotlin #elastic-stack #ktor #apm #elastic-apm

Вопрос:

Пытаемся отслеживать производительность нашего серверного приложения Ktor и можем подключить к нему агент Elastic APM. Сервер отображается на панели мониторинга Kibana как услуга. Но это не означает автоматического создания транзакций для каждого входящего запроса. Когда мы вручную запускаем транзакцию и завершаем ее определенным маршрутом, только тогда она записывает производительность для этого запроса. Есть ли другой способ решить эту ситуацию?

Попробовал следующий подход

  1. Перехватывал каждый запрос на этапе настройки и запускал транзакцию, но не мог завершить транзакцию, столкнувшуюся с проблемой, при перехвате того же вызова в конце.
  2. Для каждого запроса в контроллере/маршруте определен приведенный ниже фрагмент кода, и он работает.
     get("/api/path") {
        val transaction: Transaction = ElasticApm.startTransaction()
        try {
            transaction.setName("MyTransaction#getApi")
            transaction.setType(Transaction.TYPE_REQUEST)
            // do business logic and response
         } catch (e: java.lang.Exception) {
            transaction.captureException(e)
            throw e
         } finally {
            transaction.end()
         }  
    }
     
 
Adding below line for better search result for other developers.
How to add interceptor on starting and ending on each request in ktor. Example of ApplicationCallPipeline.Monitoring and proceed()
 

Ответ №1:

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

 intercept(ApplicationCallPipeline.Monitoring) {
    val transaction: Transaction = ElasticApm.startTransaction()
    try {
        transaction.setName("MyTransaction#getApi")
        transaction.setType(Transaction.TYPE_REQUEST)
        proceed() // This will call the rest of a pipeline
    } catch (e: Exception) {
        transaction.captureException(e)
        throw e
    } finally {
        transaction.end()
    }
}
 

Кроме того, вы можете использовать атрибуты для хранения транзакции в течение времени вызова (начинается с момента запуска запроса и заканчивается после отправки ответа).