public virtual IEnumerable <InstrumentationTarget> GetInstrumentationSet(string assemblyPath, InstrumentAttribute context, Predicate <ITypeDetails> typeFilter)
        {
            var toReturn = new List <InstrumentationTarget>();

            _logger.InfoFormat("Processing assembly {0}", assemblyPath);

            if (typeFilter == null)
            {
                typeFilter = x => true;
            }

            var allTypes = this.GetTypes(assemblyPath).Where(x => x.IsClass && !x.IsNested && typeFilter(x));

            _logger.DebugFormat("Found {0} types", allTypes.Count());

            InstrumentAttribute assyContext = null;

            if (allTypes.Any())
            {
                assyContext = allTypes.First().Assembly.InstrumentationContext;
            }

            foreach (var t in allTypes)
            {
                toReturn.AddRange(GetInstrumentationSet(t, InstrumentAttribute.GetEffectiveInstrumentationContext(assyContext, context)));
            }

            return(toReturn);
        }
예제 #2
0
        public void GetEffectiveInstrumentationContext_ReturnsContextEquivalentToSupplied_IfOnlyOneNonNullContextSuppliedWithNullsAfter()
        {
            var attr = new InstrumentAttribute {
                IncludeCompilerGeneratedCode = true, Metric = Metric.Scoped, MetricName = "Metric name", Scopes = InstrumentationScopes.All
            };
            var effective = InstrumentAttribute.GetEffectiveInstrumentationContext(attr, null, null);

            Assert.IsTrue(EqualityHelper.AreObjectsEquivalentByPublicProperties(attr, effective, false));
        }
예제 #3
0
        public void GetEffectiveInstrumentationContext_PrioritisesEarlierContextValues_ForMetricNameProperty()
        {
            var first = new InstrumentAttribute {
                MetricName = "Metric name 1"
            };
            var second = new InstrumentAttribute {
                MetricName = "Metric name 2"
            };

            var effective = InstrumentAttribute.GetEffectiveInstrumentationContext(first, second);

            Assert.AreEqual("Metric name 1", effective.MetricName);
        }
예제 #4
0
        public void GetEffectiveInstrumentationContext_PrioritisesEarlierContextValues_ForIncludeCompilerGeneratedCodeProperty()
        {
            var first = new InstrumentAttribute {
                IncludeCompilerGeneratedCode = true
            };
            var second = new InstrumentAttribute {
                IncludeCompilerGeneratedCode = false
            };

            var effective = InstrumentAttribute.GetEffectiveInstrumentationContext(first, second);

            Assert.IsTrue(effective.IncludeCompilerGeneratedCode);
        }
예제 #5
0
        public void GetEffectiveInstrumentationContext_PrioritisesEarlierContextValues_ForScopesProperty()
        {
            var first = new InstrumentAttribute {
                Scopes = InstrumentationScopes.Methods
            };
            var second = new InstrumentAttribute {
                Scopes = InstrumentationScopes.Constructors
            };

            var effective = InstrumentAttribute.GetEffectiveInstrumentationContext(first, second);

            Assert.AreEqual(InstrumentationScopes.Methods, effective.Scopes);
        }
예제 #6
0
        public void GetEffectiveInstrumentationContext_PrioritisesEarlierContextValues_ForMetricProperty()
        {
            var first = new InstrumentAttribute {
                Metric = Metric.Scoped
            };
            var second = new InstrumentAttribute {
                Metric = Metric.Both
            };

            var effective = InstrumentAttribute.GetEffectiveInstrumentationContext(first, second);

            Assert.AreEqual(Metric.Scoped, effective.Metric);
        }
예제 #7
0
        public void GetEffectiveInstrumentationContext_PrioritisesFirstSpecifiedContextValues_ForMetricProperty()
        {
            var first = new InstrumentAttribute {
                Metric = Metric.Unspecified
            };
            var second = new InstrumentAttribute {
                Metric = Metric.Both
            };
            var third = new InstrumentAttribute {
                Metric = Metric.Unscoped
            };

            var effective = InstrumentAttribute.GetEffectiveInstrumentationContext(first, second, third);

            Assert.AreEqual(Metric.Both, effective.Metric);
        }
예제 #8
0
        public void GetEffectiveInstrumentationContext_PrioritisesFirstNonNullContextValue_ForMetricNameProperty()
        {
            var first = new InstrumentAttribute {
                MetricName = null
            };
            var second = new InstrumentAttribute {
                MetricName = "Metric name 2"
            };
            var third = new InstrumentAttribute {
                MetricName = "Metric name 3"
            };

            var effective = InstrumentAttribute.GetEffectiveInstrumentationContext(first, second, third);

            Assert.AreEqual("Metric name 2", effective.MetricName);
        }
예제 #9
0
        public void GetEffectiveInstrumentationContext_ReturnsNull_WhenParamsArrayContainsOnlyNullEntries()
        {
            var effective = InstrumentAttribute.GetEffectiveInstrumentationContext(null, null, null);

            Assert.IsNull(effective);
        }
