/// Class for New Relic-compatible XML output of the tracerFactory element
Пример #1
0
        /// <summary>
        /// Creates an XML-renderable Extension object that represents the instrumentation settings
        /// specified by the supplied list of targets.
        /// </summary>
        /// <param name="targets">The set of targets to be instrumented.</param>
        /// <returns>An Extension object representing the in-memory New Relic custom
        /// instrumentation configuration XML document.</returns>
        public static Extension Render(IEnumerable<InstrumentationTarget> targets)
        {
            Instrumentation toReturn = new Instrumentation();

            // Group the targets by metric name...
            var byMetricName = targets.GroupBy(x => x.MetricName ?? string.Empty);
            foreach (var groupedByMetricName in byMetricName.OrderBy(x => x.Key))
            {
                // Then by name
                var byName = groupedByMetricName.GroupBy(x => x.Name ?? string.Empty);
                foreach (var groupedByName in byName.OrderBy(x => x.Key))
                {
                    // Then by priority
                    var byPriority = groupedByName.GroupBy(x => x.TransactionNamingPriority ?? string.Empty);
                    foreach (var groupedByPriority in byPriority.OrderBy(x => x.Key))
                    {
                        // Then group by metric
                        var byMetric = groupedByPriority.GroupBy(x => x.Metric);
                        foreach (var groupedByMetric in byMetric.OrderBy(x => x.Key))
                        {
                            string metricName = groupedByMetricName.Key == string.Empty ? null : groupedByMetricName.Key;
                            string name = groupedByName.Key == string.Empty ? null : groupedByName.Key;
                            string priority = groupedByPriority.Key == string.Empty ? null : groupedByPriority.Key;

                            TracerFactory tracerFactory = new TracerFactory(metricName, name, priority, groupedByMetric.Key);

                            var byType = groupedByMetric.GroupBy(x => x.Target.DeclaringType);
                            foreach (var groupedByType in byType.OrderBy(x => x.Key.Assembly.FullName).ThenBy(x => x.Key.FullName))
                            {
                                Match match = GetMatchFromType(groupedByType.Key);

                                // Each item in the groupedByType enumerable is a method to be instrumented
                                foreach (var toInstrument in groupedByType.OrderBy(x => x.Target.Name))
                                {
                                    ExactMethodMatcher methodMatcher = GetMatcherFromTarget(toInstrument);
                                    match.Matches.Add(methodMatcher);
                                }

                                // De-dupe the method matchers, in case we have some parameterless
                                // entries and some with - as the parameterless ones will take precedence
                                // anyway, there's no point keeping the others
                                HashSet<ExactMethodMatcher> toDelete = new HashSet<ExactMethodMatcher>();
                                foreach (var matcher in match.Matches.Where(x => string.IsNullOrWhiteSpace(x.ParameterTypes)))
                                {
                                    toDelete.UnionWith(match.Matches.Where(x => x.MethodName == matcher.MethodName && !string.IsNullOrWhiteSpace(x.ParameterTypes)));
                                }

                                match.Matches.RemoveAll(x => toDelete.Contains(x));

                                tracerFactory.MatchDefinitions.Add(match);
                            }

                            toReturn.TracerFactories.Add(tracerFactory);
                        }
                    }
                }
            }

            return new Extension() { Instrumentation = toReturn };
        }
