< Summary

Information
Class: IceMX.MetricsHelper<T>
Assembly: Ice
File(s): /_/csharp/src/Ice/MetricsObserverI.cs
Tag: 125_37167941578
Line coverage
100%
Covered lines: 4
Uncovered lines: 0
Coverable lines: 4
Total lines: 463
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage
100%
Covered methods: 4
Fully covered methods: 4
Total methods: 4
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
resolve(...)100%11100%
initMetrics(...)100%11100%
defaultResolve(...)100%11100%

File(s)

/_/csharp/src/Ice/MetricsObserverI.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using Ice.Internal;
 4using System.Diagnostics;
 5
 6namespace IceMX;
 7
 8/// <summary>
 9/// Helper class for metrics operations.
 10/// </summary>
 11/// <typeparam name="T">The metrics type.</typeparam>
 12public class MetricsHelper<T> where T : Metrics
 13{
 14    /// <summary>
 15    /// Resolves attribute values from metrics objects.
 16    /// </summary>
 17    public class AttributeResolver
 18    {
 19        private abstract class Resolver
 20        {
 21            protected Resolver(string name) => _name = name;
 22
 23            protected abstract object resolve(object obj);
 24
 25            public string resolveImpl(object obj)
 26            {
 27                try
 28                {
 29                    object result = resolve(obj);
 30                    if (result != null)
 31                    {
 32                        return result.ToString();
 33                    }
 34                    return "";
 35                }
 36                catch (ArgumentOutOfRangeException)
 37                {
 38                    throw;
 39                }
 40                catch (Exception ex)
 41                {
 42                    throw new ArgumentOutOfRangeException(_name, ex);
 43                }
 44            }
 45
 46            protected object getField(System.Reflection.FieldInfo field, object obj)
 47            {
 48                while (obj != null)
 49                {
 50                    try
 51                    {
 52                        return field.GetValue(obj);
 53                    }
 54                    catch (ArgumentException)
 55                    {
 56                        if (obj is Ice.EndpointInfo)
 57                        {
 58                            obj = ((Ice.EndpointInfo)obj).underlying;
 59                        }
 60                        else if (obj is Ice.ConnectionInfo)
 61                        {
 62                            obj = ((Ice.ConnectionInfo)obj).underlying;
 63                        }
 64                        else
 65                        {
 66                            throw;
 67                        }
 68                    }
 69                }
 70                return null;
 71            }
 72
 73            protected object getProperty(System.Reflection.PropertyInfo property, object obj) =>
 74                property?.GetValue(obj);
 75
 76            protected readonly string _name;
 77        }
 78
 79        private class FieldResolverI : Resolver
 80        {
 81            internal FieldResolverI(string name, System.Reflection.FieldInfo field)
 82                : base(name)
 83            {
 84                Debug.Assert(field != null);
 85                _field = field;
 86            }
 87
 88            protected override object resolve(object obj) => getField(_field, obj);
 89
 90            private readonly System.Reflection.FieldInfo _field;
 91        }
 92
 93        private class MethodResolverI : Resolver
 94        {
 95            internal MethodResolverI(string name, System.Reflection.MethodInfo method)
 96                : base(name)
 97            {
 98                Debug.Assert(method != null);
 99                _method = method;
 100            }
 101
 102            protected override object resolve(object obj) => _method.Invoke(obj, null);
 103
 104            private readonly System.Reflection.MethodInfo _method;
 105        }
 106
 107        private class MemberFieldResolverI : Resolver
 108        {
 109            internal MemberFieldResolverI(
 110                string name,
 111                System.Reflection.MethodInfo method,
 112                System.Reflection.FieldInfo field)
 113                : base(name)
 114            {
 115                Debug.Assert(method != null && field != null);
 116                _method = method;
 117                _field = field;
 118            }
 119
 120            protected override object resolve(object obj)
 121            {
 122                object o = _method.Invoke(obj, null);
 123                if (o != null)
 124                {
 125                    return getField(_field, o);
 126                }
 127                throw new ArgumentOutOfRangeException(_name);
 128            }
 129
 130            private readonly System.Reflection.MethodInfo _method;
 131            private readonly System.Reflection.FieldInfo _field;
 132        }
 133
 134        private class MemberPropertyResolverI : Resolver
 135        {
 136            private readonly System.Reflection.MethodInfo _method;
 137            private readonly System.Reflection.PropertyInfo _property;
 138
 139            internal MemberPropertyResolverI(
 140                string name,
 141                System.Reflection.MethodInfo method,
 142                System.Reflection.PropertyInfo property)
 143                : base(name)
 144            {
 145                Debug.Assert(method is not null && property is not null);
 146                _method = method;
 147                _property = property;
 148            }
 149
 150            protected override object resolve(object obj) =>
 151                _method.Invoke(obj, null) is object o ?
 152                    getProperty(_property, o) : throw new ArgumentOutOfRangeException(_name);
 153        }
 154
 155        private class MemberMethodResolverI : Resolver
 156        {
 157            internal MemberMethodResolverI(
 158                string name,
 159                System.Reflection.MethodInfo method,
 160                System.Reflection.MethodInfo subMeth)
 161                : base(name)
 162            {
 163                Debug.Assert(method != null && subMeth != null);
 164                _method = method;
 165                _subMethod = subMeth;
 166            }
 167
 168            protected override object resolve(object obj)
 169            {
 170                object o = _method.Invoke(obj, null);
 171                if (o != null)
 172                {
 173                    return _subMethod.Invoke(o, null);
 174                }
 175                throw new ArgumentOutOfRangeException(_name);
 176            }
 177
 178            private readonly System.Reflection.MethodInfo _method;
 179            private readonly System.Reflection.MethodInfo _subMethod;
 180        }
 181
 182        protected AttributeResolver()
 183        {
 184        }
 185
 186        public string resolve(MetricsHelper<T> helper, string attribute)
 187        {
 188            if (!_attributes.TryGetValue(attribute, out Resolver resolver))
 189            {
 190                if (attribute == "none")
 191                {
 192                    return "";
 193                }
 194                string v = helper.defaultResolve(attribute);
 195                if (v != null)
 196                {
 197                    return v;
 198                }
 199                throw new ArgumentOutOfRangeException(attribute);
 200            }
 201            return resolver.resolveImpl(helper);
 202        }
 203
 204        public void add(
 205            string name,
 206            System.Reflection.MethodInfo method) => _attributes.Add(name, new MethodResolverI(name, method));
 207
 208        public void add(
 209            string name,
 210            System.Reflection.FieldInfo field) => _attributes.Add(name, new FieldResolverI(name, field));
 211
 212        public void add(
 213            string name,
 214            System.Reflection.MethodInfo method,
 215            System.Reflection.FieldInfo field) =>
 216                _attributes.Add(name, new MemberFieldResolverI(name, method, field));
 217
 218        public void add(
 219            string name,
 220            System.Reflection.MethodInfo method,
 221            System.Reflection.PropertyInfo property) =>
 222      _attributes.Add(name, new MemberPropertyResolverI(name, method, property));
 223
 224        public void
 225        add(
 226            string name,
 227            System.Reflection.MethodInfo method,
 228            System.Reflection.MethodInfo subMethod) =>
 229                _attributes.Add(name, new MemberMethodResolverI(name, method, subMethod));
 230
 231        private readonly Dictionary<string, Resolver> _attributes = new Dictionary<string, Resolver>();
 232    }
 233
 1234    protected MetricsHelper(AttributeResolver attributes) => _attributes = attributes;
 235
 1236    public string resolve(string attribute) => _attributes.resolve(this, attribute);
 237
 238    public virtual void initMetrics(T metrics)
 239    {
 240        // Override in specialized helpers.
 1241    }
 242
 1243    protected virtual string defaultResolve(string attribute) => null;
 244
 245    private readonly AttributeResolver _attributes;
 246}
 247
 248/// <summary>
 249/// Observer implementation for metrics collection.
 250/// </summary>
 251/// <typeparam name="T">The metrics type.</typeparam>
 252public class Observer<T> : Stopwatch, Ice.Instrumentation.Observer where T : Metrics, new()
 253{
 254    /// <summary>
 255    /// Represents a function that updates a metrics object.
 256    /// </summary>
 257    /// <param name="m">The metrics object to update.</param>
 258    public delegate void MetricsUpdate(T m);
 259
 260    public virtual void attach() => Start();
 261
 262    public virtual void detach()
 263    {
 264        Stop();
 265        long lifetime = _previousDelay + (long)(ElapsedTicks / (Frequency / 1000000.0));
 266        foreach (MetricsMap<T>.Entry e in _objects)
 267        {
 268            e.detach(lifetime);
 269        }
 270    }
 271
 272    public virtual void failed(string exceptionName)
 273    {
 274        foreach (MetricsMap<T>.Entry e in _objects)
 275        {
 276            e.failed(exceptionName);
 277        }
 278    }
 279
 280    public void forEach(MetricsUpdate u)
 281    {
 282        foreach (MetricsMap<T>.Entry e in _objects)
 283        {
 284            e.execute(u);
 285        }
 286    }
 287
 288    public void init(MetricsHelper<T> helper, List<MetricsMap<T>.Entry> objects, Observer<T> previous)
 289    {
 290        _objects = objects;
 291
 292        if (previous == null)
 293        {
 294            return;
 295        }
 296
 297        _previousDelay = previous._previousDelay + (long)(previous.ElapsedTicks / (Frequency / 1000000.0));
 298        foreach (MetricsMap<T>.Entry e in previous._objects)
 299        {
 300            if (!_objects.Contains(e))
 301            {
 302                e.detach(_previousDelay);
 303            }
 304        }
 305    }
 306
 307    public ObserverImpl getObserver<S, ObserverImpl>(string mapName, MetricsHelper<S> helper)
 308        where S : Metrics, new()
 309        where ObserverImpl : Observer<S>, new()
 310    {
 311        List<MetricsMap<S>.Entry> metricsObjects = null;
 312        foreach (MetricsMap<T>.Entry entry in _objects)
 313        {
 314            MetricsMap<S>.Entry e = entry.getMatching(mapName, helper);
 315            if (e != null)
 316            {
 317                metricsObjects ??= new List<MetricsMap<S>.Entry>(_objects.Count);
 318                metricsObjects.Add(e);
 319            }
 320        }
 321
 322        if (metricsObjects == null)
 323        {
 324            return null;
 325        }
 326
 327        try
 328        {
 329            var obsv = new ObserverImpl();
 330            obsv.init(helper, metricsObjects, null);
 331            return obsv;
 332        }
 333        catch (Exception)
 334        {
 335            Debug.Assert(false);
 336            return null;
 337        }
 338    }
 339
 340    public MetricsMap<T>.Entry getEntry(MetricsMap<T> map)
 341    {
 342        foreach (MetricsMap<T>.Entry e in _objects)
 343        {
 344            if (e.getMap() == map)
 345            {
 346                return e;
 347            }
 348        }
 349        return null;
 350    }
 351
 352    private List<MetricsMap<T>.Entry> _objects;
 353    private long _previousDelay;
 354}
 355
 356/// <summary>
 357/// Factory for creating observer instances for metrics collection.
 358/// </summary>
 359/// <typeparam name="T">The metrics type.</typeparam>
 360/// <typeparam name="O">The observer type.</typeparam>
 361public class ObserverFactory<T, O> where T : Metrics, new() where O : Observer<T>, new()
 362{
 363    public ObserverFactory(Ice.Internal.MetricsAdminI metrics, string name)
 364    {
 365        _metrics = metrics;
 366        _name = name;
 367        _metrics.registerMap<T>(name, this.update);
 368    }
 369
 370    public ObserverFactory(string name)
 371    {
 372        _name = name;
 373        _metrics = null;
 374    }
 375
 376    public void destroy() => _metrics?.unregisterMap(_name);
 377
 378    public O getObserver(MetricsHelper<T> helper) => getObserver(helper, null);
 379
 380    public O getObserver(MetricsHelper<T> helper, object observer)
 381    {
 382        O old = null;
 383        try
 384        {
 385            old = (O)observer;
 386        }
 387        catch (InvalidCastException)
 388        {
 389        }
 390
 391        lock (_mutex)
 392        {
 393            List<MetricsMap<T>.Entry> metricsObjects = null;
 394            foreach (MetricsMap<T> m in _maps)
 395            {
 396                MetricsMap<T>.Entry e = m.getMatching(helper, old?.getEntry(m));
 397                if (e != null)
 398                {
 399                    metricsObjects ??= new List<MetricsMap<T>.Entry>(_maps.Count);
 400                    metricsObjects.Add(e);
 401                }
 402            }
 403
 404            if (metricsObjects != null)
 405            {
 406                O obsv;
 407                try
 408                {
 409                    obsv = new O();
 410                }
 411                catch (Exception)
 412                {
 413                    Debug.Assert(false);
 414                    return null;
 415                }
 416                obsv.init(helper, metricsObjects, old);
 417                return obsv;
 418            }
 419        }
 420
 421        // No map matched the updated observer: detach the old observer outside the factory lock, since
 422        // detach() can call into a user-supplied instrumentation delegate.
 423        old?.detach();
 424        return null;
 425    }
 426
 427    public void registerSubMap<S>(string subMap, System.Reflection.FieldInfo field)
 428        where S : Metrics, new() => _metrics.registerSubMap<S>(_name, subMap, field);
 429
 430    public bool isEnabled() => _enabled;
 431
 432    public void update()
 433    {
 434        Action updater;
 435        lock (_mutex)
 436        {
 437            _maps.Clear();
 438            foreach (MetricsMap<T> m in _metrics.getMaps<T>(_name))
 439            {
 440                _maps.Add(m);
 441            }
 442            _enabled = _maps.Count > 0;
 443            updater = _updater;
 444        }
 445
 446        updater?.Invoke();
 447    }
 448
 449    public void setUpdater(Action updater)
 450    {
 451        lock (_mutex)
 452        {
 453            _updater = updater;
 454        }
 455    }
 456
 457    private readonly MetricsAdminI _metrics;
 458    private readonly string _name;
 459    private readonly List<MetricsMap<T>> _maps = new();
 460    private volatile bool _enabled;
 461    private Action _updater;
 462    private readonly object _mutex = new();
 463}