/// <summary>
        /// Tests if the contents of the given url can be accessed from the current environment.
        /// Reports results to given data service.
        /// </summary>
        /// <param name="log"><see cref="ILogger"/> that is used to report log information.</param>
        /// <param name="monitorName">Name of this monitor to be included in the logs and in the data sent to Kusto.</param>
        /// <param name="url">Url that this method will attempt to access.</param>
        /// <param name="dataService">Data service to be used when reporting the results.</param>
        /// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
        /// <returns>A task, tracking the initiated async operation. Errors should be reported through exceptions.</returns>
        internal static async Task CheckAndReportUrlAccessAsync(ILogger log,
                                                                string monitorName,
                                                                string url,
                                                                IDataService dataService,
                                                                CancellationToken cancellationToken = default)
        {
            _ = log ?? throw new ArgumentNullException(paramName: nameof(log));
            _ = string.IsNullOrWhiteSpace(monitorName) ? throw new ArgumentNullException(paramName: nameof(monitorName)) : monitorName;
            _ = string.IsNullOrWhiteSpace(url) ? throw new ArgumentNullException(paramName: nameof(url)) : url;
            _ = dataService ?? throw new ArgumentNullException(paramName: nameof(dataService));

            HttpRequestLogEntry logEntry = new HttpRequestLogEntry()
            {
                MonitorName  = monitorName,
                EventTime    = DateTime.UtcNow,
                RequestedUrl = url
            };
            HttpResponseMessage?response = null;

            try
            {
                response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);

                logEntry.HttpResponseCode = (int)response.StatusCode;
                await dataService.ReportUrlAccessAsync(logEntry, cancellationToken).ConfigureAwait(false);
            }
            catch (Exception httpException)
            {
                if (response == null)
                {
                    // HttpClient failed to return a response, instead threw. The error should be in the exception.
                    logEntry.Error = httpException.Message;

                    try
                    {
                        await dataService.ReportUrlAccessAsync(logEntry, cancellationToken);
                    }
                    catch (Exception dataServiceException)
                    {
                        // Reporting to database has failed. Let's report into Azure Functions so that we can somehow track this.
                        log.LogError(httpException, $"Failed to access url {url} from monitor {monitorName}");
                        // There was an error with the data store and this should also be logged.
                        log.LogError(dataServiceException, "Failed to report an unsuccessful http request.");
                    }
                }
                else
                {
                    // Http request completed, but reporting to data service has failed.
                    log.LogError($"Failed to report an http response code {response.StatusCode} for url {url}.");
                }
            }
            finally
            {
                response?.Dispose();
            }
        }
        /// <summary>
        /// Reports the details of the <see cref="HttpResponseMessage"/> to kusto.
        /// </summary>
        /// <param name="monitorName">Name of the monitor generating this data entry.</param>
        /// <param name="httpResponse">Response to be reported.</param>
        /// <returns>A task, tracking this async operation.</returns>
        public async Task ReportUrlAccessAsync(string monitorName, HttpResponseMessage httpResponse, CancellationToken cancellationToken = default)
        {
            HttpRequestLogEntry logEntry = new HttpRequestLogEntry()
            {
                MonitorName      = monitorName,
                EventTime        = DateTime.UtcNow,
                RequestedUrl     = httpResponse.RequestMessage.RequestUri.AbsoluteUri,
                HttpResponseCode = (int)httpResponse.StatusCode
            };

            await _httpRequestLogsTable.InsertRowAsync(logEntry, cancellationToken).ConfigureAwait(false);
        }
Esempio n. 3
0
        /// <summary>
        /// Saves the details of the <see cref="HttpResponseMessage"/> to
        /// </summary>
        /// <param name="monitorName"></param>
        /// <param name="httpResponse"></param>
        /// <returns></returns>
        public async Task ReportUrlAccessAsync(string monitorName, HttpResponseMessage httpResponse, CancellationToken cancellationToken = default)
        {
            HttpRequestLogEntry logEntry = new HttpRequestLogEntry()
            {
                MonitorName    = monitorName,
                EventTime      = DateTime.UtcNow,
                RequestedUrl   = httpResponse.RequestMessage.RequestUri.AbsoluteUri,
                HttpStatusCode = (int)httpResponse.StatusCode
            };

            KustoConnectionStringBuilder kcsb = new KustoConnectionStringBuilder($"https://ingest-{ServiceNameAndRegion}.kusto.windows.net")
                                                .WithAadManagedIdentity("system");

            using IKustoQueuedIngestClient ingestClient = KustoIngestFactory.CreateQueuedIngestClient(kcsb);
            KustoQueuedIngestionProperties ingestProps = new KustoQueuedIngestionProperties(DatabaseName, TableName)
            {
                ReportLevel      = IngestionReportLevel.FailuresOnly,
                ReportMethod     = IngestionReportMethod.Queue,
                IngestionMapping = new IngestionMapping()
                {
                    IngestionMappingKind = Kusto.Data.Ingestion.IngestionMappingKind.Json,
                    IngestionMappings    = HttpRequestLogColumnMapping
                },
                Format = DataSourceFormat.json
            };

            using MemoryStream memStream = new MemoryStream();
            using StreamWriter writer    = new StreamWriter(memStream);

            writer.WriteLine(JsonConvert.SerializeObject(logEntry));

            writer.Flush();
            memStream.Seek(0, SeekOrigin.Begin);

            // IKustoQueuedIngestClient doesn't support cancellation at the moment. Update the line below if it does in the future.
            await ingestClient.IngestFromStreamAsync(memStream, ingestProps, leaveOpen : true);
        }
Esempio n. 4
0
 /// <summary>
 /// Stores the details of the <see cref="HttpRequestLogEntry"/> in the underlying kusto database.
 /// </summary>
 /// <inheritdoc/>
 public async Task ReportUrlAccessAsync(HttpRequestLogEntry httpRequestLogEntry, CancellationToken cancellationToken = default)
 {
     await _httpRequestLogsTable.InsertRowAsync(httpRequestLogEntry, cancellationToken).ConfigureAwait(false);
 }
 /// <inheritdoc/>
 public async Task ReportUrlAccessAsync(HttpRequestLogEntry httpRequestLogEntry, CancellationToken cancellationToken = default)
 {
     await Task.Delay(new Random().Next(200, 4000), cancellationToken).ConfigureAwait(false);
 }