Skip to main content
Glama

Azure MCP Server

Official
MIT License
1,161
  • Linux
  • Apple
LogAnalyticsHelper.cs7.11 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Net; using System.Text.Json; using System.Text.Json.Serialization; using Azure.Core; using Azure.Monitor.Ingestion; using AzureMcp.Core.Services.Azure.Authentication; using AzureMcp.Monitor.Services; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; namespace AzureMcp.Monitor.LiveTests; /// <summary> /// Helper class for sending logs to Azure Log Analytics using the Azure Monitor Ingestion SDK. /// </summary> /// <remarks> /// Initializes a new instance of the LogAnalyticsHelper class. /// </remarks> public class LogAnalyticsHelper( string workspaceName, string subscription, IMonitorService monitorService, string? tenantId = null, string logType = "TestLogs_CL", ILogger? logger = null) { private readonly string _workspaceName = workspaceName; private readonly string _subscription = subscription; private readonly string _logType = logType; private readonly string? _tenantId = tenantId; private readonly TokenCredential _credential = new CustomChainedCredential(tenantId); private readonly IMonitorService _monitorService = monitorService ?? throw new ArgumentNullException(nameof(monitorService)); private readonly ILogger _logger = logger ?? NullLogger.Instance; private readonly SemaphoreSlim _clientInitLock = new(1, 1); private string? _workspaceId; private LogsIngestionClient? _logsIngestionClient; private async Task<string> GetWorkspaceIdAsync() { if (!string.IsNullOrEmpty(_workspaceId)) { return _workspaceId; } // Get workspace info using the monitor service var workspaces = await _monitorService.ListWorkspaces(_subscription, _tenantId); var workspace = workspaces.FirstOrDefault(w => w.Name.Equals(_workspaceName, StringComparison.OrdinalIgnoreCase)) ?? throw new InvalidOperationException($"Could not find workspace {_workspaceName}"); _workspaceId = workspace.CustomerId; return _workspaceId; } private async Task<LogsIngestionClient> GetLogsIngestionClientAsync(string customerId) { if (_logsIngestionClient != null) { return _logsIngestionClient; } if (string.IsNullOrEmpty(customerId)) { throw new ArgumentNullException(nameof(customerId), "Customer ID cannot be null or empty"); } await _clientInitLock.WaitAsync(); try { // Double-check after acquiring lock if (_logsIngestionClient != null) { return _logsIngestionClient; } var endpoint = new Uri($"https://{customerId}.ods.opinsights.azure.com"); var options = new LogsIngestionClientOptions { Retry = { MaxRetries = 3, Delay = TimeSpan.FromSeconds(2), MaxDelay = TimeSpan.FromSeconds(10) } }; _logsIngestionClient = new LogsIngestionClient(endpoint, _credential, options); return _logsIngestionClient; } catch (Exception ex) { throw new InvalidOperationException($"Failed to create LogsIngestionClient: {ex.Message}", ex); } finally { _clientInitLock.Release(); } } /// <summary> /// Creates and sends a log with the specified level and message. /// </summary> private async Task<HttpStatusCode> CreateAndSendLogAsync( string level, string message, CancellationToken cancellationToken = default) { var workspaceId = await GetWorkspaceIdAsync().ConfigureAwait(false); var log = new LogRecord { TimeGenerated = DateTimeOffset.UtcNow, Level = level, Message = message, Application = "MonitorCommandTests" }; return await SendLogAsync(workspaceId, [log], cancellationToken).ConfigureAwait(false); } /// <summary> /// Sends an information level log message. /// </summary> public Task<HttpStatusCode> SendInfoLogAsync(CancellationToken cancellationToken = default) { return CreateAndSendLogAsync( "Information", $"Test info message: {DateTimeOffset.UtcNow:O}", cancellationToken); } /// <summary> /// Sends both information and error test logs. /// </summary> public async Task<(HttpStatusCode infoStatus, HttpStatusCode errorStatus)> SendTestLogsAsync( string testId, CancellationToken cancellationToken = default) { var infoStatus = await CreateAndSendLogAsync( "Information", $"Test info message: {testId}", cancellationToken).ConfigureAwait(false); var errorStatus = await CreateAndSendLogAsync( "Error", $"Test error message {Guid.NewGuid()}", cancellationToken).ConfigureAwait(false); return (infoStatus, errorStatus); } /// <summary> /// Sends log records to Azure Monitor using the Logs Ingestion API. /// </summary> private async Task<HttpStatusCode> SendLogAsync( string customerId, LogRecord[] logs, CancellationToken cancellationToken = default) { var client = await GetLogsIngestionClientAsync(customerId).ConfigureAwait(false); try { using var content = RequestContent.Create(logs); _logger.LogInformation("Sending {Count} logs to workspace {WorkspaceId}", logs.Length, customerId); cancellationToken.ThrowIfCancellationRequested(); var response = await client.UploadAsync( customerId, // DCR rule ID _logType, // Stream name (table name) content, // Log data null, // No content type (defaults to application/json) default // No request context ).ConfigureAwait(false); var status = (HttpStatusCode)response.Status; _logger.LogInformation("Log upload completed with status {Status}", status); return status; } catch (Exception ex) when (ex is not OperationCanceledException) { _logger.LogError(ex, "Error sending logs to workspace {WorkspaceId}", customerId); return HttpStatusCode.InternalServerError; } } } public class LogRecord { [JsonPropertyName("TimeGenerated")] public DateTimeOffset TimeGenerated { get; set; } = DateTimeOffset.UtcNow; [JsonPropertyName("Level")] public string Level { get; set; } = ""; [JsonPropertyName("Message")] public string Message { get; set; } = ""; [JsonPropertyName("Application")] public string Application { get; set; } = ""; [JsonExtensionData] public Dictionary<string, JsonElement> AdditionalData { get; set; } = new(); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Azure/azure-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server