Application Insights — клёвая штука, позволяющяя проводить диагностику, профилирование и анализ использования развернутых систем (в т.ч. в продакшен режиме), и при этом не требующая от разработчика вообще никаких усилий. Конечно, всё это становится возможным ценой мучительной первоначальной настройки.
В рекламных видео конечно никакой особой настройки нет, но жизнь — она сложнее, особенно если ваше ПО микросервисное. Почему? А всё очень просто.
Что в первую очередь должна делать система диагностики в микросервисной архитектуре?
Правильно, коррелировать диагностику от различных микросервисов в рамках одной операции.
Тыркнул пользователь в UI кнопочку — надо увидеть диагностику от всех N микросервисов, которые так или иначе обрабатывали этот тырк. Случился где-нибудь exception — надо увидеть не только в каком микросервисе он произошёл, но и в рамках какой операции это случилось.
Только вот Application Insights с точки зрения конкретного микросервиса — это в первую очередь SDK. И SDK таких есть несколько — есть для JS, есть для .NET Core, .NET (со своими особенностями настройки для MVC, WebAPI, WCF), есть для Java и т.д. 
Какие-то из этих SDK — opensource, какие-то — внутренняя разработка MS. И чтобы всё завелось — их надо подружить.
В этом и состоит основная сложность.
Не скажу, что я достиг 100% просветления в этом вопросе.
Но по крайней мере, я уже собрал несколько граблей и у меня есть рабочий семпл с UI на ASP.NET MVC (не Core) + JS и двумя микросервисами (Asp.Net WebApi, WCF)
Кому интересно — прошу под кат.
Немного про Application Insights
Если в двух словах — то работает он так:
- С помощью SDK ручками или автоматично генерируются объекты из дата модели Application Insights по событиям в ПО
 - Сгенерированные объекты засылаются в Azure через REST API
 - В Azure есть инструменты (очень богатые) для анализа сгенерированной инфы
 
Как дата модель Application Insights маппится на микросервисную архитектуру?

Как видно из картинки, каждый пинок в микросервис\UI\API порождает Request на той стороне, куда пнули и Dependency на той стороне, где пинали.
В процессе работы могут рождаться также трассировочные события, сообщения об ошибках, кастомные евенты, а также такие специализированные объекты как pageView
Как Application Insights коррелирует между собой объекты

На картинке синими стрелочками отмечены связи между объктами. Как видно,
Все объекты связаны с определенной операцией (это не отдельная сущность датамодели AI, они просто имеют одинаковое свойство. Операция инициализируется при первом request не в рамках операции)
Трассировочные сообщения/сообщения об ошибках/кастомные события/депенды микросервиса связаны дополнительно к объекту request (также через свойство)
- Объекты Request связаны дополнительно с объектом Dependency (если только это не самый первый Request) также через свойство.
 
Подробности можно почитать в официальной документации по Application Insights
Что дальше?
А дальше будет описание двух сценариев взаимодействия между микросервисами с подробным описанием способа реализации.
Сценарий 1 — AJAX, MVC, WebApi

Или то же самое, но словами:
Для отображения странички требуется в MVC контроллере получить данные от WebAPI микросервиса (через HttpClient)
- После отображения странички она сама с помощью jQuery лезет на сервер в MVC контроллер и получает ещё данные, которые в свою очередь также берутся от WebAPI микросервиса.
 
Что мы хотим получить
Хотим иметь возможность
- Увидеть факт просмотра страницы
 - Увидеть, что для генерации страницы сервер ходил в микросервис
 - Увидеть, что сама страница выполняла ajax запрос на сервер
 - Увидеть, что сервер для удовлетворения этого запроса также ходил в микросервис
 - В случае возникновения где-нибудь ошибки — хотим сразу увидеть контекст в рамках которого она произошла
 
В идеале, мы должны всю информацию увидеть на одном экране как последовательность действий
Конечно, все эти цели в конечном счёте мы достигнем.
Чтобы не томить — 
Сначала результат:
Переход от страницы к диагностической информации по операции

Сама диагностическая информация

А теперь с ошибкой в микросервисе:

