使用 Application Insights 監視 Azure Batch .NET 應用程式並進行偵錯

Application Insights 提供開發人員精緻且強大的方法,用來監視部署到 Azure 服務的應用程式並進行偵錯。 使用 Application Insights 監視效能計數器和例外狀況,以及透過自訂計量與追蹤來檢測您的程式碼。 整合 Application Insights 與 Azure Batch 應用程式可讓您取得行為的深入見解,並幾近即時地調查問題。

本文會示範如何將 Application Insights 程式庫新增至您的 Azure Batch .NET 解決方案並加以設定,以及檢測應用程式的程式碼。 同時示範透過 Azure 入口網站監視應用程式和建置自訂儀表板的方法。 如需了解其他語言中的 Application Insights 支援,請參閱語言、平台及整合文件。

隨附於本文的 C# 解決方案範例與程式碼可於 GitHub 中取得。 此範例會將 Application Insights 檢測程式碼新增至 TopNWords 範例。 如果您不熟悉該範例,請先嘗試建置及執行 TopNWords。 這樣做有助於你理解一個基本的批次工作流程,即在多個運算節點上平行處理一組輸入塊。

必要條件

將 Application Insights 新增到專案

您的專案需要 Microsoft.ApplicationInsights.WindowsServer NuGet 套件和其相依項目。 可將其新增或還原到您應用程式的專案。 若要安裝套件,請使用 Install-Package 命令或 NuGet 套件管理員。

Install-Package Microsoft.ApplicationInsights.WindowsServer

您可以在 .NET 應用程式中使用 Microsoft.ApplicationInsights 命名空間來參考 Application Insights。

檢測您的程式碼

若要檢測您的程式碼,您的解決方案必須建立 Application Insights TelemetryClient。 在範例中,TelemetryClient 會從 ApplicationInsights.config 檔案載入其組態。 請務必使用您的 Application Insights 檢測金鑰來更新下列專案中的 ApplicationInsights.config:Microsoft.Azure.Batch.Samples.TelemetryStartTask and TopNWordsSample。

<InstrumentationKey>YOUR-IKEY-GOES-HERE</InstrumentationKey>

也請將檢測金鑰新增到檔案 TopNWords.cs 中。

TopNWords.cs 中的範例會使用 Application Insights API 中的下列檢測呼叫:

  • TrackMetric() - 追蹤計算節點下載必要文字檔案要多久時間 (平均值)。
  • TrackTrace() - 將偵錯呼叫新增至您的程式碼。
  • TrackEvent() - 追蹤要擷取的感興趣事件。

此範例刻意省去例外狀況處理。 改為 Application Insights 會自動報告未處理的例外狀況,進而大幅改善偵錯體驗。

下列程式碼片段說明如何使用這些方法。

public void CountWords(string blobName, int numTopN, string storageAccountName, string storageAccountKey)
{
    // simulate exception for some set of tasks
    Random rand = new Random();
    if (rand.Next(0, 10) % 10 == 0)
    {
        blobName += ".badUrl";
    }

    // log the url we are downloading the file from
    insightsClient.TrackTrace(new TraceTelemetry(string.Format("Task {0}: Download file from: {1}", this.taskId, blobName), SeverityLevel.Verbose));

    // open the cloud blob that contains the book
    var storageCred = new StorageCredentials(storageAccountName, storageAccountKey);
    CloudBlockBlob blob = new CloudBlockBlob(new Uri(blobName), storageCred);
    using (Stream memoryStream = new MemoryStream())
    {
        // calculate blob download time
        DateTime start = DateTime.Now;
        blob.DownloadToStream(memoryStream);
        TimeSpan downloadTime = DateTime.Now.Subtract(start);

        // track how long the blob takes to download on this node
        // this will help debug timing issues or identify poorly performing nodes
        insightsClient.TrackMetric("Blob download in seconds", downloadTime.TotalSeconds, this.CommonProperties);

        memoryStream.Position = 0; //Reset the stream
        var sr = new StreamReader(memoryStream);
        var myStr = sr.ReadToEnd();
        string[] words = myStr.Split(' ');

        // log how many words were found in the text file
        insightsClient.TrackTrace(new TraceTelemetry(string.Format("Task {0}: Found {1} words", this.taskId, words.Length), SeverityLevel.Verbose));
        var topNWords =
            words.
                Where(word => word.Length > 0).
                GroupBy(word => word, (key, group) => new KeyValuePair<String, long>(key, group.LongCount())).
                OrderByDescending(x => x.Value).
                Take(numTopN).
                ToList();
        foreach (var pair in topNWords)
        {
            Console.WriteLine("{0} {1}", pair.Key, pair.Value);
        }

        // emit an event to track the completion of the task
        insightsClient.TrackEvent("Done counting words");
    }
}

Azure Batch 遙測初始化設定式輔助程式

報告指定伺服器和執行個體的遙測時,Application Insights 會使用 Azure VM 角色和 VM 名稱作為預設值。 在 Azure Batch 的情境下,此範例說明如何改用集區名稱和計算節點名稱。 使用遙測初始化程式來覆寫預設值。