Пример #2
0
        public void Merge_CreatesNewFactories_WhenFactoryDefinitionsDifferent()
        {
            TracerFactory first = new TracerFactory();
            Match firstMatch = new Match() { AssemblyName = "Test", ClassName = "TestClass" };
            firstMatch.Matches.Add(new ExactMethodMatcher("TestMethod1", new[] { "ParamType1", "ParamType2" }));
            first.MatchDefinitions.Add(firstMatch);

            TracerFactory second = new TracerFactory("DifferentFactory", "TestFactory", "1", Metric.Scoped);
            Match secondMatch = new Match() { AssemblyName = firstMatch.AssemblyName, ClassName = firstMatch.ClassName };
            secondMatch.Matches.Add(new ExactMethodMatcher("TestMethod1", new[] { "ParamType1", "ParamType2" }));
            second.MatchDefinitions.Add(secondMatch);

            Extension firstExtension = new Extension();
            firstExtension.Instrumentation.TracerFactories.Add(first);

            Extension secondExtension = new Extension();
            secondExtension.Instrumentation.TracerFactories.Add(second);

            Extension merged = Extension.Merge(firstExtension, secondExtension);

            Assert.AreEqual(2, merged.Instrumentation.TracerFactories.Count);
            Assert.AreEqual(1, merged.Instrumentation.TracerFactories.Count(x => x.MetricName == "DifferentFactory" && x.Metric == Metric.Scoped));
            Assert.AreEqual(1, merged.Instrumentation.TracerFactories.Count(x => x.Name == "TestFactory" && x.Metric == Metric.Scoped));
            Assert.AreEqual(1, merged.Instrumentation.TracerFactories.Count(x => x.TransactionNamingPriority == "1" && x.Metric == Metric.Scoped));
            Assert.AreEqual(1, merged.Instrumentation.TracerFactories.Count(x => x.Metric == Metric.Unspecified));

            var different = merged.Instrumentation.TracerFactories.Where(x => x.MetricName == "DifferentFactory").First();
            var other = merged.Instrumentation.TracerFactories.Where(x => x != different).First();

            Assert.AreEqual(1, different.MatchDefinitions.Count);
            Assert.AreEqual(1, other.MatchDefinitions.Count);

            Assert.AreEqual("Test", different.MatchDefinitions.First().AssemblyName);
            Assert.AreEqual("Test", other.MatchDefinitions.First().AssemblyName);

            Assert.AreEqual("TestClass", different.MatchDefinitions.First().ClassName);
            Assert.AreEqual("TestClass", other.MatchDefinitions.First().ClassName);

            Assert.AreEqual(1, different.MatchDefinitions.First().Matches.Count());
            Assert.AreEqual(1, other.MatchDefinitions.First().Matches.Count());

            Assert.AreEqual(1, different.MatchDefinitions.First().Matches.Count(x => x.MethodName == "TestMethod1" && x.ParameterTypes == "ParamType1,ParamType2"));
            Assert.AreEqual(1, other.MatchDefinitions.First().Matches.Count(x => x.MethodName == "TestMethod1" && x.ParameterTypes == "ParamType1,ParamType2"));
        }
Пример #3
0
        public void Merge_CombinesExactMethodsMatchers_WhenContextSame()
        {
            TracerFactory first = new TracerFactory("MetricName", "Name", "1", Metric.Scoped);
            Match firstMatch = new Match() { AssemblyName = "Test", ClassName = "TestClass" };
            firstMatch.Matches.Add(new ExactMethodMatcher("TestMethod1", new[] { "ParamType1", "ParamType2" }));
            first.MatchDefinitions.Add(firstMatch);

            TracerFactory second = new TracerFactory("MetricName", "Name", "1", Metric.Scoped);
            Match secondMatch = new Match() { AssemblyName = firstMatch.AssemblyName, ClassName = firstMatch.ClassName };
            secondMatch.Matches.Add(new ExactMethodMatcher("TestMethod1", new[] { "ParamType3" }));
            second.MatchDefinitions.Add(secondMatch);

            Extension firstExtension = new Extension();
            firstExtension.Instrumentation.TracerFactories.Add(first);

            Extension secondExtension = new Extension();
            secondExtension.Instrumentation.TracerFactories.Add(second);

            Extension merged = Extension.Merge(firstExtension, secondExtension);

            Assert.AreEqual(1, merged.Instrumentation.TracerFactories.Count);

            var firstFactory = merged.Instrumentation.TracerFactories.First();
            Assert.AreEqual("MetricName", firstFactory.MetricName);
            Assert.AreEqual("Name", firstFactory.Name);
            Assert.AreEqual("1", firstFactory.TransactionNamingPriority);
            Assert.AreEqual(Metric.Scoped, firstFactory.Metric);
            Assert.IsNotNull(firstFactory.MatchDefinitions);

            var firstFactoryMatches = firstFactory.MatchDefinitions;
            Assert.AreEqual(1, firstFactoryMatches.Count());

            var firstFactoryMatch = firstFactoryMatches.First();
            Assert.AreEqual("Test", firstFactoryMatch.AssemblyName);
            Assert.AreEqual("TestClass", firstFactoryMatch.ClassName);

            var methodMatchers = firstFactoryMatch.Matches;
            Assert.AreEqual(2, methodMatchers.Count);

            Assert.AreEqual(2, methodMatchers.Count(x => x.MethodName == "TestMethod1"));
            Assert.AreEqual(1, methodMatchers.Count(x => x.MethodName == "TestMethod1" && x.ParameterTypes == "ParamType1,ParamType2"));
            Assert.AreEqual(1, methodMatchers.Count(x => x.MethodName == "TestMethod1" && x.ParameterTypes == "ParamType3"));
        }
