private async Task TakeMetricsSamplesAsync() { try { // get the monitors // if the host is offline, no monitors will be returned var monitors = _monitorManager.GetMonitors(); if (monitors.Any()) { _logger.LogDebug($"Taking metrics samples for {monitors.Count()} monitor(s)."); var metricsMap = new Dictionary <IScaleMonitor, ScaleMetrics>(); foreach (var monitor in monitors) { ScaleMetrics metrics = null; try { // take a metrics sample for each monitor metrics = await monitor.GetMetricsAsync(); metricsMap[monitor] = metrics; // log the metrics json to provide visibility into monitor activity var json = JsonConvert.SerializeObject(metrics); _logger.LogDebug($"Scale metrics sample for monitor '{monitor.Descriptor.Id}': {json}"); } catch (Exception exc) when(!exc.IsFatal()) { // if a particular monitor fails, log and continue _logger.LogError(exc, $"Failed to collect scale metrics sample for monitor '{monitor.Descriptor.Id}'."); } } if (metricsMap.Count > 0) { // persist the metrics samples await _metricsRepository.WriteMetricsAsync(metricsMap); } } } catch (Exception exc) when(!exc.IsFatal()) { _logger.LogError(exc, "Failed to collect/persist scale metrics."); } }
internal static TableOperation CreateMetricsInsertOperation(ScaleMetrics metrics, string hostId, ScaleMonitorDescriptor descriptor, DateTime?now = null) { now = now ?? DateTime.UtcNow; // Use an inverted ticks rowkey to order the table in descending order, allowing us to easily // query for latest logs. Adding a guid as part of the key to ensure uniqueness. string rowKey = TableStorageHelpers.GetRowKey(now.Value); var entity = TableEntityConverter.ToEntity(metrics, hostId, rowKey, metrics.Timestamp); entity.Properties.Add(MonitorIdPropertyName, EntityProperty.GeneratePropertyForString(descriptor.Id)); // We map the sample timestamp to its own column so it doesn't conflict with the built in column. // We want to ensure that timestamp values for returned metrics are precise and monotonically // increasing when ordered results are returned. The built in timestamp doesn't guarantee this. entity.Properties.Add(SampleTimestampPropertyName, EntityProperty.GeneratePropertyForDateTimeOffset(metrics.Timestamp)); return(TableOperation.Insert(entity)); }