public async Task <PingDataPoint> PingServerAsync(PingSetting setting) { using (var httpClient = _factory.BuildClient()) { TimeSpan responseTime; HttpStatusCode statusCode = HttpStatusCode.ServiceUnavailable; // Generate a request var httpContent = new HttpRequestMessage( setting.GetMethodRequired ? HttpMethod.Get : HttpMethod.Head, setting.ServerUrl ); var timer = new Stopwatch(); timer.Start(); var task = httpClient.SendAsync(httpContent); // Make sure task finishes in TotalMilliseconds milliseconds if ( await Task.WhenAny( task, Task.Delay(Convert.ToInt32(setting.MaxResponseTime.TotalMilliseconds)) ) == task ) { var response = await task; timer.Stop(); // Record time and code responseTime = timer.Elapsed; statusCode = response.StatusCode; } if ( statusCode == HttpStatusCode.ServiceUnavailable || responseTime > setting.MaxResponseTime ) { // Timeout/cancellation logic // If problem occurred then set service unavailable. responseTime = new TimeSpan(0); statusCode = HttpStatusCode.ServiceUnavailable; // _logger.LogWarning(LoggingEvents.Ping.AsInt(), $"Resource {setting.ServerUrl} is unavailable. See stack trace."); } _logger.LogDebug(LoggingEvents.Ping.AsInt(), $"Ping completed for {setting.ServerUrl}"); var metric = await _metrics.GetOrCreateMetricAsync(Metrics.Ping, new Uri(setting.ServerUrl).Host); return(new PingDataPoint { Metric = metric, ResponseTime = responseTime, Success = statusCode.AsInt() / 100 == 2, // 2xx Message = statusCode.AsInt() / 100 == 2 ? "OK" : "Failure" }); } }
public async Task <PingDataPoint> PingServerAsync(PingSetting setting) { using (var client = _factory.BuildClient()) { var parameters = new Dictionary <string, string> { { "url", setting.ServerUrl }, { "method", setting.GetMethodRequired ? "GET" : "HEAD" }, { "timeout", setting.MaxResponseTime.TotalMilliseconds.ToString() } }; var result = await client.GetAsync(QueryHelpers.AddQueryString(_conf["Data:PingServerUrl"], parameters)); var data = JsonConvert.DeserializeObject <RemotePingServerResponse>( await result.Content.ReadAsStringAsync() ); _logger.LogDebug(LoggingEvents.Ping.AsInt(), $"Ping completed for {setting.ServerUrl}"); var metric = await _metrics.GetOrCreateMetricAsync(Metrics.Ping, new Uri(setting.ServerUrl).Host); return (data.IsError ? new PingDataPoint { Metric = metric, ResponseTime = new TimeSpan(0), Success = data.StatusCode / 100 == 2, // 2xx Message = data.Error }: new PingDataPoint { Metric = metric, ResponseTime = new TimeSpan(0, 0, 0, 0, data.Latency), Success = data.StatusCode / 100 == 2, // 2xx Message = "OK" }); } }
/// <summary> /// Populate properties with values read from config /// </summary> private void ReadConfiguration() { _autoLabels = ReadStaticValueFromConfiguration <AutoLabel, AutoLabels>( (label) => new AutoLabel { Id = label.AsInt(), Title = _configuration[$"Data:AutoLabels:{label.ToString()}"] } ); _manualLabels = ReadStaticValueFromConfiguration <ManualLabel, ManualLabels>( (label) => new ManualLabel { Id = label.AsInt(), Title = _configuration[$"Data:ManualLabels:{label.ToString()}"] } ); _compilationStages = ReadStaticValueFromConfiguration <CompilationStage, CompilationStages>( (label) => new CompilationStage { Id = label.AsInt(), Name = _configuration[$"Data:CompilationStages:{label.ToString()}"] } ); _logEntrySeverities = ReadStaticValueFromConfiguration <LogEntrySeverity, LogEntrySeverities>( (label) => new LogEntrySeverity { Id = label.AsInt(), Description = _configuration[$"Data:LogEntrySeverities:{label.ToString()}"] } ); _abstractMetrics = ReadStaticValueFromConfiguration <AbstractMetric, Metrics>( (label) => new AbstractMetric { Type = label.AsInt(), Public = label == Metrics.CpuLoad || label == Metrics.Ping || label == Metrics.Health, Title = _configuration[$"Data:Metrics:{label.ToString()}"] } ); var pingConfig = _configuration.SectionsFromArray("Data:PingSettings"); if (pingConfig.Count() > 0) { _pingSettings = pingConfig .Select(section => { var setting = new PingSetting { ServerUrl = section["ServerUrl"] }; if (section["MaxResponseTime"] != null) { setting.MaxResponseTime = new TimeSpan(0, 0, 0, 0, Convert.ToInt32(section["MaxResponseTime"])); } if (section["MaxFailures"] != null) { setting.MaxFailures = Convert.ToInt32(section["MaxFailures"]); } if (section["GetMethodRequired"] != null) { setting.GetMethodRequired = Convert.ToBoolean(section["GetMethodRequired"]); } return(setting); }) .ToList(); } }
/// <summary> /// Traverses the lists of ping datapoints looking for places where ping failed a number of times defined /// in setting. /// </summary> /// <param name="pings">List of ping datapoints to traverse</param> /// <param name="setting">Ping setting used to determine how many times it is permissible to fail a ping</param> /// <param name="metric">Metric which will appear in a resulting discrepancy object</param> /// <returns>A list of discrepancies of type DiscrepancyType.PingFailedNTimes found</returns> internal List <Discrepancy> FindPingFailuresFromDataPoints(IEnumerable <PingDataPoint> pings, PingSetting setting, Metric metric) { if (pings.Count() == 0) { return(new List <Discrepancy>()); } var failures = pings .Select(p => new { StatusOK = p.Success, Timestamp = p.Timestamp }); if (!failures.Any(l => l.StatusOK)) { // Means that server is dead for the whole timeframe // Discrepancy has been noticed already return(new List <Discrepancy>()); } return(failures .OrderBy(p => p.Timestamp) .SkipWhile(p => !p.StatusOK) .Aggregate( new Stack <BoolIntDateTuple>(), (rest, self) => { if (rest.Count == 0 || rest.Peek().StateGood != self.StatusOK) { rest.Push(new BoolIntDateTuple { StateGood = self.StatusOK, DateFirstOffense = self.Timestamp }); } else { rest.Peek().Count++; } return rest; } ) .Where(t => !t.StateGood && t.Count > setting.MaxFailures) .Select(x => new Discrepancy { DateFirstOffense = x.DateFirstOffense, Type = DiscrepancyType.PingFailedNTimes, MetricType = (Metrics)metric.Type, MetricSource = metric.Source }) .ToList()); }