針對適用於 Windows 的 Log Analytics 代理程式的問題進行疑難排解

本文協助您針對 Azure 監視器中適用於 Windows 的 Log Analytics 代理程式的錯誤進行疑難排解,並建議可解決問題的解決方法。

Log Analytics 疑難排解工具

適用於 Windows 的 Log Analytics 代理程式疑難排解工具是 PowerShell 指令碼的集合,其設計目的是協助尋找和診斷 Log Analytics 代理程式的問題。 此工具在代理程式安裝時即已自動隨附。 診斷問題的第一個步驟應該是執行此工具。

使用疑難排解工具

  1. 在 Log Analytics 代理程式安裝所在的機器上,以系統管理員身分開啟 PowerShell 提示字元。

  2. 前往工具所在的目錄:

    cd "C:\Program Files\Microsoft Monitoring Agent\Agent\Troubleshooter"

  3. 使用下列命令來執行主要指令碼:

    .\GetAgentInfo.ps1

  4. 選取疑難排解案例。

  5. 遵循主控台上的指示。 請注意,追蹤記錄步驟需要手動介入,才能停止記錄收集。 根據問題的重現性,等候持續時間,並選取 's' 來停止記錄收集,然後繼續進行下一個步驟。

    結果檔案的位置會在完成時加以記錄,並且開啟將其醒目提示的新總管視窗。

安裝

安裝 Log Analytics 代理程式組建 10.20.18053.0 和更新版本時,會自動包括疑難排解工具。

涵蓋的案例

疑難排解工具會檢查是否有下列狀況:

  • 代理程式未報告資料,或遺漏活動訊號資料。
  • 代理程式延伸模組部署失敗。
  • 代理程式失效。
  • 代理程式耗用高 CPU 或記憶體。
  • 安裝和解除安裝體驗失敗。
  • 自訂記錄發生問題。
  • OMS 閘道發生問題。
  • 效能計數器發生問題。
  • 無法收集代理程式記錄。

注意

當您遇到問題時,請執行疑難排解工具。 一開始就準備好相關記錄,將有助於支援小組更快針對您的問題進行疑難排解。

重要疑難排解來源

為了協助針對與適用於 Windows 的 Log Analytics 代理程式相關的問題進行疑難排解,代理程式會將事件記錄到 Windows 事件記錄檔,特別是 Application and Services\Operations Manager 底下。

連線能力問題

如果代理程式是透過 Proxy 伺服器或防火牆進行通訊,則可能會有適當的限制,防止來自來源電腦和 Azure 監視器服務的通訊。 如果通訊因設定錯誤而遭到封鎖,則嘗試安裝代理程式或設定代理程式後安裝以回報另一個工作區時,向工作區註冊可能會失敗。 成功註冊之後,代理程式通訊可能會失敗。 本節描述針對 Windows 代理程式這類問題進行疑難排解的方法。

重複檢查防火牆或 Proxy 是否已設定為允許下表所述的下列連接埠和 URL。 也請確認未針對 Web 流量啟用 HTTP 檢查。 因為其可能會防止代理程式與 Azure 監視器之間的安全 TLS 通道。

代理程式資源 連接埠 方向 略過 HTTPS 檢查
*.ods.opinsights.azure.com 連接埠 443 出埠
*.oms.opinsights.azure.com 連接埠 443 出埠
*.blob.core.windows.net 連接埠 443 出埠 Yes
*.agentsvc.azure-automation.net 連接埠 443 出埠 Yes

如需 Azure Government 所需的防火牆資訊,請參閱 Azure Government 管理。 如果您打算使用 Azure 自動化混合式 Runbook 背景工作角色連線到自動化服務並向其註冊,以便在您的環境中使用 Runbook 或管理解決方案,其必須具有設定適用於混合式 Runbook 背景工作角色的網路中所述的連接埠號碼和 URL 存取權。

