private static void DistributeValues(Dictionary <string, double> value, HostMetric host) { foreach (KeyValuePair <string, double> kvp in value) { string[] bits = kvp.Key.Split(':'); if (bits.Length < 4) { continue; } double currentValue = kvp.Value; string key = GetSetName(kvp.Key); if (bits[1].ToLowerInvariant() == "host") { host.Values[key] = currentValue; } else { VmMetric vm = host.GetVmByUuid(bits[2]); if (vm == null) { continue; } vm.Values[key] = currentValue; } } }
public static async Task <HttpResponseMessage> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = "tsdb")] HttpRequestMessage req, [Table("hostmetrics", Connection = "StorageConnectionString")] ICollector <HostMetric> outTable, TraceWriter log) { dynamic data = await req.Content.ReadAsAsync <object>(); var metrics = data as IEnumerable <dynamic>; if (metrics == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a host metric collection in the request body")); } foreach (var metric in metrics) { var hostMetric = new HostMetric() { PartitionKey = metric.hostId, RowKey = metric.time + "+" + metric.name, hostId = metric.hostId, name = metric.name, time = metric.time, value = metric.value, }; log.Verbose(JsonConvert.SerializeObject(metric)); log.Verbose(JsonConvert.SerializeObject(hostMetric)); outTable.Add(hostMetric); } return(req.CreateResponse(HttpStatusCode.OK)); }
private void UpdateMetrics() { while (_run) { // We work on the current list, at the time each update pulse begins. // Sometimes _hosts can be changed by SetXenModelObjects while we're updating, // but that's OK: we've done an unnecessary update of a data structure that's // about to go away, but we'll populate the new structure soon. Dictionary <Host, HostMetric> hosts; lock (_hostsLock) { hosts = _hosts; } List <Thread> updateThreads = new List <Thread>(); foreach (Host host in hosts.Keys) { if (!host.Connection.IsConnected) { continue; } HostMetric hm = hosts[host]; Host h2 = host; Thread t = new Thread(delegate() { // Value for is the function that can take a long time in the error case Dictionary <string, double> value = ValueFor(h2); // Distribute values is fast, but we want to keep it synchronized lock (updateLock) DistributeValues(value, hm); }); t.Name = string.Format("Metric Updater for '{0}'", Helpers.GetName(host)); t.IsBackground = true; updateThreads.Add(t); t.Start(); } foreach (Thread t in updateThreads) { t.Join(); } OnMetricsUpdate(EventArgs.Empty); if (_pause) { lock (_pauseMonitor) Monitor.Wait(_pauseMonitor); } else if (!_skip_sleep) { lock (_sleepMonitor) Monitor.Wait(_sleepMonitor, _sleep); } _skip_sleep = false; } }
public void SetXenObjects(IXenObject[] objects) { InvokeHelper.AssertOnEventThread(); // The QueryPanel can trigger this too often (sometimes more than once when we switch to it). // So we do a preliminary check of whether any changes will be needed to the data structures. // Without this, we wipe out the stats, and can sometimes then display them before they've been // repopulated. This check used to be at the end of this function, just before _hosts = hosts, // but it's cheaper to do it up front, at the expense of some code duplication. if (!AnyNewObjects(objects)) { return; } Dictionary <Host, HostMetric> hosts = new Dictionary <Host, HostMetric>(); // Create HostMetric's for all the hosts foreach (IXenObject obj in objects) { Host host = obj as Host; if (host != null) { hosts[host] = new HostMetric(); } } // Create VmMetric's for all the VMs, and put them under their hosts, indexed by uuid foreach (IXenObject obj in objects) { VM vm = obj as VM; if (vm != null) { Host host = GetHost(vm); if (host != null) { HostMetric hm; if (!hosts.TryGetValue(host, out hm)) { hm = new HostMetric(); hosts[host] = hm; } string uuid = Helpers.GetUuid(vm); hm.VMs[uuid] = new VmMetric(); } } } lock (_hostsLock) { _hosts = hosts; } _skip_sleep = true; lock (_sleepMonitor) Monitor.PulseAll(_sleepMonitor); }
private static void DistributeValues(Dictionary<string, double> value, HostMetric host) { foreach (KeyValuePair<string, double> kvp in value) { string[] bits = kvp.Key.Split(':'); if (bits.Length < 4) continue; double currentValue = kvp.Value; string key = GetSetName(kvp.Key); if (bits[1].ToLowerInvariant() == "host") { host.Values[key] = currentValue; } else { VmMetric vm = host.GetVmByUuid(bits[2]); if (vm == null) continue; vm.Values[key] = currentValue; } } }
public void SetXenObjects(IXenObject[] objects) { InvokeHelper.AssertOnEventThread(); // The QueryPanel can trigger this too often (sometimes more than once when we switch to it). // So we do a preliminary check of whether any changes will be needed to the data structures. // Without this, we wipe out the stats, and can sometimes then display them before they've been // repopulated. This check used to be at the end of this function, just before _hosts = hosts, // but it's cheaper to do it up front, at the expense of some code duplication. if (!AnyNewObjects(objects)) return; var hosts = new ConcurrentDictionary<Host, HostMetric>(); // Create HostMetric's for all the hosts foreach (IXenObject obj in objects) { Host host = obj as Host; if (host != null) hosts[host] = new HostMetric(); } // Create VmMetric's for all the VMs, and put them under their hosts, indexed by uuid foreach (IXenObject obj in objects) { VM vm = obj as VM; if (vm != null) { Host host = GetHost(vm); if (host != null) { var hm = hosts.GetOrAdd(host, new HostMetric()); string uuid = Helpers.GetUuid(vm); hm.VMs[uuid] = new VmMetric(); } } } lock (_hostsLock) { _hosts = hosts; } _skip_sleep = true; lock (_sleepMonitor) Monitor.PulseAll(_sleepMonitor); }