Детали реализации
В Web API микросервисе:
- Устанавливаем NuGets Microsoft.ApplicationInsights, Microsoft.ApplicationInsights.Web, Microsoft.AspNet.WebApi.Tracing
 - С пакетами выше приезжает TraceListener для ApplicationInsights, прописывается в web.config сам.
 - В WebApiConfig указываем config.EnableSystemDiagnosticsTracing()
 - Реализуем IExceptionFilter, регистрирующий все непойманные ошибки в ApplicationInsights, прописываем его в FilterConfig.cs
 
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class WebApiAITrackingAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        if (filterContext != null 
&& filterContext.HttpContext != null && filterContext.Exception != null)
        {
            ApplicationInsightsSettings.TelemetryClient.TrackException(filterContext.Exception);
        }
    }
}TelemetryClient — объект из SDK ApplicationInsights. Его не рекомендуется создавать каждый раз, поэтому он тут singleton через ApplicationInsightsSettings
В ASP.Net MVC UI:
- Устанавливаем NuGet'ы Microsoft.ApplicationInsights, Microsoft.ApplicationInsights.Web
 - Реализуем IExceptionFilter, регистрирующий все непойманные ошибки в ApplicationInsights, прописываем его в FilterConfig.cs (такой же как и для Web API микросервиса)
 - Реализуем HttpClientHandler для работы с HttpClient, создающий Dependency.
Тут чуть поподробнее: вообще, документация декларирует, что System.Net.HttpClient начиная хз с какой версии умеет сам создавать Dependency.
И это даже действительно так. Но только делает он это не напрямую (он напрямую с AI SDK не работает), а слегка через одно место, поэтому этот Dependency не всегда привязывается правильно к Request. Поэтому когда мне надоело ловить глюки с этим — я написал свой HttpClientHandler 
public class DependencyTrackingHandler : HttpClientHandler
{
    public DependencyTrackingHandler()
    {
    }
    private static int _dependencyCounter = 0;
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        using (var op = ApplicationInsightsSettings.TelemetryClient.StartOperation<DependencyTelemetry>(request.Method.Method + " " + request.RequestUri.AbsolutePath))
        {
            op.Telemetry.Target = request.RequestUri.Authority;
            op.Telemetry.Type = request.Method.Method;
            op.Telemetry.Data = request.Method.Method + " " + request.RequestUri.ToString();
            op.Telemetry.Id += "." + Interlocked.Increment(ref _dependencyCounter).ToString();
            request.Headers.Add("Request-Id", op.Telemetry.Id);
            var result = base.SendAsync(request, cancellationToken).Result;
            op.Telemetry.ResultCode = result.StatusCode.ToString();
            op.Telemetry.Success = result.IsSuccessStatusCode;
            return result;
        }
    }
}Как видно, смысл этого хендлера — обернуть вызов HttpClient'а в DependencyTelemetry, а также (и это очень важно), установить правильный Request_Id хедер.
Про хедеры также чуть поподробнее. Через них инфраструктура AI передает информацию о id операции, а также информацию о id dependency при вызовах через HttpClient.
Хедеры для этих целей используются такие: "Request-Id", "x-ms-request-id", "x-ms-request-root-id". Для того чтобы корреляция правильно инициализировалась достаточно первого или (второго И третьего).
Подробнее про корреляции и хедеры можно почитать в документации (хотя она довольно сумбурна)
- Вспоминаем, что тут мы имеем дело с двумя SDK — для JS и для .NET, поэтому где-нибудь в вьюхах MVC ищем код, инициализирующий appInsight на стороне браузера, а затем
 - Прописываем туда InstrumentationKey
 
var appInsights=window.appInsights||function(config)
{
    function r(config){ t[config] = function(){ var i = arguments; t.queue.push(function(){ t[config].apply(t, i)})} }
    var t = { config:config},u=document,e=window,o='script',s=u.createElement(o),i,f;for(s.src=config.url||'//az416426.vo.msecnd.net/scripts/a/ai.0.js',u.getElementsByTagName(o)[0].parentNode.appendChild(s),t.cookie=u.cookie,t.queue=[],i=['Event','Exception','Metric','PageView','Trace','Ajax'];i.length;)r('track'+i.pop());return r('setAuthenticatedUserContext'),r('clearAuthenticatedUserContext'),config.disableExceptionTracking||(i='onerror',r('_'+i),f=e[i],e[i]=function(config, r, u, e, o) { var s = f && f(config, r, u, e, o); return s !== !0 && t['_' + i](config, r, u, e, o),s}),t
}({
    instrumentationKey: "@Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.Active.InstrumentationKey"
});- Синхронизируем глобальную операцию между сервером и браузером (чтобы у нас в одной глобальной операции отображалась и серверная диагностика и диагностика с браузера)
 