有數種方式可以驗證代理程式是否與 Azure 監視器成功地通訊:

  • 在工作區中啟用 Azure Log Analytics 代理程式健全狀況評估。 從 [代理程式健全狀況] 儀表板中,檢視 [沒有回應的代理程式計數] 資料行,以快速查看代理程式是否已列出。

  • 執行下列查詢,以確認代理程式正在將活動訊號傳送至其設定為要回報的工作區。 將 <ComputerName> 取代為機器名稱的實際名稱。

    Heartbeat 
    | where Computer like "<ComputerName>"
    | summarize arg_max(TimeGenerated, * ) by Computer 
    

    如果電腦已與服務成功地通訊,查詢應該會傳回結果。 如果查詢未傳回結果,則請先驗證代理程式是否已設定為回報正確的工作區。 如果已正確設定,則請繼續進行步驟 3 並搜尋 Windows 事件記錄檔,以識別代理程式是否正在記錄哪個問題可能會防止其與 Azure 監視器通訊。

  • 另一個識別連線問題的方法,就是執行 TestCloudConnectivity 工具。 此工具預設會與 %SystemRoot%\Program Files\Microsoft Monitoring Agent\Agent 資料夾中的代理程式一起安裝。 從已提升權限的命令提示字元中前往資料夾,然後執行該工具。 該工具會傳回結果,並醒目提示測試失敗之處。 例如,這或許與封鎖的特定連接埠或 URL 有關。

    Screenshot that shows TestCloudConnection tool execution results.

  • 依 [事件來源]「健全狀況服務模組」、「HealthService」和「服務連接器」來篩選 Operations Manager 事件記錄檔,並依 [事件層級]「警告」和「錯誤」進行篩選,以確認其是否已從下表寫入事件。 如果是,請檢閱針對每個可能事件所包含的解決步驟。

    事件識別碼 來源 描述 解決方案
    2133 & 2129 健康情況服務 從代理程式連線至服務失敗。 代理程式無法直接或透過防火牆或 Proxy 伺服器與 Azure 監視器服務通訊時,會發生此錯誤。 驗證代理程式 Proxy 設定,或驗證網路防火牆或 Proxy 是否允許從電腦到服務的 TCP 流量。
    2138 健全狀況服務模組 Proxy 需要驗證。 設定代理程式 Proxy 設定,並指定使用 Proxy 伺服器進行驗證所需的使用者名稱/密碼。
    2129 健全狀況服務模組 連線失敗。 TLS 交涉失敗。 檢查網路介面卡 TCP/IP 設定和代理程式 Proxy 設定。
    2127 健全狀況服務模組 傳送資料失敗並收到錯誤碼。 如果其只在白天定期發生,則可能是可忽略的隨機異常。 監視以了解其發生頻率。 如果其整天經常發生,請先檢查您的網路設定和 Proxy 設定。 如果描述包含 HTTP 錯誤碼 404,且代理程式是第一次嘗試將資料傳送至服務,其將會包含 500 錯誤,內含 404 錯誤碼。 404 錯誤碼表示「找不到」,這指出仍在佈建新工作區的儲存區域。 下次重試時,資料會如預期般成功地寫入至工作區。 HTTP 錯誤 403 可能指出權限或認證問題。 403 錯誤包括詳細資訊,可協助針對問題進行疑難排解。
    4000 服務連接器 DNS 名稱解析失敗。 機器無法解析將資料傳送至服務時所使用的網際網路位址。 此問題可能是您機器上的 DNS 解析程式設定、Proxy 設定不正確,或您的提供者發生暫時性 DNS 問題。 如果其定期發生,可能是由於暫時性網路相關問題所造成。
    4001 服務連接器 連線至服務失敗。 代理程式無法直接或透過防火牆或 Proxy 伺服器與 Azure 監視器服務通訊時,會發生此錯誤。 驗證代理程式 Proxy 設定,或驗證網路防火牆或 Proxy 是否允許從電腦到服務的 TCP 流量。
    4002 服務連接器 服務傳回 HTTP 狀態代碼 403 以回應查詢。 請與服務管理員一起檢查服務的健康情況。 稍後會重試查詢。 此錯誤是在代理程式初始註冊階段期間寫入。 您會看到類似 https://<workspaceID>.oms.opinsights.azure.com/AgentService.svc/AgentTopologyRequest 的 URL。 403 錯誤碼表示「禁止」,而且可能是輸入錯誤的工作區識別碼或金鑰所造成。 電腦上的日期和時間也可能不正確。 如果時間為目前時間算起的 +/-15 分鐘,則上線會失敗。 若要更正此問題,請更新 Windows 電腦的日期和 (或) 時間。