using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
using System;
using System.Threading;

namespace Microsoft.Azure.Batch.Samples.TelemetryInitializer
{
    public class AzureBatchNodeTelemetryInitializer : ITelemetryInitializer
    {
        // Azure Batch environment variables
        private const string PoolIdEnvironmentVariable = "AZ_BATCH_POOL_ID";
        private const string NodeIdEnvironmentVariable = "AZ_BATCH_NODE_ID";

        private string roleInstanceName;
        private string roleName;

        public void Initialize(ITelemetry telemetry)
        {
            if (string.IsNullOrEmpty(telemetry.Context.Cloud.RoleName))
            {
                // override the role name with the Azure Batch Pool name
                string name = LazyInitializer.EnsureInitialized(ref this.roleName, this.GetPoolName);
                telemetry.Context.Cloud.RoleName = name;
            }

            if (string.IsNullOrEmpty(telemetry.Context.Cloud.RoleInstance))
            {
                // override the role instance with the Azure Batch Compute Node name
                string name = LazyInitializer.EnsureInitialized(ref this.roleInstanceName, this.GetNodeName);
                telemetry.Context.Cloud.RoleInstance = name;
            }
        }

        private string GetPoolName()
        {
            return Environment.GetEnvironmentVariable(PoolIdEnvironmentVariable) ?? string.Empty;
        }

        private string GetNodeName()
        {
            return Environment.GetEnvironmentVariable(NodeIdEnvironmentVariable) ?? string.Empty;
        }
    }
}

若要啟用遙測初始設定式,TopNWordsSample 專案中的 ApplicationInsights.config 檔案包含下列內容:

<TelemetryInitializers>
    <Add Type="Microsoft.Azure.Batch.Samples.TelemetryInitializer.AzureBatchNodeTelemetryInitializer, Microsoft.Azure.Batch.Samples.TelemetryInitializer"/>
</TelemetryInitializers>

更新作業和任務,以納入 Application Insights 的二進位檔

為了讓 Application Insights 在節點上正確地執行,請確定二進位檔位於正確位置。 請將所需的二進位檔新增至您工作資源檔案的集合,使其能在工作執行時加以下載。 下列程式碼片段類似於 Job.cs 中的程式碼。

首先,建立要上傳的 Application Insights 檔案靜態清單。

private static readonly List<string> AIFilesToUpload = new List<string>()
{
    // Application Insights config and assemblies
    "ApplicationInsights.config",
    "Microsoft.ApplicationInsights.dll",
    "Microsoft.AI.Agent.Intercept.dll",
    "Microsoft.AI.DependencyCollector.dll",
    "Microsoft.AI.PerfCounterCollector.dll",
    "Microsoft.AI.ServerTelemetryChannel.dll",
    "Microsoft.AI.WindowsServer.dll",

    // custom telemetry initializer assemblies
    "Microsoft.Azure.Batch.Samples.TelemetryInitializer.dll",
 };
...

接下來,建立任務所使用的暫存檔案。

...
// create file staging objects that represent the executable and its dependent assembly to run as the task.
// These files are copied to every node before the corresponding task is scheduled to run on that node.
FileToStage topNWordExe = new FileToStage(TopNWordsExeName, stagingStorageAccount);
FileToStage storageDll = new FileToStage(StorageClientDllName, stagingStorageAccount);

// Upload Application Insights assemblies
List<FileToStage> aiStagedFiles = new List<FileToStage>();
foreach (string aiFile in AIFilesToUpload)
{
    aiStagedFiles.Add(new FileToStage(aiFile, stagingStorageAccount));
}
...

FileToStage 方法是程式碼範例中的協助程式函式,可讓您輕鬆地將檔案從本機磁碟中上傳至 Azure 儲存體 Blob。 之後會將每個檔案下載到運算節點,並由工作加以引用。

最後,將任務新增至工作,並納入必要的 Application Insights 二進位檔案。

...
// initialize a collection to hold the tasks that will be submitted in their entirety
List<CloudTask> tasksToRun = new List<CloudTask>(topNWordsConfiguration.NumberOfTasks);
for (int i = 1; i <= topNWordsConfiguration.NumberOfTasks; i++)
{
    CloudTask task = new CloudTask("task_no_" + i, String.Format("{0} --Task {1} {2} {3} {4}",
        TopNWordsExeName,
        string.Format("https://{0}.blob.core.windows.net/{1}",
            accountSettings.StorageAccountName,
            documents[i]),
        topNWordsConfiguration.TopWordCount,
        accountSettings.StorageAccountName,
        accountSettings.StorageAccountKey));

    //This is the list of files to stage to a container -- for each job, one container is created and
    //files all resolve to Azure Blobs by their name (so two tasks with the same named file will create just 1 blob in
    //the container).
    task.FilesToStage = new List<IFileStagingProvider>
                        {
                            // required application binaries
                            topNWordExe,
                            storageDll,
                        };
    foreach (FileToStage stagedFile in aiStagedFiles)
   {
        task.FilesToStage.Add(stagedFile);
   }
    task.RunElevated = false;
    tasksToRun.Add(task);
}

