Возможно включить трассировку рентгеновских лучей с помощью RestSharp

#c# #amazon-web-services #restsharp #aws-xray

#c# #amazon-веб-сервисы #restsharp #aws-xray

Вопрос:

В настоящее время у нас есть внутренняя библиотека, которую мы используем для выполнения многих наших HTTP-вызовов, которая использует RestSharp, а не HttpClient для выполнения всех наших запросов к нижестоящим службам. Возможно ли включить трассировку рентгеновских лучей в AWS без перезаписи этой библиотеки, чтобы вместо этого использовать HttpClient? Цель состоит в том, чтобы получить ту же функциональность, которая была бы описана здесь (при использовании HttpClient): https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-httpclients.html

Комментарии:

1. Что вы в конечном итоге сделали, чтобы решить свою проблему?

Ответ №1:

Библиотека RestSharp представляет собой отдельный HTTP-клиент, который X-Ray SDK для .NET в настоящее время не поддерживает. Я не знаком с RestSharp, но я полагаю, что он использует HttpClient под капотом, поскольку это встроенная библиотека для HTTP-вызовов в .NET. Итак, если бы вы могли каким-то образом заменить базовый HttpClient, используемый библиотекой RestSharp, на инструментальную версию HttpClient, это позволило бы выполнять трассировку рентгеновских лучей, но я не уверен, возможна ли такая замена.

X-Ray SDK для .NET имеет открытый исходный код, и мы с радостью примем запросы на извлечение, если вы хотите написать модуль для поддержки X-Ray RestSharphttps://github.com/aws/aws-xray-sdk-dotnet

Комментарии:

1. Правильно, RestSharp использует HttpWebRequest , который, в свою очередь, использует HttpClient . На самом деле это довольно легко настроить HttpClient ненавязчивым образом с помощью диагностических прослушивателей, как это делается в OpenTracing github.com/opentracing-contrib/csharp-netcore/blob/master/src /…

2. Не могли бы вы немного рассказать о том, что потребуется с технической точки зрения, чтобы добавить поддержку RestSharp? Вы упоминали о написании модуля? Есть ли у вас образец модуля, на который кто-нибудь может ссылаться при рассмотрении вопроса о его создании? Можете ли вы дать несколько советов?

3. Каковы необходимые и достаточные шаги для обновления dotnet xray sdk, чтобы он поддерживал RestSharp? Не могли бы вы, пожалуйста, дать несколько указаний? Я полагаю, вы упоминали что-то о «модуле». Что такое модуль в этом отношении? Является ли это специфичной концепцией xray sdk, о которой я могу где-нибудь узнать больше?

4. @AlexeyZimarev, я не верю, что клиенты библиотеки RestSharp обновляют экземпляр HttpClient непосредственно в своем вызывающем коде. Я полагаю, что ваша ссылка предназначена для всех, кто обновляет экземпляр HttpClient. Когда кто-то использует преимущества RestSharp, они, скорее всего, будут обновлять только экземпляры RestSharp.

5. @jbooker это правда, но любой инструментарий с System.Diagnostics , использующий activities, может быть легко расширен извне. Как только вы создадите действие перед отправкой запроса с помощью RestSharp, оно будет распространено с помощью HttpClient . Кроме того, это имеет мало общего с HttpClient экземпляром, поскольку трассировка выполняется по каждому запросу.

Ответ №2:

Вот как я в конечном итоге реализовал это — практически невозможно перехватить что-либо в RestSharp, поэтому я выбрал обратный подход, разбив и изменив расширение «GetResponseTraced»:

     public static class RestClientXrayExtensions
    {
        public static IRestResponse ExecuteTraced(this IRestClient client, IRestRequest request)
        {
            return client.ExecuteTraced(request, () => client.Execute(request));
        }

        public static IRestResponse<T> ExecuteTraced<T>(this IRestClient client, IRestRequest request)
            where T : new()
        {
            return client.ExecuteTraced(request, () => client.Execute<T>(request));
        }

        public static IRestResponse ExecuteAsGetTraced(this IRestClient client, IRestRequest request, string httpMethod)
        {
            return client.ExecuteTraced(request, () => client.ExecuteAsGet(request, httpMethod));
        }

        private static TResponse ExecuteTraced<TRequest,TResponse>(this IRestClient client, TRequest request, Func<TResponse> execute)
            where TRequest : IRestRequest
            where TResponse : IRestResponse
        {
            ProcessRequest(client.BuildUri(request), request.Method.ToString(), header => request.AddHeader("X-Amzn-Trace-Id", header));
            try
            {
                var response = execute();
                ProcessResponse(response.StatusCode, response.ContentLength);
                return response;
            }
            catch (Exception ex)
            {
                AWSXRayRecorder.Instance.AddException(ex);
                throw;
            }
            finally
            {
                AWSXRayRecorder.Instance.EndSubsegment(new DateTime?());
            }
        }

        private static void ProcessRequest(Uri uri, string method, Action<string> addHeaderAction)
        {
            if (!AWSXRayRecorder.Instance.IsTracingDisabled())
            {
                AWSXRayRecorder instance = AWSXRayRecorder.Instance;
                instance.BeginSubsegment(uri.Host, new DateTime?());
                instance.SetNamespace("remote");
                Dictionary<string, object> dictionary = new Dictionary<string, object>()
                {
                    ["url"] = (object)uri.AbsoluteUri,
                    [nameof(method)] = (object)method
                };
                instance.AddHttpInformation("request", (object)dictionary);
                try
                {
                    TraceHeader header;
                    if (!TraceHeader.TryParse(instance.GetEntity(), out header))
                        return;
                    addHeaderAction(header.ToString());
                }
                catch (EntityNotAvailableException ex)
                {
                    instance.TraceContext.HandleEntityMissing((IAWSXRayRecorder)instance, (Exception)ex, "Failed to get entity since it is not available in trace context while processing http request.");
                }
            }
        }

        private static void ProcessResponse(HttpStatusCode httpStatusCode, long? contentLength)
        {
            if (!AWSXRayRecorder.Instance.IsTracingDisabled())
            {
                int num = (int)httpStatusCode;
                Dictionary<string, object> dictionary = new Dictionary<string, object>()
                {
                    ["status"] = (object)num
                };
                if (num >= 400 amp;amp; num <= 499)
                {
                    AWSXRayRecorder.Instance.MarkError();
                    if (num == 429)
                        AWSXRayRecorder.Instance.MarkThrottle();
                }
                else if (num >= 500 amp;amp; num <= 599)
                    AWSXRayRecorder.Instance.MarkFault();
                dictionary["content_length"] = (object)contentLength;
                AWSXRayRecorder.Instance.AddHttpInformation("response", (object)dictionary);
            }
        }
    }