資料收集問題

在代理程式完成安裝並回報其設定的工作區之後,其可能會停止接收設定,以及收集或轉送效能、記錄或其他資料至服務,這取決於啟用的內容並以電腦為目標。 您必須決定︰

  • 其是特定資料類型,還是無法在工作區中使用的所有資料?
  • 資料類型是由解決方案所指定,還是指定為工作區資料收集設定的一部分?
  • 多少部電腦受到影響? 是單一電腦還是多部電腦回報工作區?
  • 其運作正常並在一天的特定時間停止,還是從未進行收集?
  • 您正在使用的記錄搜尋查詢語法是否正確?
  • 代理程式是否曾經從 Azure 監視器收到其設定?

疑難排解的第一個步驟是判斷電腦是否正在傳送活動訊號事件。

Heartbeat 
    | where Computer like "<ComputerName>"
    | summarize arg_max(TimeGenerated, * ) by Computer

如果查詢傳回結果,則您需要判斷是否未收集特定資料類型並將其轉送至服務。 此問題的造成原因可能是代理程式未從服務接收已更新的設定,或某些其他徵兆防止代理程式正常運作。 請執行下列步驟以進一步疑難排解。

  1. 在電腦上開啟提高權限的命令提示字元,並輸入 net stop healthservice && net start healthservice 來重新啟動代理程式服務。

  2. 開啟 Operations Manager 事件記錄檔,並從事件來源HealthService 搜尋事件識別碼7023、7024、7025、70281210。 這些事件指出代理程式正在從 Azure 監視器成功地接收設定,並且正在主動監視電腦。 事件識別碼 1210 的事件描述也會最後一行上,指定代理程式上監視範圍中包含的所有解決方案和深入解析。

    Screenshot that shows an Event ID 1210 description.

  3. 請等候幾分鐘。 如果您在查詢結果或視覺效果中看不到預期資料,則根據您正在檢視的資料來自解決方案還是深入解析,從 Operations Manager 事件記錄檔中搜尋 [事件來源]「HealthService」和「健全狀況服務模組」。 依 [事件層級]「警告」和「錯誤」進行篩選,以確認其是否已從下表寫入事件。

    事件識別碼 來源 描述 解決方案
    8000 HealthService 此事件會指定與所收集效能、事件或其他資料類型相關的工作流程是否無法轉送至服務,以擷取至工作區。 來源 HealthService 的事件識別碼 2136 會與此事件一起寫入,而且指出代理程式無法與服務進行通訊。 可能的原因可能是錯誤地設定 Proxy 和驗證設定、網路中斷,或是網路防火牆或 Proxy 不允許從電腦到服務的 TCP 流量。
    10102 和 10103 健全狀況服務模組 工作流程無法解析資料來源。 如果指定的效能計數器或執行個體不存在於電腦上,或未正確地定義在工作區資料設定中,則會發生此問題。 如果這是使用者指定的效能計數器,則請驗證指定的資訊是否遵循正確的格式,並存在於目標電腦上。
    26002 健全狀況服務模組 工作流程無法解析資料來源。 如果指定的 Windows 事件記錄檔不存在於電腦上,則會發生此問題。 如果電腦未預期註冊此事件記錄檔,則可以放心地忽略此錯誤。 否則,如果這是使用者指定的事件記錄檔,則請確認指定的資訊正確。

舊版 Microsoft Monitoring Agent 的釘選憑證問題 - 中斷性變更

根 CA 變更概觀

自 2023 年 6 月 30 日起,Log Analytics 後端將不再接受參考無效根證書的 MMA 連線。 這些 MMA 是 2020 年冬季版本 (Log Analytics Agent) 和 SCOM 2019 UR3 (SCOM) 之前的舊版。 任何版本套件組合:10.20.18053 / 擴充功能:1.0.18053.0 或更新版本將不會有任何問題,以及任何高於 SCOM 2019 UR3 的版本。 任何比較舊的代理程式都會中斷,且不再運作並上傳至Log Analytics。