檢視 Azure 入口網站中的資料

現在您已將作業和工作設定為使用 Application Insights,接著請在您的集區中執行範例作業。 瀏覽至 Azure 入口網站,並開啟您佈建的 Application Insights 資源。 集區佈建完成後,您應該會開始看到資料流入,並被記錄下來。 本文其餘部分只會說明幾個 Application Insights 功能,但您可以隨意地探索完整的功能集。

檢視即時資料流

若要在應用洞察資源中查看追蹤日誌,請選擇 「即時串流」。 下列螢幕擷取畫面說明如何檢視來自集區中計算節點的即時資料,例如每個計算節點的 CPU 使用量。

即時串流計算節點資料的螢幕擷取畫面。

檢視追蹤記錄

若要在你的應用洞察資源中查看追蹤日誌,請選擇 搜尋。 此檢視會顯示 Application Insights 所擷取的診斷資料清單,其中包括追蹤、事件和例外狀況。

下列螢幕截圖顯示如何記錄某項工作的單一追蹤記錄,以及之後如何為了偵錯而加以查詢。

顯示單一追蹤記錄的螢幕擷取畫面。

檢視未處理的例外狀況

Application Insights 會記錄從您的應用程式擲回的例外狀況。 在此案例中,在應用程式擲回例外狀況的幾秒內,您就可以深入了解特定例外狀況並診斷問題。

顯示未處理的例外狀況的螢幕擷取畫面。

測量 Blob 下載時間

自訂計量也是入口網站中的實用工具。 例如,您可以顯示每個計算節點下載所處理的必要文字檔案時,所花費的平均時間。

建立範例圖表:

  1. 在你的應用程式洞察資源中,選擇 「指標總覽」「>新增圖表」。
  2. 在新增的圖表上選擇 編輯 。
  3. 更新圖表的詳細資料,如下所示:
    • 將 [圖表類型] 設定為 [方格]。
    • 將 [彙總] 設定為 [平均]。
    • 將分組依據設為NodeId。
    • 在[計量值]中,選取[自訂]>[Blob 下載時間(秒)]。
    • 您可以依喜好調整顯示的 [色彩調色盤]。

顯示每個節點 Blob 下載時間圖表的螢幕擷取畫面。

持續監視計算節點

你可能注意到所有指標,包括效能計數器,只有在任務執行時才會被記錄。 此行為是非常實用,因為這會限制 Application Insights 記錄的資料量。 不過,在某些情況下,您可能需要一直監視計算節點。 例如,它們可能是未透過 Batch 服務進行排程的執行中背景工作。 在此情況下,請針對計算節點的存留期,設定要執行的監視程序。

要完成此行為的方法之一是繁衍程序來載入 Application Insights 程式庫,並在背景中執行。 在範例中,啟動工作會在機器上載入二進位檔,並會無限期地持續執行處理程序。 設定此處理程序的 Application Insights 組態檔,以發出您關注的其他資料,例如效能計數器。

...
 // Batch start task telemetry runner
private const string BatchStartTaskFolderName = "StartTask";
private const string BatchStartTaskTelemetryRunnerName = "Microsoft.Azure.Batch.Samples.TelemetryStartTask.exe";
private const string BatchStartTaskTelemetryRunnerAIConfig = "ApplicationInsights.config";
...
CloudPool pool = client.PoolOperations.CreatePool(
    topNWordsConfiguration.PoolId,
    targetDedicated: topNWordsConfiguration.PoolNodeCount,
    virtualMachineSize: "standard_d1_v2",
    VirtualMachineConfiguration: new VirtualMachineConfiguration(
    imageReference: new ImageReference(
                        publisher: "MicrosoftWindowsServer",
                        offer: "WindowsServer",
                        sku: "2019-datacenter-core",
                        version: "latest"),
    nodeAgentSkuId: "batch.node.windows amd64");
...

// Create a start task which will run a dummy exe in background that simply emits performance
// counter data as defined in the relevant ApplicationInsights.config.
// Note that the waitForSuccess on the start task was not set so the Compute Node will be
// available immediately after this command is run.
pool.StartTask = new StartTask()
{
    CommandLine = string.Format("cmd /c {0}", BatchStartTaskTelemetryRunnerName),
    ResourceFiles = resourceFiles
};
...

提示

若要增加解決方案的可管理性,您可以搭配應用程式套件中的組件。 然後,若要讓應用程式套件自動部署至您的集區,請將應用程式套件參考新增至集區組態。

節流與樣本資料

由於在生產環境中執行的 Azure Batch 應用程式本質上都是大規模運作,因此建議您藉由限制 Application Insights 所收集的資料量來管理成本。 請參閱 Application Insights 中的取樣,以了解完成此操作的一些機制。

下一步