window.appInsights.queue.push(function () {
    var serverId ="@Context.GetRequestTelemetry().Context.Operation.Id";
    appInsights.context.operation.id = serverId;
});Большое спасибо за этот WA **Sergey Kanzhelev** и его блогу [http://apmtips.com](http://apmtips.com)Сценарий 2 — AJAX, WCF, WebApi

Или то же самое, но словами:
- Для отображения странички не требуется данных от микросервиса
 - После отображения странички она сама с помощью jQuery лезет в WCF микросервис и получает ещё данные, которые в свою очеред также берутся от WebAPI микросервиса.
 
Цели те же, как и в предыдущем сценарии
Сначала результат:

С ошибкой в микросервисе:

Детали реализации
В Web API микросервисе — ничего нового относительно предыдущего сценария
В ASP.Net MVC UI:
- Где-нибудь в вьюхах MVC ищем код, инициализирующий appInsight на стороне браузера, а затем перепределяем функцию appInsights._ajaxMonitor.sendHandler
 
window.appInsights.queue.push(function () {
    appInsights._ajaxMonitor.sendHandler = function (e, n) {
        e.ajaxData.requestSentTime = Date.now();
        if (!this.appInsights.config.disableCorrelationHeaders) {
            var i = this.appInsights.context.operation.id;
            e.setRequestHeader("x-ms-request-root-id", i);
            e.setRequestHeader("x-ms-request-id", e.ajaxData.id);
        }
        e.ajaxData.xhrMonitoringState.sendDone = !0;
    };
});С этим чуть поподробнее. Как известно, запросы через XmlHttpRequest на хосты, отличные от текущего, подвержены дополнительной секьюрити, т.н. CORS
Выражается это в том, что в http API могут прилетать т.н. preflight запросы перед основным для апрува хедеров, метода и хоста основного запроса.
Так вот, почему-то Application Insights SDK для JS видимо очень боится отправить эти preflight запросы и поэтому никогда не пересылает корреляционные хедеры на хосты, отличные от текущего (с учётом порта).
На команду Application Insights SDK для JS уже заведён FR по этому поводу.
В коде выше в качестве WA просто убирается проверка на соответствие хостов и таким образом, хедеры отсылаются в любом случае.
В WcfApi:
- Устанавливаем NuGet'ы Microsoft.ApplicationInsights, Microsoft.ApplicationInsights.Web, Microsoft.ApplicationInsights.Wcf (из https://www.myget.org/F/applicationinsights-sdk-labs/)
 - Удаляем из ApplicationInsights.config 
<Add Type="Microsoft.ApplicationInsights.Web.OperationNameTelemetryInitializer, Microsoft.AI.Web"/> - Помечаем атрибутом [ServiceTelemetry] класс сервиса
 - Не забываем установить Method = "*" в атрибуте WebInvoke для методов интерфейса сервиса (т.к. в него будут прилетать preflight запросы с методом OPTIONS)
 - Реализуем ответ на preflight запрос в методах сервиса
 
private bool CheckCorsPreFlight()
{
    var cors = false;
    if (WebOperationContext.Current != null)
    {
        var request = WebOperationContext.Current.IncomingRequest;
        var response = WebOperationContext.Current.OutgoingResponse;
        if (request.Method == "OPTIONS")
        {
            response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
            response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, X-Requested-With, x-ms-request-root-id, x-ms-request-id");
            response.Headers.Add("Access-Control-Allow-Credentials", "true");
            cors = true;
        }
        var origin = request.Headers.GetValues("Origin");
        if (origin.Length > 0)
            response.Headers.Add("Access-Control-Allow-Origin", origin[0]);
        else
            response.Headers.Add("Access-Control-Allow-Origin", "*");
    }
    return cors;
}В качестве бонуса — запросы для Application Insights Analytics
Получение id глобальной операции по факту просмотра страницы
pageViews
| order by timestamp desc
| project timestamp, operation_Id, name
Получение id глобальной операции по факту возникновения ошибки
exceptions
| order by timestamp desc
| project timestamp, operation_Id, problemId, assembly  Также для этих целей удобно использовать новый интерфейс Failures

Получение диагностических данных по глобальной операции
requests
| union dependencies
| union pageViews
| union exceptions
| where operation_Id == "<place operation id here>"
| order by timestamp desc
| project timestamp, itemType, data = iif(itemType == "exception", problemId, name) 

Всем спасибо
Тестовый проект на github
Что почитать:
Мега блог amptips.com
Официальная документация
Буду благодарен за любую конструктивную критику!