到底有什麼變更?

作為跨各種 Azure 服務進行中安全性工作的一部分,Azure Log Analytics 將正式從 Baltimore CyberTrust CA 根目錄切換至 DigiCert Global G2 CA 根。 如果 OS 缺少新的 DigiCert Global G2 CA 根憑證,或應用程式參考舊的 Baltimore 根 CA,這項變更會影響與 Log Analytics 的 TLS 通訊。 這表示 Log Analytics 將不再接受來自 MMA 的連線,且在淘汰之後會使用舊的根 CA。

解決方案產品

即使您尚未親自安裝 Microsoft Monitoring Agent,您也可能收到重大變更通知。 這是因為各種 Azure 產品會利用 Microsoft Monitoring Agent。 如果您使用其中一個產品,可能會因為使用 Windows Log Analytics 代理程式而受到影響。 針對以下連結的產品,可能會有特定指示會要求您升級至最新的代理程式。

識別和修補中斷代理程式

對於具有有限代理程式的部署,強烈建議您透過這些管理指示,升級每個節點的代理程式。

針對具有多個節點的部署,我們撰寫了指令碼,以偵測每個訂用帳戶任何受影響的中斷 MMA,然後升級至最新版本。 這些指令碼必須循序執行,從 UpdateMMA.ps1 開始,然後從 UpgradeMMA.ps1 開始。 視機器而定,指令碼可能需要一段時間。 需要 PowerShell 7 或更新版本才能執行,以避免逾時。

UpdateMMA.ps1 此指令碼將會透過訂用帳戶中的 VM,檢查已安裝的現有 MMA,然後產生需要升級的代理程式 .csv 檔案。

UpgradeMMA.ps1 此文稿將會使用 UpdateMMA.ps1 中產生的 .CSV 檔案,以升級所有中斷的 MMA。

這兩個指令碼可能需要一段時間才能完成。

# UpdateMMA.ps1
# This script is to be run per subscription, the customer has to set the az subscription before running this within the terminal scope.
# This script uses parallel processing, modify the $parallelThrottleLimit parameter to either increase or decrease the number of parallel processes
# PS> .\UpdateMMA.ps1 GetInventory
# The above command will generate a csv file with the details of VM's and VMSS that require MMA upgrade. 
# The customer can modify the csv by adding/removing rows if needed
# Update the MMA by running the script again and passing the csv file as parameter as shown below:
# PS> .\UpdateMMA.ps1 Upgrade
# If you don't want to check the inventory, then run the script wiht an additional -no-inventory-check
# PS> .\UpdateMMA.ps1 GetInventory & .\UpdateMMA.ps1 Upgrade


# This version of the script requires Powershell version >= 7 in order to improve performance via ForEach-Object -Parallel
# https://docs.microsoft.com/powershell/scripting/whats-new/migrating-from-windows-powershell-51-to-powershell-7?view=powershell-7.1
if ($PSVersionTable.PSVersion.Major -lt 7) 
{
    Write-Host "This script requires Powershell version 7 or newer to run. Please see https://docs.microsoft.com/powershell/scripting/whats-new/migrating-from-windows-powershell-51-to-powershell-7?view=powershell-7.1."
    exit 1
}

$parallelThrottleLimit = 16
$mmaFixVersion = [version]"10.20.18053.0"