Пример #4
0
        /// <summary>
        /// Creates an XML-renderable Extension object that represents the instrumentation settings
        /// specified by the supplied list of targets.
        /// </summary>
        /// <param name="targets">The set of targets to be instrumented.</param>
        /// <returns>An Extension object representing the in-memory New Relic custom
        /// instrumentation configuration XML document.</returns>
        public static Extension Render(IEnumerable <InstrumentationTarget> targets)
        {
            Instrumentation toReturn = new Instrumentation();

            // Group the targets by metric name...
            var byMetricName = targets.GroupBy(x => x.MetricName ?? string.Empty);

            foreach (var groupedByMetricName in byMetricName.OrderBy(x => x.Key))
            {
                // Then by name
                var byName = groupedByMetricName.GroupBy(x => x.Name ?? string.Empty);
                foreach (var groupedByName in byName.OrderBy(x => x.Key))
                {
                    // Then by priority
                    var byPriority = groupedByName.GroupBy(x => x.TransactionNamingPriority ?? string.Empty);
                    foreach (var groupedByPriority in byPriority.OrderBy(x => x.Key))
                    {
                        // Then group by metric
                        var byMetric = groupedByPriority.GroupBy(x => x.Metric);
                        foreach (var groupedByMetric in byMetric.OrderBy(x => x.Key))
                        {
                            string metricName = groupedByMetricName.Key == string.Empty ? null : groupedByMetricName.Key;
                            string name       = groupedByName.Key == string.Empty ? null : groupedByName.Key;
                            string priority   = groupedByPriority.Key == string.Empty ? null : groupedByPriority.Key;

                            TracerFactory tracerFactory = new TracerFactory(metricName, name, priority, groupedByMetric.Key);

                            var byType = groupedByMetric.GroupBy(x => x.Target.DeclaringType);
                            foreach (var groupedByType in byType.OrderBy(x => x.Key.Assembly.FullName).ThenBy(x => x.Key.FullName))
                            {
                                Match match = GetMatchFromType(groupedByType.Key);

                                // Each item in the groupedByType enumerable is a method to be instrumented
                                foreach (var toInstrument in groupedByType.OrderBy(x => x.Target.Name))
                                {
                                    ExactMethodMatcher methodMatcher = GetMatcherFromTarget(toInstrument);
                                    match.Matches.Add(methodMatcher);
                                }

                                // De-dupe the method matchers, in case we have some parameterless
                                // entries and some with - as the parameterless ones will take precedence
                                // anyway, there's no point keeping the others
                                HashSet <ExactMethodMatcher> toDelete = new HashSet <ExactMethodMatcher>();
                                foreach (var matcher in match.Matches.Where(x => string.IsNullOrWhiteSpace(x.ParameterTypes)))
                                {
                                    toDelete.UnionWith(match.Matches.Where(x => x.MethodName == matcher.MethodName && !string.IsNullOrWhiteSpace(x.ParameterTypes)));
                                }

                                match.Matches.RemoveAll(x => toDelete.Contains(x));

                                tracerFactory.MatchDefinitions.Add(match);
                            }

                            toReturn.TracerFactories.Add(tracerFactory);
                        }
                    }
                }
            }

            return(new Extension()
            {
                Instrumentation = toReturn
            });
        }
