// // Copyright (c) ZeroC, Inc. All rights reserved. // namespace IceMX { using IceInternal; using System; using System.Diagnostics; using System.Collections.Generic; public class MetricsHelper where T : Metrics { public class AttributeResolver { private abstract class Resolver { protected Resolver(string name) { _name = name; } protected abstract object resolve(object obj); public string resolveImpl(object obj) { try { object result = resolve(obj); if(result != null) { return result.ToString(); } return ""; } catch(ArgumentOutOfRangeException) { throw; } catch(Exception ex) { throw new ArgumentOutOfRangeException(_name, ex); } } protected object getField(System.Reflection.FieldInfo field, object obj) { while(obj != null) { try { return field.GetValue(obj); } catch(ArgumentException) { if(obj is Ice.EndpointInfo) { obj = ((Ice.EndpointInfo)obj).underlying; } else if(obj is Ice.ConnectionInfo) { obj = ((Ice.ConnectionInfo)obj).underlying; } else { throw; } } } return null; } readonly protected string _name; } class FieldResolverI : Resolver { internal FieldResolverI(string name, System.Reflection.FieldInfo field) : base(name) { Debug.Assert(field != null); _field = field; } override protected object resolve(object obj) { return getField(_field, obj); } readonly private System.Reflection.FieldInfo _field; } class MethodResolverI : Resolver { internal MethodResolverI(string name, System.Reflection.MethodInfo method) : base(name) { Debug.Assert(method != null); _method = method; } override protected object resolve(object obj) { return _method.Invoke(obj, null); } readonly private System.Reflection.MethodInfo _method; } class MemberFieldResolverI : Resolver { internal MemberFieldResolverI(string name, System.Reflection.MethodInfo method, System.Reflection.FieldInfo field) : base(name) { Debug.Assert(method != null && field != null); _method = method; _field = field; } override protected object resolve(object obj) { object o = _method.Invoke(obj, null); if(o != null) { return getField(_field, o); } throw new ArgumentOutOfRangeException(_name); } readonly private System.Reflection.MethodInfo _method; readonly private System.Reflection.FieldInfo _field; } class MemberMethodResolverI : Resolver { internal MemberMethodResolverI(string name, System.Reflection.MethodInfo method, System.Reflection.MethodInfo subMeth) : base(name) { Debug.Assert(method != null && subMeth != null); _method = method; _subMethod = subMeth; } override protected object resolve(object obj) { object o = _method.Invoke(obj, null); if(o != null) { return _subMethod.Invoke(o, null); } throw new ArgumentOutOfRangeException(_name); } readonly private System.Reflection.MethodInfo _method; readonly private System.Reflection.MethodInfo _subMethod; } protected AttributeResolver() { } public string resolve(MetricsHelper helper, string attribute) { Resolver resolver; if(!_attributes.TryGetValue(attribute, out resolver)) { if(attribute.Equals("none")) { return ""; } string v = helper.defaultResolve(attribute); if(v != null) { return v; } throw new ArgumentOutOfRangeException(attribute); } return resolver.resolveImpl(helper); } public void add(string name, System.Reflection.MethodInfo method) { _attributes.Add(name, new MethodResolverI(name, method)); } public void add(string name, System.Reflection.FieldInfo field) { _attributes.Add(name, new FieldResolverI(name, field)); } public void add(string name, System.Reflection.MethodInfo method, System.Reflection.FieldInfo field) { _attributes.Add(name, new MemberFieldResolverI(name, method, field)); } public void add(string name, System.Reflection.MethodInfo method, System.Reflection.MethodInfo subMethod) { _attributes.Add(name, new MemberMethodResolverI(name, method, subMethod)); } private Dictionary _attributes = new Dictionary(); } protected MetricsHelper(AttributeResolver attributes) { _attributes = attributes; } public string resolve(string attribute) { return _attributes.resolve(this, attribute); } virtual public void initMetrics(T metrics) { // Override in specialized helpers. } virtual protected string defaultResolve(string attribute) { return null; } private AttributeResolver _attributes; } public class Observer : Stopwatch, Ice.Instrumentation.Observer where T : Metrics, new() { public delegate void MetricsUpdate(T m); virtual public void attach() { Start(); } virtual public void detach() { Stop(); long lifetime = _previousDelay + (long)(ElapsedTicks / (Frequency / 1000000.0)); foreach(MetricsMap.Entry e in _objects) { e.detach(lifetime); } } virtual public void failed(string exceptionName) { foreach(MetricsMap.Entry e in _objects) { e.failed(exceptionName); } } public void forEach(MetricsUpdate u) { foreach(MetricsMap.Entry e in _objects) { e.execute(u); } } public void init(MetricsHelper helper, List.Entry> objects, Observer previous) { _objects = objects; if(previous == null) { return; } _previousDelay = previous._previousDelay + (long)(previous.ElapsedTicks / (Frequency / 1000000.0)); foreach(MetricsMap.Entry e in previous._objects) { if(!_objects.Contains(e)) { e.detach(_previousDelay); } } } public ObserverImpl getObserver(string mapName, MetricsHelper helper) where S : Metrics, new() where ObserverImpl : Observer, new() { List.Entry> metricsObjects = null; foreach(MetricsMap.Entry entry in _objects) { MetricsMap.Entry e = entry.getMatching(mapName, helper); if(e != null) { if(metricsObjects == null) { metricsObjects = new List.Entry>(_objects.Count); } metricsObjects.Add(e); } } if(metricsObjects == null) { return null; } try { ObserverImpl obsv = new ObserverImpl(); obsv.init(helper, metricsObjects, null); return obsv; } catch(Exception) { Debug.Assert(false); return null; } } public MetricsMap.Entry getEntry(MetricsMap map) { foreach(MetricsMap.Entry e in _objects) { if(e.getMap() == map) { return e; } } return null; } private List.Entry> _objects; private long _previousDelay = 0; } public class ObserverFactory where T : Metrics, new() where O : Observer, new() { public ObserverFactory(IceInternal.MetricsAdminI metrics, string name) { _metrics = metrics; _name = name; _metrics.registerMap(name, this.update); } public ObserverFactory(string name) { _name = name; _metrics = null; } public void destroy() { if(_metrics != null) { _metrics.unregisterMap(_name); } } public O getObserver(MetricsHelper helper) { return getObserver(helper, null); } public O getObserver(MetricsHelper helper, object observer) { lock(this) { List.Entry> metricsObjects = null; O old = null; try { old = (O)observer; } catch(InvalidCastException) { } foreach(MetricsMap m in _maps) { MetricsMap.Entry e = m.getMatching(helper, old != null ? old.getEntry(m) : null); if(e != null) { if(metricsObjects == null) { metricsObjects = new List.Entry>(_maps.Count); } metricsObjects.Add(e); } } if(metricsObjects == null) { if(old != null) { old.detach(); } return null; } O obsv; try { obsv = new O(); } catch(Exception) { Debug.Assert(false); return null; } obsv.init(helper, metricsObjects, old); return obsv; } } public void registerSubMap(string subMap, System.Reflection.FieldInfo field) where S : Metrics, new() { _metrics.registerSubMap(_name, subMap, field); } public bool isEnabled() { return _enabled; } public void update() { Action updater; lock(this) { _maps.Clear(); foreach(MetricsMap m in _metrics.getMaps(_name)) { _maps.Add(m); } _enabled = _maps.Count > 0; updater = _updater; } if(updater != null) { updater(); } } public void setUpdater(Action updater) { lock(this) { _updater = updater; } } private readonly MetricsAdminI _metrics; private readonly string _name; private List> _maps = new List>(); private volatile bool _enabled; private Action _updater; } }