예제 #10
0
        public void GetEffectiveInstrumentationContext_ReturnsNull_WhenNullAttributesSupplied()
        {
            var effective = InstrumentAttribute.GetEffectiveInstrumentationContext(null);

            Assert.IsNull(effective);
        }
        protected virtual IEnumerable <InstrumentationTarget> GetInstrumentationSet(ITypeDetails t, InstrumentAttribute context)
        {
            var toReturn = new List <InstrumentationTarget>();

            if (!t.IsGenericTypeDefinition)
            {
                // Does the type have an Instrument attribute?
                var typeLevelAttribute = t.InstrumentationContext;
                typeLevelAttribute = InstrumentAttribute.GetEffectiveInstrumentationContext(typeLevelAttribute, context);

                if (t.IsCompilerGenerated && (typeLevelAttribute == null || !typeLevelAttribute.IncludeCompilerGeneratedCode))
                {
                    // Bail out early - we've found a compiler-generated method and haven't been told to include 'em
                    _logger.DebugFormat("Skipping type {0} - compiler-generated and configuration set to skip", t.FullName);

                    return(toReturn);
                }

                _logger.DebugFormat("Processing type {0}", t.FullName);

                var baseBindingFlags   = BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
                var propBindingFlags   = baseBindingFlags;
                var methodBindingFlags = baseBindingFlags;
                var ctorBindingFlags   = baseBindingFlags;

                if (typeLevelAttribute == null)
                {
                    propBindingFlags   |= BindingFlags.NonPublic | BindingFlags.Public;
                    methodBindingFlags |= BindingFlags.NonPublic | BindingFlags.Public;
                    ctorBindingFlags   |= BindingFlags.NonPublic | BindingFlags.Public;
                }
                else
                {
                    if ((typeLevelAttribute.Scopes & InstrumentationScopes.PublicProperties) == InstrumentationScopes.PublicProperties)
                    {
                        propBindingFlags |= BindingFlags.Public;
                    }
                    if ((typeLevelAttribute.Scopes & InstrumentationScopes.NonPublicProperties) == InstrumentationScopes.NonPublicProperties)
                    {
                        propBindingFlags |= BindingFlags.NonPublic;
                    }

                    if ((typeLevelAttribute.Scopes & InstrumentationScopes.PublicMethods) == InstrumentationScopes.PublicMethods)
                    {
                        methodBindingFlags |= BindingFlags.Public;
                    }
                    if ((typeLevelAttribute.Scopes & InstrumentationScopes.NonPublicMethods) == InstrumentationScopes.NonPublicMethods)
                    {
                        methodBindingFlags |= BindingFlags.NonPublic;
                    }

                    if ((typeLevelAttribute.Scopes & InstrumentationScopes.PublicConstructors) == InstrumentationScopes.PublicConstructors)
                    {
                        ctorBindingFlags |= BindingFlags.Public;
                    }
                    if ((typeLevelAttribute.Scopes & InstrumentationScopes.NonPublicConstructors) == InstrumentationScopes.NonPublicConstructors)
                    {
                        ctorBindingFlags |= BindingFlags.NonPublic;
                    }
                }

                _logger.DebugFormat("Prop flags {0}, Ctor flags {1}, Method flags {2}", propBindingFlags, ctorBindingFlags, methodBindingFlags);

                // Instrument everything in this type, irrespective of its member-level
                // details
                foreach (var methodDetails in t.GetMethods(methodBindingFlags))
                {
                    _logger.DebugFormat("Examining method {0}", methodDetails.ToString());

                    var attr = InstrumentAttribute.GetEffectiveInstrumentationContext(methodDetails.InstrumentationContext, typeLevelAttribute);
                    if (attr != null && (!methodDetails.IsCompilerGenerated || attr.IncludeCompilerGeneratedCode))
                    {
                        toReturn.Add(GetInstrumentationTarget(methodDetails, attr));
                    }
                }

                foreach (var propertyDetails in t.GetProperties(propBindingFlags))
                {
                    _logger.DebugFormat("Examining property {0}.{1}", t.FullName, propertyDetails.Name);

                    var getMethod = propertyDetails.GetMethod;
                    var setMethod = propertyDetails.SetMethod;

                    if (getMethod != null && getMethod.ContainsGenericParameters)
                    {
                        getMethod = null;
                    }

                    if (setMethod != null && setMethod.ContainsGenericParameters)
                    {
                        setMethod = null;
                    }

                    if (getMethod != null)
                    {
                        var getMethodAttr = InstrumentAttribute.GetEffectiveInstrumentationContext(propertyDetails.InstrumentationContext, getMethod.InstrumentationContext, typeLevelAttribute);
                        if (getMethodAttr != null)
                        {
                            toReturn.Add(GetInstrumentationTarget(getMethod, getMethodAttr));
                        }
                    }

                    if (setMethod != null)
                    {
                        var setMethodAttr = InstrumentAttribute.GetEffectiveInstrumentationContext(propertyDetails.InstrumentationContext, setMethod.InstrumentationContext, typeLevelAttribute);
                        if (setMethodAttr != null)
                        {
                            toReturn.Add(GetInstrumentationTarget(setMethod, setMethodAttr));
                        }
                    }
                }

                foreach (var constructorDetails in t.GetConstructors(ctorBindingFlags).Where(x => !x.ContainsGenericParameters))
                {
                    _logger.DebugFormat("Examining method {0}", constructorDetails.ToString());

                    var attr = InstrumentAttribute.GetEffectiveInstrumentationContext(constructorDetails.InstrumentationContext, typeLevelAttribute);
                    if (attr != null)
                    {
                        toReturn.Add(GetInstrumentationTarget(constructorDetails, attr));
                    }
                }

                // Process nested types recursively, rather than enumerating them from the get-go so that we can apply
                // instrumentation scoping recursively too - the nested class will take on the instrumentation configuration
                // of the containing type, if any, or whatever's been passed down by initial settings
                foreach (var nested in t.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
                {
                    toReturn.AddRange(GetInstrumentationSet(nested, typeLevelAttribute));
                }
            }
            else
            {
                _logger.DebugFormat("Skipping type {0} - generic types not supported", t.FullName);
            }

            return(toReturn);
        }