Пример #5
0
        /// <summary>
        /// Produces a new Extension object that represents the union of all instrumentation
        /// targets specified in the supplied Extension objects.
        /// </summary>
        /// <param name="toMerge">The Extension objects to be merged.</param>
        /// <returns>A single Extension object that represents the combined instrumentation
        /// footprint described by all of the supplied Extension objects.</returns>
        public static Extension Merge(params Extension[] toMerge)
        {
            Extension toReturn = new Extension();

            var matchRecords = new Dictionary<DenormalisedExactMatchRecord, HashSet<ExactMethodMatcher>>();

            foreach (var factory in toMerge.SelectMany(x => x.Instrumentation.TracerFactories))
            {
                foreach (var match in factory.MatchDefinitions)
                {
                    DenormalisedExactMatchRecord matchRecord = new DenormalisedExactMatchRecord
                    {
                        Metric = factory.Metric,
                        MetricName = factory.MetricName,
                        Name = factory.Name,
                        TransactionNamingPriority = factory.TransactionNamingPriority,
                        AssemblyName = match.AssemblyName,
                        ClassName = match.ClassName
                    };

                    HashSet<ExactMethodMatcher> matchers = null;

                    if (!matchRecords.TryGetValue(matchRecord, out matchers))
                    {
                        matchers = matchRecords[matchRecord] = new HashSet<ExactMethodMatcher>();
                    }

                    matchers.UnionWith(match.Matches.Select(x => new ExactMethodMatcher { MethodName = x.MethodName, ParameterTypes = x.ParameterTypes }));
                }
            }

            // Group the records by factory details, then by assy/classname pair
            var keysByFactoryDetails = matchRecords.Keys.GroupBy(x => new { Metric = x.Metric, MetricName = x.MetricName, Name = x.Name, TransactionNamingPriority = x.TransactionNamingPriority});
            foreach (var factoryDetail in keysByFactoryDetails)
            {
                TracerFactory toAdd = new TracerFactory(factoryDetail.Key.MetricName, factoryDetail.Key.Name, factoryDetail.Key.TransactionNamingPriority, factoryDetail.Key.Metric);

                var byClassDetail = factoryDetail.GroupBy(x => new { AssemblyName = x.AssemblyName, ClassName = x.ClassName });
                foreach (var classDetail in byClassDetail)
                {
                    Match matchToAdd = new Match(classDetail.Key.AssemblyName, classDetail.Key.ClassName);

                    var matchRecord = new DenormalisedExactMatchRecord
                    {
                        Metric = toAdd.Metric,
                        MetricName = toAdd.MetricName,
                        Name = toAdd.Name,
                        TransactionNamingPriority = toAdd.TransactionNamingPriority,
                        AssemblyName = matchToAdd.AssemblyName,
                        ClassName = matchToAdd.ClassName
                    };

                    matchToAdd.Matches = matchRecords[matchRecord].OrderBy(x => x.MethodName).ThenBy(x => x.ParameterTypes).ToList();
                    toAdd.MatchDefinitions.Add(matchToAdd);
                }

                toAdd.MatchDefinitions = toAdd.MatchDefinitions.OrderBy(x => x.AssemblyName).ThenBy(x => x.ClassName).ToList();

                toReturn.Instrumentation.TracerFactories.Add(toAdd);
            }

            // Have tracer factories prefer unspecified metrics and metric names first, then others later
            toReturn.Instrumentation.TracerFactories =
                toReturn
                .Instrumentation
                .TracerFactories
                .OrderBy(x => x.Metric == Metric.Unspecified ? -1 : (int) x.Metric)
                .ThenBy(x => x.MetricName ?? string.Empty)
                .ThenBy(x => x.Name ?? string.Empty)
                .ThenBy(x => x.TransactionNamingPriority ?? string.Empty)
                .ToList();

            return toReturn;
        }
Пример #6
0
        public void Merge_DoesNotDuplicateMethodMatchers_WhenContextSame()
        {
            TracerFactory first = new TracerFactory();
            Match firstMatch = new Match() { AssemblyName = "Test", ClassName = "TestClass" };
            firstMatch.Matches.Add(new ExactMethodMatcher("TestMethod1", new[] { "ParamType1", "ParamType2" }));
            first.MatchDefinitions.Add(firstMatch);

            TracerFactory second = new TracerFactory();
            Match secondMatch = new Match() { AssemblyName = firstMatch.AssemblyName, ClassName = firstMatch.ClassName };
            secondMatch.Matches.Add(new ExactMethodMatcher("TestMethod1", new[] { "ParamType1", "ParamType2" }));
            second.MatchDefinitions.Add(secondMatch);

            Extension firstExtension = new Extension();
            firstExtension.Instrumentation.TracerFactories.Add(first);

            Extension secondExtension = new Extension();
            secondExtension.Instrumentation.TracerFactories.Add(second);

            Extension merged = Extension.Merge(firstExtension, secondExtension);

            Assert.AreEqual(1, merged.Instrumentation.TracerFactories.Count());
            Assert.IsTrue(string.IsNullOrWhiteSpace(merged.Instrumentation.TracerFactories.First().MetricName));
            Assert.AreEqual(Metric.Unspecified, merged.Instrumentation.TracerFactories.First().Metric);
            Assert.AreEqual(1, merged.Instrumentation.TracerFactories.First().MatchDefinitions.Count);

            var firstMergedMatch = merged.Instrumentation.TracerFactories.First().MatchDefinitions.First();
            Assert.AreEqual("Test", firstMergedMatch.AssemblyName);
            Assert.AreEqual("TestClass", firstMergedMatch.ClassName);
            Assert.AreEqual(1, firstMergedMatch.Matches.Count);

            Assert.AreEqual("TestMethod1", firstMergedMatch.Matches.First().MethodName);
            Assert.AreEqual("ParamType1,ParamType2", string.Join(",", firstMergedMatch.Matches.First().ParameterTypes));
        }