function GetVmsWithMMAInstalled
{
    param(
        $fileName
    )

    $vmList = az vm list --show-details --query "[?powerState=='VM running'].{ResourceGroup:resourceGroup, VmName:name}" | ConvertFrom-Json
    
    if(!$vmList)
    {
        Write-Host "Cannot get the VM list, this script can only detect the running VM's"
        return
    }

    $vmsCount = $vmList.Length
    
    $vmParallelThrottleLimit = $parallelThrottleLimit
    if ($vmsCount -lt $vmParallelThrottleLimit) 
    {
        $vmParallelThrottleLimit = $vmsCount
    }

    if($vmsCount -eq 1)
    {
        $vmGroups += ,($vmList[0])
    }
    else
    {
        # split the vm's into batches to do parallel processing
        for ($i = 0; $i -lt $vmsCount; $i += $vmParallelThrottleLimit) 
        { 
            $vmGroups += , ($vmList[$i..($i + $vmParallelThrottleLimit - 1)]) 
        }
    }

    Write-Host "Detected $vmsCount Vm's running in this subscription."
    $hash = [hashtable]::Synchronized(@{})
    $hash.One = 1

    $vmGroups | Foreach-Object -ThrottleLimit $parallelThrottleLimit -Parallel {
        $len = $using:vmsCount
        $hash = $using:hash
        $_ | ForEach-Object {
            $percent = 100 * $hash.One++ / $len
            Write-Progress -Activity "Getting VM Inventory" -PercentComplete $percent
            $vmName = $_.VmName
            $resourceGroup = $_.ResourceGroup
            $responseJson = az vm run-command invoke --command-id RunPowerShellScript --name $vmName -g $resourceGroup --scripts '@UpgradeMMA.ps1' --parameters "functionName=GetMMAVersion" --output json | ConvertFrom-Json
            if($responseJson)
            {
                $mmaVersion = $responseJson.Value[0].message
                if ($mmaVersion) 
                {
                    $extensionName = az vm extension list -g $resourceGroup --vm-name $vmName --query "[?name == 'MicrosoftMonitoringAgent'].name" | ConvertFrom-Json
                    if ($extensionName) 
                    {
                        $installType = "Extension"
                    }
                    else 
                    {
                        $installType = "Installer"
                    }
                    $csvObj = New-Object -TypeName PSObject -Property @{
                        'Name'           = $vmName
                        'Resource_Group' = $resourceGroup
                        'Resource_Type'  = "VM"
                        'Install_Type'   = $installType
                        'Version'        = $mmaVersion
                        "Instance_Id"    = ""
                    }
                    $csvObj | Export-Csv $using:fileName -Append -Force
                } 
            } 
        }
    }
}

function GetVmssWithMMAInstalled
{
    param(
        $fileName
    )

    # get the vmss list which are successfully provisioned
    $vmssList = az vmss list --query "[?provisioningState=='Succeeded'].{ResourceGroup:resourceGroup, VmssName:name}" | ConvertFrom-Json   

    $vmssCount = $vmssList.Length
    Write-Host "Detected $vmssCount Vmss running in this subscription."
    $hash = [hashtable]::Synchronized(@{})
    $hash.One = 1

    $vmssList | Foreach-Object -ThrottleLimit $parallelThrottleLimit -Parallel {
        $len = $using:vmssCount
        $hash = $using:hash
        $percent = 100 * $hash.One++ / $len
        Write-Progress -Activity "Getting VMSS Inventory" -PercentComplete $percent
        $vmssName = $_.VmssName
        $resourceGroup = $_.ResourceGroup

        # get running vmss instance ids
        $vmssInstanceIds = az vmss list-instances --resource-group $resourceGroup --name $vmssName --expand instanceView --query "[?instanceView.statuses[1].displayStatus=='VM running'].instanceId" | ConvertFrom-Json
        if ($vmssInstanceIds.Length -gt 0) 
        {
            $isMMAExtensionInstalled = az vmss extension list -g $resourceGroup --vmss-name $vmssName --query "[?name == 'MicrosoftMonitoringAgent'].name" | ConvertFrom-Json
            if ($isMMAExtensionInstalled ) 
            {
                # check an instance in vmss, if it needs an MMA upgrade. Since the extension is installed at VMSS level, checking for bad version in 1 instance should be fine.
                $responseJson = az vmss run-command invoke --command-id RunPowerShellScript --name $vmssName -g $resourceGroup --instance-id $vmssInstanceIds[0] --scripts '@UpgradeMMA.ps1' --parameters "functionName=GetMMAVersion" --output json | ConvertFrom-Json
                $mmaVersion = $responseJson.Value[0].message
                if ($mmaVersion) 
                {
                    $csvObj = New-Object -TypeName PSObject -Property @{
                        'Name'           = $vmssName
                        'Resource_Group' = $resourceGroup
                        'Resource_Type'  = "VMSS"
                        'Install_Type'   = "Extension"
                        'Version'        = $mmaVersion
                        "Instance_Id"    = ""
                    }
                    $csvObj | Export-Csv $using:fileName -Append -Force
                }
            }
            else 
            {
                foreach ($instanceId in $vmssInstanceIds) 
                {
                    $responseJson = az vmss run-command invoke --command-id RunPowerShellScript --name $vmssName -g $resourceGroup --instance-id $instanceId --scripts '@UpgradeMMA.ps1' --parameters "functionName=GetMMAVersion" --output json | ConvertFrom-Json
                    $mmaVersion = $responseJson.Value[0].message
                    if ($mmaVersion) 
                    {
                        $csvObj = New-Object -TypeName PSObject -Property @{
                            'Name'           = $vmssName
                            'Resource_Group' = $resourceGroup
                            'Resource_Type'  = "VMSS"
                            'Install_Type'   = "Installer"
                            'Version'        = $mmaVersion
                            "Instance_Id"    = $instanceId
                        }
                        $csvObj | Export-Csv $using:fileName -Append -Force
                    }
                }
            }
        }      
    }
}

