1 // 2 // Copyright (c) ZeroC, Inc. All rights reserved. 3 // 4 5 namespace IceInternal 6 { 7 using System; 8 using System.Text; 9 using System.Diagnostics; 10 using System.Collections.Generic; 11 using System.Text.RegularExpressions; 12 13 internal interface IMetricsMap 14 { getMetrics()15 IceMX.Metrics[] getMetrics(); getFailures()16 IceMX.MetricsFailures[] getFailures(); getFailures(string id)17 IceMX.MetricsFailures getFailures(string id); getProperties()18 Dictionary<string, string> getProperties(); 19 } 20 21 interface ISubMap 22 { addSubMapToMetrics(IceMX.Metrics metrics)23 void addSubMapToMetrics(IceMX.Metrics metrics); 24 } 25 26 interface ISubMapCloneFactory 27 { create()28 ISubMap create(); 29 } 30 31 interface ISubMapFactory 32 { createCloneFactory(string subMapPrefix, Ice.Properties properties)33 ISubMapCloneFactory createCloneFactory(string subMapPrefix, Ice.Properties properties); 34 } 35 36 internal interface IMetricsMapFactory 37 { 38 void registerSubMap<S>(string subMap, System.Reflection.FieldInfo field) where S : IceMX.Metrics, new(); update()39 void update(); create(string mapPrefix, Ice.Properties properties)40 IMetricsMap create(string mapPrefix, Ice.Properties properties); 41 } 42 43 internal class SubMap<S> : ISubMap where S : IceMX.Metrics, new() 44 { SubMap(MetricsMap<S> map, System.Reflection.FieldInfo field)45 internal SubMap(MetricsMap<S> map, System.Reflection.FieldInfo field) 46 { 47 _map = map; 48 _field = field; 49 } 50 getMatching(IceMX.MetricsHelper<S> helper)51 internal MetricsMap<S>.Entry getMatching(IceMX.MetricsHelper<S> helper) 52 { 53 return _map.getMatching(helper, null); 54 } 55 addSubMapToMetrics(IceMX.Metrics metrics)56 public void addSubMapToMetrics(IceMX.Metrics metrics) 57 { 58 try 59 { 60 _field.SetValue(metrics, _map.getMetrics()); 61 } 62 catch(Exception) 63 { 64 Debug.Assert(false); 65 } 66 } 67 68 readonly private MetricsMap<S> _map; 69 readonly private System.Reflection.FieldInfo _field; 70 } 71 72 internal class SubMapCloneFactory<S> : ISubMapCloneFactory where S : IceMX.Metrics, new() 73 { SubMapCloneFactory(MetricsMap<S> map, System.Reflection.FieldInfo field)74 internal SubMapCloneFactory(MetricsMap<S> map, System.Reflection.FieldInfo field) 75 { 76 _map = map; 77 _field = field; 78 } 79 create()80 public ISubMap create() 81 { 82 return new SubMap<S>(new MetricsMap<S>(_map), _field); 83 } 84 85 readonly private MetricsMap<S> _map; 86 readonly private System.Reflection.FieldInfo _field; 87 } 88 89 class SubMapFactory<S> : ISubMapFactory where S : IceMX.Metrics, new() 90 { SubMapFactory(System.Reflection.FieldInfo field)91 internal SubMapFactory(System.Reflection.FieldInfo field) 92 { 93 _field = field; 94 } 95 createCloneFactory(string subMapPrefix, Ice.Properties properties)96 public ISubMapCloneFactory createCloneFactory(string subMapPrefix, Ice.Properties properties) 97 { 98 return new SubMapCloneFactory<S>(new MetricsMap<S>(subMapPrefix, properties, null), _field); 99 } 100 101 readonly private System.Reflection.FieldInfo _field; 102 } 103 104 public class MetricsMap<T> : IMetricsMap where T : IceMX.Metrics, new() 105 { 106 public class Entry 107 { Entry(MetricsMap<T> map, T obj)108 internal Entry(MetricsMap<T> map, T obj) 109 { 110 _map = map; 111 _object = obj; 112 } 113 failed(string exceptionName)114 public void failed(string exceptionName) 115 { 116 lock(_map) 117 { 118 ++_object.failures; 119 int count; 120 if(_failures == null) 121 { 122 _failures = new Dictionary<string, int>(); 123 } 124 if(_failures.TryGetValue(exceptionName, out count)) 125 { 126 _failures[exceptionName] = count + 1; 127 } 128 else 129 { 130 _failures[exceptionName] = 1; 131 } 132 } 133 } 134 135 internal MetricsMap<S>.Entry getMatching<S>(string mapName, IceMX.MetricsHelper<S> helper) 136 where S : IceMX.Metrics, new() 137 { 138 ISubMap m; 139 lock(_map) 140 { 141 if(_subMaps == null || !_subMaps.TryGetValue(mapName, out m)) 142 { 143 m = _map.createSubMap(mapName); 144 if(m == null) 145 { 146 return null; 147 } 148 if(_subMaps == null) 149 { 150 _subMaps = new Dictionary<string, ISubMap>(); 151 } 152 _subMaps.Add(mapName, m); 153 } 154 } 155 return ((SubMap<S>)m).getMatching(helper); 156 } 157 detach(long lifetime)158 public void detach(long lifetime) 159 { 160 lock(_map) 161 { 162 _object.totalLifetime += lifetime; 163 if(--_object.current == 0) 164 { 165 _map.detached(this); 166 } 167 } 168 } 169 execute(IceMX.Observer<T>.MetricsUpdate func)170 public void execute(IceMX.Observer<T>.MetricsUpdate func) 171 { 172 lock(_map) 173 { 174 func(_object); 175 } 176 } 177 getMap()178 public MetricsMap<T> getMap() 179 { 180 return _map; 181 } 182 getFailures()183 internal IceMX.MetricsFailures getFailures() 184 { 185 if(_failures == null) 186 { 187 return null; 188 } 189 IceMX.MetricsFailures f = new IceMX.MetricsFailures(); 190 f.id = _object.id; 191 f.failures = new Dictionary<string, int>(_failures); 192 return f; 193 } 194 attach(IceMX.MetricsHelper<T> helper)195 internal void attach(IceMX.MetricsHelper<T> helper) 196 { 197 ++_object.total; 198 ++_object.current; 199 helper.initMetrics(_object); 200 } 201 isDetached()202 internal bool isDetached() 203 { 204 return _object.current == 0; 205 } 206 clone()207 internal IceMX.Metrics clone() 208 { 209 T metrics = (T)_object.Clone(); 210 if(_subMaps != null) 211 { 212 foreach(ISubMap s in _subMaps.Values) 213 { 214 s.addSubMapToMetrics(metrics); 215 } 216 } 217 return metrics; 218 } 219 getId()220 internal string getId() 221 { 222 return _object.id; 223 } 224 225 private MetricsMap<T> _map; 226 private T _object; 227 private Dictionary<string, int> _failures; 228 private Dictionary<string, ISubMap> _subMaps; 229 } 230 MetricsMap(string mapPrefix, Ice.Properties props, Dictionary<string, ISubMapFactory> subMaps)231 internal MetricsMap(string mapPrefix, Ice.Properties props, Dictionary<string, ISubMapFactory> subMaps) 232 { 233 MetricsAdminI.validateProperties(mapPrefix, props); 234 _properties = props.getPropertiesForPrefix(mapPrefix); 235 236 _retain = props.getPropertyAsIntWithDefault(mapPrefix + "RetainDetached", 10); 237 _accept = parseRule(props, mapPrefix + "Accept"); 238 _reject = parseRule(props, mapPrefix + "Reject"); 239 _groupByAttributes = new List<string>(); 240 _groupBySeparators = new List<string>(); 241 242 string groupBy = props.getPropertyWithDefault(mapPrefix + "GroupBy", "id"); 243 if(groupBy.Length > 0) 244 { 245 string v = ""; 246 bool attribute = char.IsLetter(groupBy[0]) || char.IsDigit(groupBy[0]); 247 if(!attribute) 248 { 249 _groupByAttributes.Add(""); 250 } 251 252 foreach(char p in groupBy) 253 { 254 bool isAlphaNum = char.IsLetter(p) || char.IsDigit(p) || p == '.'; 255 if(attribute && !isAlphaNum) 256 { 257 _groupByAttributes.Add(v); 258 v = "" + p; 259 attribute = false; 260 } 261 else if(!attribute && isAlphaNum) 262 { 263 _groupBySeparators.Add(v); 264 v = "" + p; 265 attribute = true; 266 } 267 else 268 { 269 v += p; 270 } 271 } 272 273 if(attribute) 274 { 275 _groupByAttributes.Add(v); 276 } 277 else 278 { 279 _groupBySeparators.Add(v); 280 } 281 } 282 283 if(subMaps != null && subMaps.Count > 0) 284 { 285 _subMaps = new Dictionary<string, ISubMapCloneFactory>(); 286 287 List<string> subMapNames = new List<string>(); 288 foreach(KeyValuePair<string, ISubMapFactory> e in subMaps) 289 { 290 subMapNames.Add(e.Key); 291 string subMapsPrefix = mapPrefix + "Map."; 292 string subMapPrefix = subMapsPrefix + e.Key + '.'; 293 if(props.getPropertiesForPrefix(subMapPrefix).Count == 0) 294 { 295 if(props.getPropertiesForPrefix(subMapsPrefix).Count == 0) 296 { 297 subMapPrefix = mapPrefix; 298 } 299 else 300 { 301 continue; // This sub-map isn't configured. 302 } 303 } 304 305 _subMaps.Add(e.Key, e.Value.createCloneFactory(subMapPrefix, props)); 306 } 307 } 308 else 309 { 310 _subMaps = null; 311 } 312 } 313 MetricsMap(MetricsMap<T> map)314 internal MetricsMap(MetricsMap<T> map) 315 { 316 _properties = map._properties; 317 _groupByAttributes = map._groupByAttributes; 318 _groupBySeparators = map._groupBySeparators; 319 _retain = map._retain; 320 _accept = map._accept; 321 _reject = map._reject; 322 _subMaps = map._subMaps; 323 } 324 getProperties()325 public Dictionary<string, string> getProperties() 326 { 327 return _properties; 328 } 329 getMetrics()330 public IceMX.Metrics[] getMetrics() 331 { 332 lock(this) 333 { 334 IceMX.Metrics[] metrics = new IceMX.Metrics[_objects.Count]; 335 int i = 0; 336 foreach(Entry e in _objects.Values) 337 { 338 metrics[i++] = e.clone(); 339 } 340 return metrics; 341 } 342 } 343 getFailures()344 public IceMX.MetricsFailures[] getFailures() 345 { 346 lock(this) 347 { 348 List<IceMX.MetricsFailures> failures = new List<IceMX.MetricsFailures>(); 349 foreach(Entry e in _objects.Values) 350 { 351 IceMX.MetricsFailures f = e.getFailures(); 352 if(f != null) 353 { 354 failures.Add(f); 355 } 356 } 357 return failures.ToArray(); 358 } 359 } 360 getFailures(string id)361 public IceMX.MetricsFailures getFailures(string id) 362 { 363 lock(this) 364 { 365 Entry e; 366 if(_objects.TryGetValue(id, out e)) 367 { 368 return e.getFailures(); 369 } 370 return null; 371 } 372 } 373 createSubMap(string subMapName)374 ISubMap createSubMap(string subMapName) 375 { 376 if(_subMaps == null) 377 { 378 return null; 379 } 380 ISubMapCloneFactory factory; 381 if(_subMaps.TryGetValue(subMapName, out factory)) 382 { 383 return factory.create(); 384 } 385 return null; 386 } 387 getMatching(IceMX.MetricsHelper<T> helper, Entry previous)388 public Entry getMatching(IceMX.MetricsHelper<T> helper, Entry previous) 389 { 390 // 391 // Check the accept and reject filters. 392 // 393 foreach(KeyValuePair<string, Regex> e in _accept) 394 { 395 if(!match(e.Key, e.Value, helper, false)) 396 { 397 return null; 398 } 399 } 400 401 foreach(KeyValuePair<string, Regex> e in _reject) 402 { 403 if(match(e.Key, e.Value, helper, true)) 404 { 405 return null; 406 } 407 } 408 409 // 410 // Compute the key from the GroupBy property. 411 // 412 string key; 413 try 414 { 415 if(_groupByAttributes.Count == 1) 416 { 417 key = helper.resolve(_groupByAttributes[0]); 418 } 419 else 420 { 421 StringBuilder os = new StringBuilder(); 422 IEnumerator<string> q = _groupBySeparators.GetEnumerator(); 423 foreach(string p in _groupByAttributes) 424 { 425 os.Append(helper.resolve(p)); 426 if(q.MoveNext()) 427 { 428 os.Append(q.Current); 429 } 430 } 431 key = os.ToString(); 432 } 433 } 434 catch(Exception) 435 { 436 return null; 437 } 438 439 // 440 // Lookup the metrics object. 441 // 442 lock(this) 443 { 444 if(previous != null && previous.getId().Equals(key)) 445 { 446 Debug.Assert(_objects[key] == previous); 447 return previous; 448 } 449 450 Entry e; 451 if(!_objects.TryGetValue(key, out e)) 452 { 453 try 454 { 455 T t = new T(); 456 t.id = key; 457 e = new Entry(this, t); 458 _objects.Add(key, e); 459 } 460 catch(Exception) 461 { 462 Debug.Assert(false); 463 } 464 } 465 e.attach(helper); 466 return e; 467 } 468 } 469 detached(Entry entry)470 private void detached(Entry entry) 471 { 472 if(_retain == 0) 473 { 474 return; 475 } 476 477 if(_detachedQueue == null) 478 { 479 _detachedQueue = new LinkedList<Entry>(); 480 } 481 Debug.Assert(_detachedQueue.Count <= _retain); 482 483 // Compress the queue by removing entries which are no longer detached. 484 LinkedListNode<Entry> p = _detachedQueue.First; 485 while(p != null) 486 { 487 LinkedListNode<Entry> next = p.Next; 488 if(p.Value == entry || !p.Value.isDetached()) 489 { 490 _detachedQueue.Remove(p); 491 } 492 p = next; 493 } 494 495 // If there's still no room, remove the oldest entry (at the front). 496 if(_detachedQueue.Count == _retain) 497 { 498 _objects.Remove(_detachedQueue.First.Value.getId()); 499 _detachedQueue.RemoveFirst(); 500 } 501 502 // Add the entry at the back of the queue. 503 _detachedQueue.AddLast(entry); 504 } 505 parseRule(Ice.Properties properties, string name)506 private Dictionary<string, Regex> parseRule(Ice.Properties properties, string name) 507 { 508 Dictionary<string, Regex> pats = new Dictionary<string, Regex>(); 509 Dictionary<string, string> rules = properties.getPropertiesForPrefix(name + '.'); 510 foreach(KeyValuePair<string, string> e in rules) 511 { 512 pats.Add(e.Key.Substring(name.Length + 1), new Regex(e.Value)); 513 } 514 return pats; 515 } 516 match(string attribute, Regex regex, IceMX.MetricsHelper<T> helper, bool reject)517 private bool match(string attribute, Regex regex, IceMX.MetricsHelper<T> helper, bool reject) 518 { 519 string value; 520 try 521 { 522 value = helper.resolve(attribute); 523 } 524 catch(Exception) 525 { 526 return !reject; 527 } 528 return regex.IsMatch(value); 529 } 530 531 readonly private Dictionary<string, string> _properties; 532 readonly private List<string> _groupByAttributes; 533 readonly private List<string> _groupBySeparators; 534 readonly private int _retain; 535 readonly private Dictionary<string, Regex> _accept; 536 readonly private Dictionary<string, Regex> _reject; 537 538 readonly private Dictionary<string, Entry> _objects = new Dictionary<string, Entry>(); 539 readonly private Dictionary<string, ISubMapCloneFactory> _subMaps; 540 private LinkedList<Entry> _detachedQueue; 541 } 542 543 internal class MetricsViewI 544 { MetricsViewI(string name)545 internal MetricsViewI(string name) 546 { 547 _name = name; 548 } 549 addOrUpdateMap(Ice.Properties properties, string mapName, IMetricsMapFactory factory, Ice.Logger logger)550 internal bool addOrUpdateMap(Ice.Properties properties, string mapName, IMetricsMapFactory factory, 551 Ice.Logger logger) 552 { 553 // 554 // Add maps to views configured with the given map. 555 // 556 string viewPrefix = "IceMX.Metrics." + _name + "."; 557 string mapsPrefix = viewPrefix + "Map."; 558 Dictionary<string, string> mapsProps = properties.getPropertiesForPrefix(mapsPrefix); 559 560 string mapPrefix; 561 Dictionary<string, string> mapProps = new Dictionary<string, string>(); 562 if(mapsProps.Count > 0) 563 { 564 mapPrefix = mapsPrefix + mapName + "."; 565 mapProps = properties.getPropertiesForPrefix(mapPrefix); 566 if(mapProps.Count == 0) 567 { 568 // This map isn't configured for this view. 569 return _maps.Remove(mapName); 570 } 571 } 572 else 573 { 574 mapPrefix = viewPrefix; 575 mapProps = properties.getPropertiesForPrefix(mapPrefix); 576 } 577 578 if(properties.getPropertyAsInt(mapPrefix + "Disabled") > 0) 579 { 580 // This map is disabled for this view. 581 return _maps.Remove(mapName); 582 } 583 584 IMetricsMap m; 585 if(_maps.TryGetValue(mapName, out m) && 586 IceUtilInternal.Collections.DictionaryEquals(m.getProperties(), mapProps)) 587 { 588 return false; // The map configuration didn't change, no need to re-create. 589 } 590 591 try 592 { 593 _maps[mapName] = factory.create(mapPrefix, properties); 594 } 595 catch(Exception ex) 596 { 597 logger.warning("unexpected exception while creating metrics map:\n" + ex); 598 _maps.Remove(mapName); 599 } 600 return true; 601 } 602 removeMap(string mapName)603 internal bool removeMap(string mapName) 604 { 605 return _maps.Remove(mapName); 606 } 607 getMetrics()608 internal Dictionary<string, IceMX.Metrics[]> getMetrics() 609 { 610 Dictionary<string, IceMX.Metrics[]> metrics = new Dictionary<string, IceMX.Metrics[]>(); 611 foreach(KeyValuePair<string, IMetricsMap> e in _maps) 612 { 613 IceMX.Metrics[] m = e.Value.getMetrics(); 614 if(m != null) 615 { 616 metrics.Add(e.Key, m); 617 } 618 } 619 return metrics; 620 } 621 getFailures(string mapName)622 internal IceMX.MetricsFailures[] getFailures(string mapName) 623 { 624 IMetricsMap m; 625 if(_maps.TryGetValue(mapName, out m)) 626 { 627 return m.getFailures(); 628 } 629 return null; 630 } 631 getFailures(string mapName, string id)632 internal IceMX.MetricsFailures getFailures(string mapName, string id) 633 { 634 IMetricsMap m; 635 if(_maps.TryGetValue(mapName, out m)) 636 { 637 return m.getFailures(id); 638 } 639 return null; 640 } 641 getMaps()642 internal ICollection<string> getMaps() 643 { 644 return _maps.Keys; 645 } 646 647 internal MetricsMap<T> getMap<T>(string mapName) where T : IceMX.Metrics, new() 648 { 649 IMetricsMap m; 650 if(_maps.TryGetValue(mapName, out m)) 651 { 652 return (MetricsMap<T>)m; 653 } 654 return null; 655 } 656 657 readonly private string _name; 658 readonly private Dictionary<string, IMetricsMap> _maps = new Dictionary<string, IMetricsMap>(); 659 } 660 661 public class MetricsAdminI : IceMX.MetricsAdminDisp_, Ice.PropertiesAdminUpdateCallback 662 { 663 readonly static private string[] suffixes = 664 { 665 "Disabled", 666 "GroupBy", 667 "Accept.*", 668 "Reject.*", 669 "RetainDetached", 670 "Map.*", 671 }; 672 validateProperties(string prefix, Ice.Properties properties)673 public static void validateProperties(string prefix, Ice.Properties properties) 674 { 675 Dictionary<string, string> props = properties.getPropertiesForPrefix(prefix); 676 List<string> unknownProps = new List<string>(); 677 foreach(string prop in props.Keys) 678 { 679 bool valid = false; 680 foreach(string suffix in suffixes) 681 { 682 if(IceUtilInternal.StringUtil.match(prop, prefix + suffix, false)) 683 { 684 valid = true; 685 break; 686 } 687 } 688 689 if(!valid) 690 { 691 unknownProps.Add(prop); 692 } 693 } 694 695 if(unknownProps.Count != 0 && properties.getPropertyAsIntWithDefault("Ice.Warn.UnknownProperties", 1) > 0) 696 { 697 StringBuilder message = new StringBuilder("found unknown IceMX properties for `"); 698 message.Append(prefix.Substring(0, prefix.Length - 1)); 699 message.Append("':"); 700 foreach(string p in unknownProps) 701 { 702 message.Append("\n "); 703 message.Append(p); 704 } 705 Ice.Util.getProcessLogger().warning(message.ToString()); 706 } 707 } 708 709 class MetricsMapFactory<T> : IMetricsMapFactory where T : IceMX.Metrics, new() 710 { MetricsMapFactory(Action updater)711 public MetricsMapFactory(Action updater) 712 { 713 _updater = updater; 714 } 715 update()716 public void update() 717 { 718 Debug.Assert(_updater != null); 719 _updater(); 720 } 721 create(string mapPrefix, Ice.Properties properties)722 public IMetricsMap create(string mapPrefix, Ice.Properties properties) 723 { 724 return new MetricsMap<T>(mapPrefix, properties, _subMaps); 725 } 726 727 public void registerSubMap<S>(string subMap, System.Reflection.FieldInfo field) 728 where S : IceMX.Metrics, new() 729 { 730 _subMaps.Add(subMap, new SubMapFactory<S>(field)); 731 } 732 733 readonly private Action _updater; 734 readonly private Dictionary<string, ISubMapFactory> _subMaps = new Dictionary<string, ISubMapFactory>(); 735 } 736 MetricsAdminI(Ice.Properties properties, Ice.Logger logger)737 public MetricsAdminI(Ice.Properties properties, Ice.Logger logger) 738 { 739 _logger = logger; 740 _properties = properties; 741 updateViews(); 742 } 743 updateViews()744 public void updateViews() 745 { 746 HashSet<IMetricsMapFactory> updatedMaps = new HashSet<IMetricsMapFactory>(); 747 lock(this) 748 { 749 string viewsPrefix = "IceMX.Metrics."; 750 Dictionary<string, string> viewsProps = _properties.getPropertiesForPrefix(viewsPrefix); 751 Dictionary<string, MetricsViewI> views = new Dictionary<string, MetricsViewI>(); 752 _disabledViews.Clear(); 753 foreach(KeyValuePair<string, string> e in viewsProps) 754 { 755 string viewName = e.Key.Substring(viewsPrefix.Length); 756 int dotPos = viewName.IndexOf('.'); 757 if(dotPos > 0) 758 { 759 viewName = viewName.Substring(0, dotPos); 760 } 761 762 if(views.ContainsKey(viewName) || _disabledViews.Contains(viewName)) 763 { 764 continue; // View already configured. 765 } 766 767 validateProperties(viewsPrefix + viewName + ".", _properties); 768 769 if(_properties.getPropertyAsIntWithDefault(viewsPrefix + viewName + ".Disabled", 0) > 0) 770 { 771 _disabledViews.Add(viewName); 772 continue; // The view is disabled 773 } 774 775 // 776 // Create the view or update it. 777 // 778 MetricsViewI v; 779 if(!_views.TryGetValue(viewName, out v)) 780 { 781 v = new MetricsViewI(viewName); 782 } 783 views[viewName] = v; 784 785 foreach(KeyValuePair<string, IMetricsMapFactory> f in _factories) 786 { 787 if(v.addOrUpdateMap(_properties, f.Key, f.Value, _logger)) 788 { 789 updatedMaps.Add(f.Value); 790 } 791 } 792 } 793 794 Dictionary<string, MetricsViewI> tmp = _views; 795 _views = views; 796 views = tmp; 797 798 // 799 // Go through removed views to collect maps to update. 800 // 801 foreach(KeyValuePair<string, MetricsViewI> v in views) 802 { 803 if(!_views.ContainsKey(v.Key)) 804 { 805 foreach(string n in v.Value.getMaps()) 806 { 807 updatedMaps.Add(_factories[n]); 808 } 809 } 810 } 811 } 812 813 // 814 // Call the updaters to update the maps. 815 // 816 foreach(IMetricsMapFactory f in updatedMaps) 817 { 818 f.update(); 819 } 820 } 821 getMetricsViewNames(out string[] disabledViews, Ice.Current current)822 override public string[] getMetricsViewNames(out string[] disabledViews, Ice.Current current) 823 { 824 lock(this) 825 { 826 disabledViews = _disabledViews.ToArray(); 827 return new List<String>(_views.Keys).ToArray(); 828 } 829 } 830 enableMetricsView(string name, Ice.Current current)831 override public void enableMetricsView(string name, Ice.Current current) 832 { 833 lock(this) 834 { 835 getMetricsView(name); // Throws if unknown view. 836 _properties.setProperty("IceMX.Metrics." + name + ".Disabled", "0"); 837 } 838 updateViews(); 839 } 840 disableMetricsView(string name, Ice.Current current)841 override public void disableMetricsView(string name, Ice.Current current) 842 { 843 lock(this) 844 { 845 getMetricsView(name); // Throws if unknown view. 846 _properties.setProperty("IceMX.Metrics." + name + ".Disabled", "1"); 847 } 848 updateViews(); 849 } 850 getMetricsView(string viewName, out long timestamp, Ice.Current current)851 override public Dictionary<string, IceMX.Metrics[]> getMetricsView(string viewName, out long timestamp, 852 Ice.Current current) 853 { 854 lock(this) 855 { 856 MetricsViewI view = getMetricsView(viewName); 857 timestamp = Time.currentMonotonicTimeMillis(); 858 if(view != null) 859 { 860 return view.getMetrics(); 861 } 862 return new Dictionary<string, IceMX.Metrics[]>(); 863 } 864 } 865 getMapMetricsFailures(string viewName, string mapName, Ice.Current c)866 override public IceMX.MetricsFailures[] getMapMetricsFailures(string viewName, string mapName, Ice.Current c) 867 { 868 lock(this) 869 { 870 MetricsViewI view = getMetricsView(viewName); 871 if(view != null) 872 { 873 return view.getFailures(mapName); 874 } 875 return new IceMX.MetricsFailures[0]; 876 } 877 } 878 getMetricsFailures(string viewName, string mapName, string id, Ice.Current c)879 override public IceMX.MetricsFailures getMetricsFailures(string viewName, string mapName, string id, 880 Ice.Current c) 881 { 882 lock(this) 883 { 884 MetricsViewI view = getMetricsView(viewName); 885 if(view != null) 886 { 887 return view.getFailures(mapName, id); 888 } 889 return new IceMX.MetricsFailures(); 890 } 891 } 892 893 public void registerMap<T>(string map, Action updater) 894 where T : IceMX.Metrics, new() 895 { 896 bool updated; 897 MetricsMapFactory<T> factory; 898 lock(this) 899 { 900 factory = new MetricsMapFactory<T>(updater); 901 _factories.Add(map, factory); 902 updated = addOrUpdateMap(map, factory); 903 } 904 if(updated) 905 { 906 factory.update(); 907 } 908 } 909 910 public void registerSubMap<S>(string map, string subMap, System.Reflection.FieldInfo field) 911 where S : IceMX.Metrics, new() 912 { 913 bool updated; 914 IMetricsMapFactory factory; 915 lock(this) 916 { 917 if(!_factories.TryGetValue(map, out factory)) 918 { 919 return; 920 } 921 factory.registerSubMap<S>(subMap, field); 922 removeMap(map); 923 updated = addOrUpdateMap(map, factory); 924 } 925 if(updated) 926 { 927 factory.update(); 928 } 929 } 930 unregisterMap(string mapName)931 public void unregisterMap(string mapName) 932 { 933 bool updated; 934 IMetricsMapFactory factory; 935 lock(this) 936 { 937 if(!_factories.TryGetValue(mapName, out factory)) 938 { 939 return; 940 } 941 _factories.Remove(mapName); 942 updated = removeMap(mapName); 943 } 944 if(updated) 945 { 946 factory.update(); 947 } 948 } 949 950 public List<MetricsMap<T>> getMaps<T>(string mapName) where T : IceMX.Metrics, new() 951 { 952 List<MetricsMap<T>> maps = new List<MetricsMap<T>>(); 953 foreach(MetricsViewI v in _views.Values) 954 { 955 MetricsMap<T> map = v.getMap<T>(mapName); 956 if(map != null) 957 { 958 maps.Add(map); 959 } 960 } 961 return maps; 962 } 963 getLogger()964 public Ice.Logger getLogger() 965 { 966 return _logger; 967 } 968 updated(Dictionary<string, string> props)969 public void updated(Dictionary<string, string> props) 970 { 971 foreach(KeyValuePair<string, string> e in props) 972 { 973 if(e.Key.IndexOf("IceMX.") == 0) 974 { 975 // Udpate the metrics views using the new configuration. 976 try 977 { 978 updateViews(); 979 } 980 catch(Exception ex) 981 { 982 _logger.warning("unexpected exception while updating metrics view configuration:\n" + 983 ex.ToString()); 984 } 985 return; 986 } 987 } 988 } 989 getMetricsView(string name)990 private MetricsViewI getMetricsView(string name) 991 { 992 MetricsViewI view; 993 if(!_views.TryGetValue(name, out view)) 994 { 995 if(!_disabledViews.Contains(name)) 996 { 997 throw new IceMX.UnknownMetricsView(); 998 } 999 return null; 1000 } 1001 return view; 1002 } 1003 addOrUpdateMap(string mapName, IMetricsMapFactory factory)1004 private bool addOrUpdateMap(string mapName, IMetricsMapFactory factory) 1005 { 1006 bool updated = false; 1007 foreach(MetricsViewI v in _views.Values) 1008 { 1009 updated |= v.addOrUpdateMap(_properties, mapName, factory, _logger); 1010 } 1011 return updated; 1012 } 1013 removeMap(string mapName)1014 private bool removeMap(string mapName) 1015 { 1016 bool updated = false; 1017 foreach(MetricsViewI v in _views.Values) 1018 { 1019 updated |= v.removeMap(mapName); 1020 } 1021 return updated; 1022 } 1023 1024 private Ice.Properties _properties; 1025 readonly private Ice.Logger _logger; 1026 readonly private Dictionary<string, IMetricsMapFactory> _factories = 1027 new Dictionary<string, IMetricsMapFactory>(); 1028 private Dictionary<string, MetricsViewI> _views = new Dictionary<string, MetricsViewI>(); 1029 private List<string> _disabledViews = new List<string>(); 1030 } 1031 } 1032