Пример #7
0
        /// <summary>
        /// Produces a new Extension object that represents the union of all instrumentation
        /// targets specified in the supplied Extension objects.
        /// </summary>
        /// <param name="toMerge">The Extension objects to be merged.</param>
        /// <returns>A single Extension object that represents the combined instrumentation
        /// footprint described by all of the supplied Extension objects.</returns>
        public static Extension Merge(params Extension[] toMerge)
        {
            Extension toReturn = new Extension();

            var matchRecords = new Dictionary <DenormalisedExactMatchRecord, HashSet <ExactMethodMatcher> >();

            foreach (var factory in toMerge.SelectMany(x => x.Instrumentation.TracerFactories))
            {
                foreach (var match in factory.MatchDefinitions)
                {
                    DenormalisedExactMatchRecord matchRecord = new DenormalisedExactMatchRecord
                    {
                        Metric     = factory.Metric,
                        MetricName = factory.MetricName,
                        Name       = factory.Name,
                        TransactionNamingPriority = factory.TransactionNamingPriority,
                        AssemblyName = match.AssemblyName,
                        ClassName    = match.ClassName
                    };

                    HashSet <ExactMethodMatcher> matchers = null;

                    if (!matchRecords.TryGetValue(matchRecord, out matchers))
                    {
                        matchers = matchRecords[matchRecord] = new HashSet <ExactMethodMatcher>();
                    }

                    matchers.UnionWith(match.Matches.Select(x => new ExactMethodMatcher {
                        MethodName = x.MethodName, ParameterTypes = x.ParameterTypes
                    }));
                }
            }

            // Group the records by factory details, then by assy/classname pair
            var keysByFactoryDetails = matchRecords.Keys.GroupBy(x => new { Metric = x.Metric, MetricName = x.MetricName, Name = x.Name, TransactionNamingPriority = x.TransactionNamingPriority });

            foreach (var factoryDetail in keysByFactoryDetails)
            {
                TracerFactory toAdd = new TracerFactory(factoryDetail.Key.MetricName, factoryDetail.Key.Name, factoryDetail.Key.TransactionNamingPriority, factoryDetail.Key.Metric);

                var byClassDetail = factoryDetail.GroupBy(x => new { AssemblyName = x.AssemblyName, ClassName = x.ClassName });
                foreach (var classDetail in byClassDetail)
                {
                    Match matchToAdd = new Match(classDetail.Key.AssemblyName, classDetail.Key.ClassName);

                    var matchRecord = new DenormalisedExactMatchRecord
                    {
                        Metric     = toAdd.Metric,
                        MetricName = toAdd.MetricName,
                        Name       = toAdd.Name,
                        TransactionNamingPriority = toAdd.TransactionNamingPriority,
                        AssemblyName = matchToAdd.AssemblyName,
                        ClassName    = matchToAdd.ClassName
                    };

                    matchToAdd.Matches = matchRecords[matchRecord].OrderBy(x => x.MethodName).ThenBy(x => x.ParameterTypes).ToList();
                    toAdd.MatchDefinitions.Add(matchToAdd);
                }

                toAdd.MatchDefinitions = toAdd.MatchDefinitions.OrderBy(x => x.AssemblyName).ThenBy(x => x.ClassName).ToList();

                toReturn.Instrumentation.TracerFactories.Add(toAdd);
            }

            // Have tracer factories prefer unspecified metrics and metric names first, then others later
            toReturn.Instrumentation.TracerFactories =
                toReturn
                .Instrumentation
                .TracerFactories
                .OrderBy(x => x.Metric == Metric.Unspecified ? -1 : (int)x.Metric)
                .ThenBy(x => x.MetricName ?? string.Empty)
                .ThenBy(x => x.Name ?? string.Empty)
                .ThenBy(x => x.TransactionNamingPriority ?? string.Empty)
                .ToList();

            return(toReturn);
        }