function Upgrade
{
    param(
        $fileName = "MMAInventory.csv"
    )
    Import-Csv $fileName | ForEach-Object -ThrottleLimit $parallelThrottleLimit -Parallel {
        $mmaVersion = [version]$_.Version
        if($mmaVersion -lt $using:mmaFixVersion)
        {
            if ($_.Install_Type -eq "Extension") 
            {
                if ($_.Resource_Type -eq "VMSS") 
                {
                    # if the extension is installed with a custom name, provide the name using the flag: --extension-instance-name <extension name>
                    az vmss extension set --name MicrosoftMonitoringAgent --publisher Microsoft.EnterpriseCloud.Monitoring --force-update --vmss-name $_.Name --resource-group $_.Resource_Group --no-wait --output none
                }
                else 
                {
                    # if the extension is installed with a custom name, provide the name using the flag: --extension-instance-name <extension name>
                    az vm extension set --name MicrosoftMonitoringAgent --publisher Microsoft.EnterpriseCloud.Monitoring --force-update --vm-name $_.Name --resource-group $_.Resource_Group --no-wait --output none
                }
            }
            else {
                if ($_.Resource_Type -eq "VMSS") 
                {
                    az vmss run-command invoke --command-id RunPowerShellScript --name $_.Name -g $_.Resource_Group --instance-id $_.Instance_Id --scripts '@UpgradeMMA.ps1' --parameters "functionName=UpgradeMMA" --output none
                }
                else 
                {
                    az vm run-command invoke --command-id RunPowerShellScript --name $_.Name -g $_.Resource_Group --scripts '@UpgradeMMA.ps1' --parameters "functionName=UpgradeMMA" --output none
                }
            }
        }
    }
}

function GetInventory
{
    param(
        $fileName = "MMAInventory.csv"
    )

    # create a new file 
    New-Item -Name $fileName -ItemType File -Force
    GetVmsWithMMAInstalled $fileName
    GetVmssWithMMAInstalled $fileName
}

switch ($args.Count)
{
    0 {
        Write-Host "The arguments provided are incorrect."
        Write-Host "To get the Inventory: Run the script as: PS> .\UpdateMMA.ps1 GetInventory"
        Write-Host "To update MMA from Inventory: Run the script as: PS> .\UpdateMMA.ps1 Upgrade"
        Write-Host "To do the both steps together: PS> .\UpdateMMA.ps1 GetInventory & .\UpdateMMA.ps1 Upgrade"
    }
    1 {
        $funcname = $args[0]
        Invoke-Expression "& $funcname"
    }
    2 {
        $funcname = $args[0]
        $funcargs = $args[1]
        Invoke-Expression "& $funcname $funcargs"
    }
}