diff --git a/.gitignore b/.gitignore index 9cd3777..5d38378 100644 --- a/.gitignore +++ b/.gitignore @@ -93,3 +93,6 @@ src/scaffolding.config .idea/ *.sln.iml src/ForIntegration/* +src/Integration/Directory.Build.props + +.learningtransport \ No newline at end of file diff --git a/GitVersion.yml b/GitVersion.yml index 613dd0e..16d2978 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,6 +1,8 @@ assembly-versioning-scheme: Major -next-version: 1.0.0 +next-version: 2.0.0 commit-message-incrementing: Disabled branches: + release: + tag: beta develop: - tag: alpha + tag: alpha \ No newline at end of file diff --git a/packaging/nuget/NServiceBus.Metrics.PerformanceCounters.nuspec b/packaging/nuget/NServiceBus.Metrics.PerformanceCounters.nuspec deleted file mode 100644 index bfc7bfb..0000000 --- a/packaging/nuget/NServiceBus.Metrics.PerformanceCounters.nuspec +++ /dev/null @@ -1,24 +0,0 @@ - - - - NServiceBus.Metrics.PerformanceCounters - NServiceBus Windows Performance Counters - $version$ - $authors$ - $owners$ - $licenseUrl$ - $projectUrl$ - $iconUrl$ - $requireLicenseAcceptance$ - Enables access to performance counters - $copyright$ - $tags$ - - - - - - - - - diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000..965a519 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,8 @@ + + + + latest + true + + + \ No newline at end of file diff --git a/src/GuardTemplates.DotSettings b/src/GuardTemplates.DotSettings deleted file mode 100644 index 4352395..0000000 --- a/src/GuardTemplates.DotSettings +++ /dev/null @@ -1,56 +0,0 @@ - - True - guard - Guards against null arguments - Guard.AgainstNull("$ARG$", $ARG$); - True - True - Guard - True - True - InCSharpStatement - 2.0 - True - complete() - 0 - True - guarde - Guards against null or empty arguments - Guard.AgainstNullAndEmpty("$ARG$", $ARG$); - True - True - Guard - True - True - InCSharpStatement - 2.0 - True - complete() - 0 - True - guardn - Guard against negative arguments - Guard.AgainstNegative("$ARG$", $ARG$); - True - True - Guard - True - True - InCSharpStatement - 2.0 - True - 0 - True - guardnz - Guards against negative and zero - Guard.AgainstNegativeAndZero("$ARG$", $ARG$); - True - True - Guard - True - True - InCSharpStatement - 2.0 - True - complete() - 0 \ No newline at end of file diff --git a/src/Integration/Integration.sln b/src/Integration/Integration.sln deleted file mode 100644 index 3a3e457..0000000 --- a/src/Integration/Integration.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26403.3 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyEndpoint", "MyEndpoint\MyEndpoint.csproj", "{C112D4A5-4A86-432F-8B5C-17B641ED6DC6}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C112D4A5-4A86-432F-8B5C-17B641ED6DC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C112D4A5-4A86-432F-8B5C-17B641ED6DC6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C112D4A5-4A86-432F-8B5C-17B641ED6DC6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C112D4A5-4A86-432F-8B5C-17B641ED6DC6}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/src/Integration/MyEndpoint/MyEndpoint.csproj b/src/Integration/MyEndpoint/MyEndpoint.csproj deleted file mode 100644 index 53a2a07..0000000 --- a/src/Integration/MyEndpoint/MyEndpoint.csproj +++ /dev/null @@ -1,64 +0,0 @@ - - - - - Debug - AnyCPU - {C112D4A5-4A86-432F-8B5C-17B641ED6DC6} - Exe - MyEndpoint - MyEndpoint - v4.5.2 - 512 - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\..\packages\NServiceBus.6.2.1\lib\net452\NServiceBus.Core.dll - - - ..\..\packages\NServiceBus.Metrics.1.0.0-alpha0065\lib\net452\NServiceBus.Metrics.dll - - - False - ..\..\ForIntegration\NServiceBus.Metrics.PerformanceCounters.dll - - - - - - - - - - - - - - - - Designer - - - - - \ No newline at end of file diff --git a/src/Integration/MyEndpoint/Program.cs b/src/Integration/MyEndpoint/Program.cs deleted file mode 100644 index 0340200..0000000 --- a/src/Integration/MyEndpoint/Program.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Threading.Tasks; -using NServiceBus; - -namespace MyEndpoint -{ - class Program - { - static void Main(string[] args) - { - AsyncMain().GetAwaiter().GetResult(); - } - - static async Task AsyncMain() - { - var configuration = new EndpointConfiguration("MyEndpoint"); - configuration.SendFailedMessagesTo("error"); - configuration.UsePersistence(); - configuration.UseTransport(); - configuration.EnableInstallers(); - var performanceCounters = configuration.EnableWindowsPerformanceCounters(); - performanceCounters.EnableSLAPerformanceCounters(TimeSpan.FromSeconds(1)); - var endpoint = await Endpoint.Start(configuration); - - ConsoleKeyInfo readKey; - do - { - await endpoint.SendLocal(new MyMessage()); - - readKey = Console.ReadKey(); - } while (readKey.Key != ConsoleKey.Escape); - - await endpoint.Stop(); - } - } - - public class MyMessage : ICommand - { - } - - public class MyHandler : IHandleMessages { - public Task Handle(MyMessage message, IMessageHandlerContext context) - { - return Task.Delay(2000); - } - } -} diff --git a/src/Integration/MyEndpoint/packages.config b/src/Integration/MyEndpoint/packages.config deleted file mode 100644 index 3894d38..0000000 --- a/src/Integration/MyEndpoint/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/APIApprovals.Approve.approved.txt b/src/NServiceBus.Metrics.PerformanceCounters.Tests/APIApprovals.Approve.approved.txt index d1f99ad..d40dc09 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/APIApprovals.Approve.approved.txt +++ b/src/NServiceBus.Metrics.PerformanceCounters.Tests/APIApprovals.Approve.approved.txt @@ -1,4 +1,6 @@ -namespace NServiceBus.Metrics.PerformanceCounters +[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute(@"NServiceBus.Metrics.PerformanceCounters.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100D32BC524DCB1205998C155A4F36BF873587D3602822ECD7B49CD775B2E6A006EE6B9164AB2E3103A6A4D1310C6E5C26818A32FE86710141A2D1F02EB564381CD64C88131BCCA478CDB5072F06DB991DE33DAC1C82BAF40D9F61DD6B40300A4673B693B51CD10A8B9B7D8AB64450431FA422514D6DABCAF70DF785B1E4E6E8AAF")] +[assembly: System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5.2", FrameworkDisplayName=".NET Framework 4.5.2")] +namespace NServiceBus.Metrics.PerformanceCounters { [System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.All)] public sealed class PerformanceCounterSettingsAttribute : System.Attribute @@ -18,6 +20,8 @@ namespace NServiceBus public class PerformanceCountersSettings { public void EnableSLAPerformanceCounters(System.TimeSpan sla) { } + [System.ObsoleteAttribute("This interval is no longer used for reporting. Counters values are updated as soo" + + "n as they are reported. Will be removed in version 3.0.0.", true)] public void UpdateCounterEvery(System.TimeSpan updateInterval) { } } } \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/APIApprovals.cs b/src/NServiceBus.Metrics.PerformanceCounters.Tests/APIApprovals.cs index 9ce4329..8ad00a7 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/APIApprovals.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters.Tests/APIApprovals.cs @@ -22,10 +22,12 @@ public void Approve() string Filter(string text) { - return string.Join(Environment.NewLine, text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) - .Where(l => !l.StartsWith("[assembly: ")) + return string.Join(Environment.NewLine, text.Split(new[] + { + Environment.NewLine + }, StringSplitOptions.RemoveEmptyEntries) + .Where(l => !l.StartsWith("[assembly: ReleaseDateAttribute(")) .Where(l => !string.IsNullOrWhiteSpace(l)) - ); + ); } - } \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/App_Packages/PublicApiGenerator.6.0.0/ApiGenerator.cs b/src/NServiceBus.Metrics.PerformanceCounters.Tests/App_Packages/PublicApiGenerator.6.0.0/ApiGenerator.cs deleted file mode 100644 index af61e83..0000000 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/App_Packages/PublicApiGenerator.6.0.0/ApiGenerator.cs +++ /dev/null @@ -1,796 +0,0 @@ -using System; -using System.CodeDom; -using System.CodeDom.Compiler; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using Microsoft.CSharp; -using Mono.Cecil; -using Mono.Cecil.Rocks; -using ICustomAttributeProvider = Mono.Cecil.ICustomAttributeProvider; -using TypeAttributes = System.Reflection.TypeAttributes; -using System.Globalization; - -// ReSharper disable BitwiseOperatorOnEnumWithoutFlags -namespace PublicApiGenerator -{ - public static class ApiGenerator - { - public static string GeneratePublicApi(Assembly assemby, Type[] includeTypes = null, bool shouldIncludeAssemblyAttributes = true) - { - var assemblyResolver = new DefaultAssemblyResolver(); - var assemblyPath = assemby.Location; - assemblyResolver.AddSearchDirectory(Path.GetDirectoryName(assemblyPath)); - - var readSymbols = File.Exists(Path.ChangeExtension(assemblyPath, ".pdb")); - var asm = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters(ReadingMode.Deferred) - { - ReadSymbols = readSymbols, - AssemblyResolver = assemblyResolver, - }); - - return CreatePublicApiForAssembly(asm, tr => includeTypes == null || includeTypes.Any(t => t.FullName == tr.FullName && t.Assembly.FullName == tr.Module.Assembly.FullName), shouldIncludeAssemblyAttributes); - } - - // TODO: Assembly references? - // TODO: Better handle namespaces - using statements? - requires non-qualified type names - static string CreatePublicApiForAssembly(AssemblyDefinition assembly, Func shouldIncludeType, bool shouldIncludeAssemblyAttributes) - { - var publicApiBuilder = new StringBuilder(); - var cgo = new CodeGeneratorOptions - { - BracingStyle = "C", - BlankLinesBetweenMembers = false, - VerbatimOrder = false - }; - - using (var provider = new CSharpCodeProvider()) - { - var compileUnit = new CodeCompileUnit(); - if (shouldIncludeAssemblyAttributes && assembly.HasCustomAttributes) - { - PopulateCustomAttributes(assembly, compileUnit.AssemblyCustomAttributes); - } - - var publicTypes = assembly.Modules.SelectMany(m => m.GetTypes()) - .Where(t => !t.IsNested && ShouldIncludeType(t) && shouldIncludeType(t)) - .OrderBy(t => t.FullName); - foreach (var publicType in publicTypes) - { - var @namespace = compileUnit.Namespaces.Cast() - .FirstOrDefault(n => n.Name == publicType.Namespace); - if (@namespace == null) - { - @namespace = new CodeNamespace(publicType.Namespace); - compileUnit.Namespaces.Add(@namespace); - } - - var typeDeclaration = CreateTypeDeclaration(publicType); - @namespace.Types.Add(typeDeclaration); - } - - using (var writer = new StringWriter()) - { - provider.GenerateCodeFromCompileUnit(compileUnit, writer, cgo); - var typeDeclarationText = NormaliseGeneratedCode(writer); - publicApiBuilder.AppendLine(typeDeclarationText); - } - } - return NormaliseLineEndings(publicApiBuilder.ToString().Trim()); - } - - static string NormaliseLineEndings(string value) - { - return Regex.Replace(value, @"\r\n|\n\r|\r|\n", Environment.NewLine); - } - - static bool IsDelegate(TypeDefinition publicType) - { - return publicType.BaseType != null && publicType.BaseType.FullName == "System.MulticastDelegate"; - } - - static bool ShouldIncludeType(TypeDefinition t) - { - return (t.IsPublic || t.IsNestedPublic || t.IsNestedFamily) && !IsCompilerGenerated(t); - } - - static bool ShouldIncludeMember(IMemberDefinition m) - { - return !IsCompilerGenerated(m) && !IsDotNetTypeMember(m) && !(m is FieldDefinition); - } - - static bool IsCompilerGenerated(IMemberDefinition m) - { - return m.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.CompilerGeneratedAttribute"); - } - - static bool IsDotNetTypeMember(IMemberDefinition m) - { - if (m.DeclaringType == null || m.DeclaringType.FullName == null) - return false; - return m.DeclaringType.FullName.StartsWith("System") || m.DeclaringType.FullName.StartsWith("Microsoft"); - } - - static void AddMemberToTypeDeclaration(CodeTypeDeclaration typeDeclaration, IMemberDefinition memberInfo) - { - var methodDefinition = memberInfo as MethodDefinition; - if (methodDefinition != null) - { - if (methodDefinition.IsConstructor) - AddCtorToTypeDeclaration(typeDeclaration, methodDefinition); - else - AddMethodToTypeDeclaration(typeDeclaration, methodDefinition); - } - else if (memberInfo is PropertyDefinition) - { - AddPropertyToTypeDeclaration(typeDeclaration, (PropertyDefinition) memberInfo); - } - else if (memberInfo is EventDefinition) - { - typeDeclaration.Members.Add(GenerateEvent((EventDefinition)memberInfo)); - } - else if (memberInfo is FieldDefinition) - { - AddFieldToTypeDeclaration(typeDeclaration, (FieldDefinition) memberInfo); - } - } - - static string NormaliseGeneratedCode(StringWriter writer) - { - var gennedClass = writer.ToString(); - const string autoGeneratedHeader = @"^//-+\s*$.*^//-+\s*$"; - const string emptyGetSet = @"\s+{\s+get\s+{\s+}\s+set\s+{\s+}\s+}"; - const string emptyGet = @"\s+{\s+get\s+{\s+}\s+}"; - const string emptySet = @"\s+{\s+set\s+{\s+}\s+}"; - const string getSet = @"\s+{\s+get;\s+set;\s+}"; - const string get = @"\s+{\s+get;\s+}"; - const string set = @"\s+{\s+set;\s+}"; - gennedClass = Regex.Replace(gennedClass, autoGeneratedHeader, string.Empty, - RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline | RegexOptions.Singleline); - gennedClass = Regex.Replace(gennedClass, emptyGetSet, " { get; set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, getSet, " { get; set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, emptyGet, " { get; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, emptySet, " { set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, get, " { get; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, set, " { set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, @"\s+{\s+}", " { }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, @"\)\s+;", ");", RegexOptions.IgnorePatternWhitespace); - return gennedClass; - } - - static CodeTypeDeclaration CreateTypeDeclaration(TypeDefinition publicType) - { - if (IsDelegate(publicType)) - return CreateDelegateDeclaration(publicType); - - bool @static = false; - TypeAttributes attributes = 0; - if (publicType.IsPublic || publicType.IsNestedPublic) - attributes |= TypeAttributes.Public; - if (publicType.IsNestedFamily) - attributes |= TypeAttributes.NestedFamily; - if (publicType.IsSealed && !publicType.IsAbstract) - attributes |= TypeAttributes.Sealed; - else if (!publicType.IsSealed && publicType.IsAbstract && !publicType.IsInterface) - attributes |= TypeAttributes.Abstract; - else if (publicType.IsSealed && publicType.IsAbstract) - @static = true; - - // Static support is a hack. CodeDOM does support it, and this isn't - // correct C#, but it's good enough for our API outline - var name = publicType.Name; - - var index = name.IndexOf('`'); - if (index != -1) - name = name.Substring(0, index); - var declaration = new CodeTypeDeclaration(@static ? "static " + name : name) - { - CustomAttributes = CreateCustomAttributes(publicType), - // TypeAttributes must be specified before the IsXXX as they manipulate TypeAttributes! - TypeAttributes = attributes, - IsClass = publicType.IsClass, - IsEnum = publicType.IsEnum, - IsInterface = publicType.IsInterface, - IsStruct = publicType.IsValueType && !publicType.IsPrimitive && !publicType.IsEnum, - }; - - if (declaration.IsInterface && publicType.BaseType != null) - throw new NotImplementedException("Base types for interfaces needs testing"); - - PopulateGenericParameters(publicType, declaration.TypeParameters); - - if (publicType.BaseType != null && ShouldOutputBaseType(publicType)) - { - if (publicType.BaseType.FullName == "System.Enum") - { - var underlyingType = publicType.GetEnumUnderlyingType(); - if (underlyingType.FullName != "System.Int32") - declaration.BaseTypes.Add(CreateCodeTypeReference(underlyingType)); - } - else - declaration.BaseTypes.Add(CreateCodeTypeReference(publicType.BaseType)); - } - foreach(var @interface in publicType.Interfaces.OrderBy(i => i.FullName) - .Select(t => new { Reference = t, Definition = t.Resolve() }) - .Where(t => ShouldIncludeType(t.Definition)) - .Select(t => t.Reference)) - declaration.BaseTypes.Add(CreateCodeTypeReference(@interface)); - - foreach (var memberInfo in publicType.GetMembers().Where(ShouldIncludeMember).OrderBy(m => m.Name)) - AddMemberToTypeDeclaration(declaration, memberInfo); - - // Fields should be in defined order for an enum - var fields = !publicType.IsEnum - ? publicType.Fields.OrderBy(f => f.Name) - : (IEnumerable)publicType.Fields; - foreach (var field in fields) - AddMemberToTypeDeclaration(declaration, field); - - foreach (var nestedType in publicType.NestedTypes.Where(ShouldIncludeType).OrderBy(t => t.FullName)) - { - var nestedTypeDeclaration = CreateTypeDeclaration(nestedType); - declaration.Members.Add(nestedTypeDeclaration); - } - - return declaration; - } - - static CodeTypeDeclaration CreateDelegateDeclaration(TypeDefinition publicType) - { - var invokeMethod = publicType.Methods.Single(m => m.Name == "Invoke"); - var name = publicType.Name; - var index = name.IndexOf('`'); - if (index != -1) - name = name.Substring(0, index); - var declaration = new CodeTypeDelegate(name) - { - Attributes = MemberAttributes.Public, - CustomAttributes = CreateCustomAttributes(publicType), - ReturnType = CreateCodeTypeReference(invokeMethod.ReturnType), - }; - - // CodeDOM. No support. Return type attributes. - PopulateCustomAttributes(invokeMethod.MethodReturnType, declaration.CustomAttributes, type => ModifyCodeTypeReference(type, "return:")); - PopulateGenericParameters(publicType, declaration.TypeParameters); - PopulateMethodParameters(invokeMethod, declaration.Parameters); - - // Of course, CodeDOM doesn't support generic type parameters for delegates. Of course. - if (declaration.TypeParameters.Count > 0) - { - var parameterNames = from parameterType in declaration.TypeParameters.Cast() - select parameterType.Name; - declaration.Name = string.Format(CultureInfo.InvariantCulture, "{0}<{1}>", declaration.Name, string.Join(", ", parameterNames)); - } - - return declaration; - } - - static bool ShouldOutputBaseType(TypeDefinition publicType) - { - return publicType.BaseType.FullName != "System.Object" && publicType.BaseType.FullName != "System.ValueType"; - } - - static void PopulateGenericParameters(IGenericParameterProvider publicType, CodeTypeParameterCollection parameters) - { - foreach (var parameter in publicType.GenericParameters) - { - if (parameter.HasCustomAttributes) - throw new NotImplementedException("Attributes on type parameters is not supported. And weird"); - - // A little hacky. Means we get "in" and "out" prefixed on any constraints, but it's either that - // or add it as a custom attribute, which looks even weirder - var name = parameter.Name; - if (parameter.IsCovariant) - name = "out " + name; - if (parameter.IsContravariant) - name = "in " + name; - - var typeParameter = new CodeTypeParameter(name) - { - HasConstructorConstraint = - parameter.HasDefaultConstructorConstraint && !parameter.HasNotNullableValueTypeConstraint - }; - if (parameter.HasNotNullableValueTypeConstraint) - typeParameter.Constraints.Add(" struct"); // Extra space is a hack! - if (parameter.HasReferenceTypeConstraint) - typeParameter.Constraints.Add(" class"); - foreach (var constraint in parameter.Constraints.Where(t => t.FullName != "System.ValueType")) - { - typeParameter.Constraints.Add(CreateCodeTypeReference(constraint.GetElementType())); - } - parameters.Add(typeParameter); - } - } - - static CodeAttributeDeclarationCollection CreateCustomAttributes(ICustomAttributeProvider type) - { - var attributes = new CodeAttributeDeclarationCollection(); - PopulateCustomAttributes(type, attributes); - return attributes; - } - - static void PopulateCustomAttributes(ICustomAttributeProvider type, - CodeAttributeDeclarationCollection attributes) - { - PopulateCustomAttributes(type, attributes, ctr => ctr); - } - - static void PopulateCustomAttributes(ICustomAttributeProvider type, - CodeAttributeDeclarationCollection attributes, Func codeTypeModifier) - { - foreach (var customAttribute in type.CustomAttributes.Where(ShouldIncludeAttribute).OrderBy(a => a.AttributeType.FullName).ThenBy(a => ConvertAttrbuteToCode(codeTypeModifier, a))) - { - var attribute = GenerateCodeAttributeDeclaration(codeTypeModifier, customAttribute); - attributes.Add(attribute); - } - } - - static CodeAttributeDeclaration GenerateCodeAttributeDeclaration(Func codeTypeModifier, CustomAttribute customAttribute) - { - var attribute = new CodeAttributeDeclaration(codeTypeModifier(CreateCodeTypeReference(customAttribute.AttributeType))); - foreach (var arg in customAttribute.ConstructorArguments) - { - attribute.Arguments.Add(new CodeAttributeArgument(CreateInitialiserExpression(arg))); - } - foreach (var field in customAttribute.Fields.OrderBy(f => f.Name)) - { - attribute.Arguments.Add(new CodeAttributeArgument(field.Name, CreateInitialiserExpression(field.Argument))); - } - foreach (var property in customAttribute.Properties.OrderBy(p => p.Name)) - { - attribute.Arguments.Add(new CodeAttributeArgument(property.Name, CreateInitialiserExpression(property.Argument))); - } - return attribute; - } - - // Litee: This method is used for additional sorting of custom attributes when multiple values are allowed - static object ConvertAttrbuteToCode(Func codeTypeModifier, CustomAttribute customAttribute) - { - using (var provider = new CSharpCodeProvider()) - { - var cgo = new CodeGeneratorOptions - { - BracingStyle = "C", - BlankLinesBetweenMembers = false, - VerbatimOrder = false - }; - var attribute = GenerateCodeAttributeDeclaration(codeTypeModifier, customAttribute); - var declaration = new CodeTypeDeclaration("DummyClass") - { - CustomAttributes = new CodeAttributeDeclarationCollection(new[] { attribute }), - }; - using (var writer = new StringWriter()) - { - provider.GenerateCodeFromType(declaration, writer, cgo); - return writer.ToString(); - } - } - } - - static readonly HashSet SkipAttributeNames = new HashSet - { - "System.CodeDom.Compiler.GeneratedCodeAttribute", - "System.ComponentModel.EditorBrowsableAttribute", - "System.Runtime.CompilerServices.AsyncStateMachineAttribute", - "System.Runtime.CompilerServices.CompilerGeneratedAttribute", - "System.Runtime.CompilerServices.CompilationRelaxationsAttribute", - "System.Runtime.CompilerServices.ExtensionAttribute", - "System.Runtime.CompilerServices.RuntimeCompatibilityAttribute", - "System.Reflection.DefaultMemberAttribute", - "System.Diagnostics.DebuggableAttribute", - "System.Diagnostics.DebuggerNonUserCodeAttribute", - "System.Diagnostics.DebuggerStepThroughAttribute", - "System.Reflection.AssemblyCompanyAttribute", - "System.Reflection.AssemblyConfigurationAttribute", - "System.Reflection.AssemblyCopyrightAttribute", - "System.Reflection.AssemblyDescriptionAttribute", - "System.Reflection.AssemblyFileVersionAttribute", - "System.Reflection.AssemblyInformationalVersionAttribute", - "System.Reflection.AssemblyProductAttribute", - "System.Reflection.AssemblyTitleAttribute", - "System.Reflection.AssemblyTrademarkAttribute" - }; - - static bool ShouldIncludeAttribute(CustomAttribute attribute) - { - var attributeTypeDefinition = attribute.AttributeType.Resolve(); - return !SkipAttributeNames.Contains(attribute.AttributeType.FullName) && attributeTypeDefinition.IsPublic; - } - - static CodeExpression CreateInitialiserExpression(CustomAttributeArgument attributeArgument) - { - if (attributeArgument.Value is CustomAttributeArgument) - { - return CreateInitialiserExpression((CustomAttributeArgument) attributeArgument.Value); - } - - if (attributeArgument.Value is CustomAttributeArgument[]) - { - var initialisers = from argument in (CustomAttributeArgument[]) attributeArgument.Value - select CreateInitialiserExpression(argument); - return new CodeArrayCreateExpression(CreateCodeTypeReference(attributeArgument.Type), initialisers.ToArray()); - } - - var type = attributeArgument.Type.Resolve(); - var value = attributeArgument.Value; - if (type.BaseType != null && type.BaseType.FullName == "System.Enum") - { - var originalValue = Convert.ToInt64(value); - if (type.CustomAttributes.Any(a => a.AttributeType.FullName == "System.FlagsAttribute")) - { - //var allFlags = from f in type.Fields - // where f.Constant != null - // let v = Convert.ToInt64(f.Constant) - // where v == 0 || (originalValue & v) != 0 - // select (CodeExpression)new CodeFieldReferenceExpression(typeExpression, f.Name); - //return allFlags.Aggregate((current, next) => new CodeBinaryOperatorExpression(current, CodeBinaryOperatorType.BitwiseOr, next)); - - // I'd rather use the above, as it's just using the CodeDOM, but it puts - // brackets around each CodeBinaryOperatorExpression - var flags = from f in type.Fields - where f.Constant != null - let v = Convert.ToInt64(f.Constant) - where v == 0 || (originalValue & v) != 0 - select type.FullName + "." + f.Name; - return new CodeSnippetExpression(flags.Aggregate((current, next) => current + " | " + next)); - } - - var allFlags = from f in type.Fields - where f.Constant != null - let v = Convert.ToInt64(f.Constant) - where v == originalValue - select new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(CreateCodeTypeReference(type)), f.Name); - return allFlags.FirstOrDefault(); - } - - if (type.FullName == "System.Type" && value is TypeReference) - { - return new CodeTypeOfExpression(CreateCodeTypeReference((TypeReference)value)); - } - - if (value is string) - { - // CodeDOM outputs a verbatim string. Any string with \n is treated as such, so normalise - // it to make it easier for comparisons - value = Regex.Replace((string)value, @"\n", "\\n"); - value = Regex.Replace((string)value, @"\r\n|\r\\n", "\\r\\n"); - } - - return new CodePrimitiveExpression(value); - } - - static void AddCtorToTypeDeclaration(CodeTypeDeclaration typeDeclaration, MethodDefinition member) - { - if (member.IsAssembly || member.IsPrivate) - return; - - var method = new CodeConstructor - { - CustomAttributes = CreateCustomAttributes(member), - Name = member.Name, - Attributes = GetMethodAttributes(member) - }; - PopulateMethodParameters(member, method.Parameters); - - typeDeclaration.Members.Add(method); - } - - static void AddMethodToTypeDeclaration(CodeTypeDeclaration typeDeclaration, MethodDefinition member) - { - if (member.IsAssembly || member.IsPrivate || member.IsSpecialName) - return; - - var returnType = CreateCodeTypeReference(member.ReturnType); - - var method = new CodeMemberMethod - { - Name = member.Name, - Attributes = GetMethodAttributes(member), - CustomAttributes = CreateCustomAttributes(member), - ReturnType = returnType, - }; - PopulateCustomAttributes(member.MethodReturnType, method.ReturnTypeCustomAttributes); - PopulateGenericParameters(member, method.TypeParameters); - PopulateMethodParameters(member, method.Parameters, IsExtensionMethod(member)); - - typeDeclaration.Members.Add(method); - } - - static bool IsExtensionMethod(ICustomAttributeProvider method) - { - return method.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute"); - } - - static void PopulateMethodParameters(IMethodSignature member, - CodeParameterDeclarationExpressionCollection parameters, bool isExtension = false) - { - foreach (var parameter in member.Parameters) - { - FieldDirection direction = 0; - if (parameter.IsOut) - direction |= FieldDirection.Out; - else if (parameter.ParameterType.IsByReference) - direction |= FieldDirection.Ref; - - var parameterType = parameter.ParameterType.IsByReference - ? parameter.ParameterType.GetElementType() - : parameter.ParameterType; - - var type = CreateCodeTypeReference(parameterType); - - if (isExtension) - { - type = ModifyCodeTypeReference(type, "this"); - isExtension = false; - } - - var name = parameter.HasConstant - ? string.Format(CultureInfo.InvariantCulture, "{0} = {1}", parameter.Name, FormatParameterConstant(parameter)) - : parameter.Name; - var expression = new CodeParameterDeclarationExpression(type, name) - { - Direction = direction, - CustomAttributes = CreateCustomAttributes(parameter) - }; - parameters.Add(expression); - } - } - - static object FormatParameterConstant(IConstantProvider parameter) - { - return parameter.Constant is string ? string.Format(CultureInfo.InvariantCulture, "\"{0}\"", parameter.Constant) : (parameter.Constant ?? "null"); - } - - static MemberAttributes GetMethodAttributes(MethodDefinition method) - { - MemberAttributes access = 0; - if (method.IsFamily) - access = MemberAttributes.Family; - if (method.IsPublic) - access = MemberAttributes.Public; - if (method.IsAssembly) - access = MemberAttributes.Assembly; - if (method.IsFamilyAndAssembly) - access = MemberAttributes.FamilyAndAssembly; - if (method.IsFamilyOrAssembly) - access = MemberAttributes.FamilyOrAssembly; - - MemberAttributes scope = 0; - if (method.IsStatic) - scope |= MemberAttributes.Static; - if (method.IsFinal || !method.IsVirtual) - scope |= MemberAttributes.Final; - if (method.IsAbstract) - scope |= MemberAttributes.Abstract; - if (method.IsVirtual && !method.IsNewSlot) - scope |= MemberAttributes.Override; - - MemberAttributes vtable = 0; - if (IsHidingMethod(method)) - vtable = MemberAttributes.New; - - return access | scope | vtable; - } - - static bool IsHidingMethod(MethodDefinition method) - { - var typeDefinition = method.DeclaringType; - - // If we're an interface, just try and find any method with the same signature - // in any of the interfaces that we implement - if (typeDefinition.IsInterface) - { - var interfaceMethods = from @interfaceReference in typeDefinition.Interfaces - let interfaceDefinition = @interfaceReference.Resolve() - where interfaceDefinition != null - select interfaceDefinition.Methods; - - return interfaceMethods.Any(ms => MetadataResolver.GetMethod(ms, method) != null); - } - - // If we're not an interface, find a base method that isn't virtual - return !method.IsVirtual && GetBaseTypes(typeDefinition).Any(d => MetadataResolver.GetMethod(d.Methods, method) != null); - } - - static IEnumerable GetBaseTypes(TypeDefinition type) - { - var baseType = type.BaseType; - while (baseType != null) - { - var definition = baseType.Resolve(); - if (definition == null) - yield break; - yield return definition; - - baseType = baseType.DeclaringType; - } - } - - static void AddPropertyToTypeDeclaration(CodeTypeDeclaration typeDeclaration, PropertyDefinition member) - { - var getterAttributes = member.GetMethod != null ? GetMethodAttributes(member.GetMethod) : 0; - var setterAttributes = member.SetMethod != null ? GetMethodAttributes(member.SetMethod) : 0; - - if (!HasVisiblePropertyMethod(getterAttributes) && !HasVisiblePropertyMethod(setterAttributes)) - return; - - var propertyAttributes = GetPropertyAttributes(getterAttributes, setterAttributes); - - var propertyType = member.PropertyType.IsGenericParameter - ? new CodeTypeReference(member.PropertyType.Name) - : CreateCodeTypeReference(member.PropertyType); - - var property = new CodeMemberProperty - { - Name = member.Name, - Type = propertyType, - Attributes = propertyAttributes, - CustomAttributes = CreateCustomAttributes(member), - HasGet = member.GetMethod != null && HasVisiblePropertyMethod(getterAttributes), - HasSet = member.SetMethod != null && HasVisiblePropertyMethod(setterAttributes) - }; - - // Here's a nice hack, because hey, guess what, the CodeDOM doesn't support - // attributes on getters or setters - if (member.GetMethod != null && member.GetMethod.HasCustomAttributes) - { - PopulateCustomAttributes(member.GetMethod, property.CustomAttributes, type => ModifyCodeTypeReference(type, "get:")); - } - if (member.SetMethod != null && member.SetMethod.HasCustomAttributes) - { - PopulateCustomAttributes(member.SetMethod, property.CustomAttributes, type => ModifyCodeTypeReference(type, "set:")); - } - - foreach (var parameter in member.Parameters) - { - property.Parameters.Add( - new CodeParameterDeclarationExpression(CreateCodeTypeReference(parameter.ParameterType), - parameter.Name)); - } - - // TODO: CodeDOM has no support for different access modifiers for getters and setters - // TODO: CodeDOM has no support for attributes on setters or getters - promote to property? - - typeDeclaration.Members.Add(property); - } - - static MemberAttributes GetPropertyAttributes(MemberAttributes getterAttributes, MemberAttributes setterAttributes) - { - MemberAttributes access = 0; - var getterAccess = getterAttributes & MemberAttributes.AccessMask; - var setterAccess = setterAttributes & MemberAttributes.AccessMask; - if (getterAccess == MemberAttributes.Public || setterAccess == MemberAttributes.Public) - access = MemberAttributes.Public; - else if (getterAccess == MemberAttributes.Family || setterAccess == MemberAttributes.Family) - access = MemberAttributes.Family; - else if (getterAccess == MemberAttributes.FamilyAndAssembly || setterAccess == MemberAttributes.FamilyAndAssembly) - access = MemberAttributes.FamilyAndAssembly; - else if (getterAccess == MemberAttributes.FamilyOrAssembly || setterAccess == MemberAttributes.FamilyOrAssembly) - access = MemberAttributes.FamilyOrAssembly; - else if (getterAccess == MemberAttributes.Assembly || setterAccess == MemberAttributes.Assembly) - access = MemberAttributes.Assembly; - else if (getterAccess == MemberAttributes.Private || setterAccess == MemberAttributes.Private) - access = MemberAttributes.Private; - - // Scope should be the same for getter and setter. If one isn't specified, it'll be 0 - var getterScope = getterAttributes & MemberAttributes.ScopeMask; - var setterScope = setterAttributes & MemberAttributes.ScopeMask; - var scope = (MemberAttributes) Math.Max((int) getterScope, (int) setterScope); - - // Vtable should be the same for getter and setter. If one isn't specified, it'll be 0 - var getterVtable = getterAttributes & MemberAttributes.VTableMask; - var setterVtable = setterAttributes & MemberAttributes.VTableMask; - var vtable = (MemberAttributes) Math.Max((int) getterVtable, (int) setterVtable); - - return access | scope | vtable; - } - - static bool HasVisiblePropertyMethod(MemberAttributes attributes) - { - var access = attributes & MemberAttributes.AccessMask; - return access == MemberAttributes.Public || access == MemberAttributes.Family || - access == MemberAttributes.FamilyOrAssembly; - } - - static CodeTypeMember GenerateEvent(EventDefinition eventDefinition) - { - var @event = new CodeMemberEvent - { - Name = eventDefinition.Name, - Attributes = MemberAttributes.Public | MemberAttributes.Final, - CustomAttributes = CreateCustomAttributes(eventDefinition), - Type = CreateCodeTypeReference(eventDefinition.EventType) - }; - - return @event; - } - - static void AddFieldToTypeDeclaration(CodeTypeDeclaration typeDeclaration, FieldDefinition memberInfo) - { - if (memberInfo.IsPrivate || memberInfo.IsAssembly || memberInfo.IsSpecialName) - return; - - MemberAttributes attributes = 0; - if (memberInfo.HasConstant) - attributes |= MemberAttributes.Const; - if (memberInfo.IsFamily) - attributes |= MemberAttributes.Family; - if (memberInfo.IsPublic) - attributes |= MemberAttributes.Public; - if (memberInfo.IsStatic && !memberInfo.HasConstant) - attributes |= MemberAttributes.Static; - - // TODO: Values for readonly fields are set in the ctor - var codeTypeReference = CreateCodeTypeReference(memberInfo.FieldType); - if (memberInfo.IsInitOnly) - codeTypeReference = MakeReadonly(codeTypeReference); - var field = new CodeMemberField(codeTypeReference, memberInfo.Name) - { - Attributes = attributes, - CustomAttributes = CreateCustomAttributes(memberInfo) - }; - - if (memberInfo.HasConstant) - field.InitExpression = new CodePrimitiveExpression(memberInfo.Constant); - - typeDeclaration.Members.Add(field); - } - - static CodeTypeReference MakeReadonly(CodeTypeReference typeReference) - { - return ModifyCodeTypeReference(typeReference, "readonly"); - } - - static CodeTypeReference ModifyCodeTypeReference(CodeTypeReference typeReference, string modifier) - { - using (var provider = new CSharpCodeProvider()) - return new CodeTypeReference(modifier + " " + provider.GetTypeOutput(typeReference)); - } - - static CodeTypeReference CreateCodeTypeReference(TypeReference type) - { - var typeName = GetTypeName(type); - return new CodeTypeReference(typeName, CreateGenericArguments(type)); - } - - static string GetTypeName(TypeReference type) - { - if (type.IsGenericParameter) - return type.Name; - - if (!type.IsNested) - { - return (!string.IsNullOrEmpty(type.Namespace) ? (type.Namespace + ".") : "") + type.Name; - } - - return GetTypeName(type.DeclaringType) + "." + type.Name; - } - - static CodeTypeReference[] CreateGenericArguments(TypeReference type) - { - var genericInstance = type as IGenericInstance; - if (genericInstance == null) return null; - - var genericArguments = new List(); - foreach (var argument in genericInstance.GenericArguments) - { - genericArguments.Add(CreateCodeTypeReference(argument)); - } - return genericArguments.ToArray(); - } - } - - static class CecilEx - { - public static IEnumerable GetMembers(this TypeDefinition type) - { - return type.Fields.Cast() - .Concat(type.Methods) - .Concat(type.Properties) - .Concat(type.Events); - } - } -} diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/EndpointConfigBuilder.cs b/src/NServiceBus.Metrics.PerformanceCounters.Tests/EndpointConfigBuilder.cs index 848a5d7..0062194 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/EndpointConfigBuilder.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters.Tests/EndpointConfigBuilder.cs @@ -5,9 +5,10 @@ static class EndpointConfigBuilder public static EndpointConfiguration BuildEndpoint(string s) { var endpointConfiguration = new EndpointConfiguration(s); + endpointConfiguration.UseTransport(); endpointConfiguration.SendFailedMessagesTo("error"); endpointConfiguration.EnableInstallers(); - endpointConfiguration.UseSerialization(); + //endpointConfiguration.UseSerialization(); endpointConfiguration.UsePersistence(); var recoverability = endpointConfiguration.Recoverability(); recoverability.Immediate(c => c.NumberOfRetries(0)); diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/EstimatedTimeToSLABreachCounterTests.cs b/src/NServiceBus.Metrics.PerformanceCounters.Tests/EstimatedTimeToSLABreachCounterTests.cs index 5715f9b..be3ff37 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/EstimatedTimeToSLABreachCounterTests.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters.Tests/EstimatedTimeToSLABreachCounterTests.cs @@ -5,7 +5,7 @@ public class EstimatedTimeToSLABreachCounterTests { [Test] - public void Single_Datapoint_should_result_in_MaxValue() + public void Single_DataPoint_should_result_in_MaxValue() { var mockPerformanceCounter = new MockIPerformanceCounter(); var counter = new EstimatedTimeToSLABreachCounter(TimeSpan.FromSeconds(2), mockPerformanceCounter); diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/IntegrationTests.cs b/src/NServiceBus.Metrics.PerformanceCounters.Tests/IntegrationTests.cs index a096475..a06d254 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/IntegrationTests.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters.Tests/IntegrationTests.cs @@ -8,6 +8,7 @@ [TestFixture] public class IntegrationTests { + const string EndpointName = "PerfCountersIntegrationTests"; static ManualResetEvent ManualResetEvent = new ManualResetEvent(false); [Test] @@ -15,8 +16,7 @@ public async Task Ensure_counters_are_written() { string message = null; - var endpointName = "PerfCountersIntegrationTests"; - var endpointConfiguration = EndpointConfigBuilder.BuildEndpoint(endpointName); + var endpointConfiguration = EndpointConfigBuilder.BuildEndpoint(EndpointName); endpointConfiguration.DefineCriticalErrorAction( context => { @@ -27,11 +27,21 @@ public async Task Ensure_counters_are_written() var performanceCounters = endpointConfiguration.EnableWindowsPerformanceCounters(); performanceCounters.EnableSLAPerformanceCounters(TimeSpan.FromSeconds(10)); - performanceCounters.UpdateCounterEvery(TimeSpan.FromSeconds(1)); var endpoint = await Endpoint.Start(endpointConfiguration) .ConfigureAwait(false); - + + var criticalTime = GetCounter(PerformanceCountersFeature.CriticalTimeCounterName); + var processingTime = GetCounter(PerformanceCountersFeature.ProcessingTimeCounterName); + + Assert.AreEqual(0, criticalTime.RawValue); + Assert.AreEqual(0, processingTime.RawValue); + + var cancellation = new CancellationTokenSource(); + + var criticalTimeReading = ReadNonZero(criticalTime, cancellation); + var processingTimeReading = ReadNonZero(processingTime, cancellation); + await endpoint.SendLocal(new MyMessage()) .ConfigureAwait(false); @@ -41,14 +51,13 @@ await Task.Delay(1500) await endpoint.Stop() .ConfigureAwait(false); - var criticalTimePerfCounter = new PerformanceCounter("NServiceBus", PerformanceCountersFeature.CriticalTimeCounterName, endpointName, true); - //var processingTimePerfCounter = new PerformanceCounter("NServiceBus", PerformanceCountersFeature.ProcessingTimeCounterName, endpointName, true); - var slaPerCounter = new PerformanceCounter("NServiceBus", SLAMonitoringFeature.CounterName, endpointName, true); - var messagesFailuresPerSecondCounter = new PerformanceCounter("NServiceBus", PerformanceCountersFeature.MessagesFailuresPerSecondCounterName, endpointName, true); - var messagesProcessedPerSecondCounter = new PerformanceCounter("NServiceBus", PerformanceCountersFeature.MessagesProcessedPerSecondCounterName, endpointName, true); - var messagesPulledPerSecondCounter = new PerformanceCounter("NServiceBus", PerformanceCountersFeature.MessagesPulledPerSecondCounterName, endpointName, true); - Assert.AreNotEqual(0, criticalTimePerfCounter.RawValue); - //Assert.AreNotEqual(0, processingTimePerfCounter.RawValue); + cancellation.Cancel(); + var slaPerCounter = GetCounter(SLAMonitoringFeature.CounterName); + var messagesFailuresPerSecondCounter = GetCounter(PerformanceCountersFeature.MessagesFailuresPerSecondCounterName); + var messagesProcessedPerSecondCounter = GetCounter(PerformanceCountersFeature.MessagesProcessedPerSecondCounterName); + var messagesPulledPerSecondCounter = GetCounter(PerformanceCountersFeature.MessagesPulledPerSecondCounterName); + Assert.True(await criticalTimeReading); + Assert.True(await processingTimeReading); Assert.AreNotEqual(0, slaPerCounter.RawValue); Assert.AreEqual(0, messagesFailuresPerSecondCounter.RawValue); Assert.AreNotEqual(0, messagesProcessedPerSecondCounter.RawValue); @@ -57,12 +66,29 @@ await endpoint.Stop() Assert.IsNull(message); } + static async Task ReadNonZero(PerformanceCounter counter, CancellationTokenSource cancellation) + { + while (counter.RawValue == 0) + { + if (cancellation.IsCancellationRequested) + { + return false; + } + + await Task.Delay(TimeSpan.FromMilliseconds(10)); + } + + return true; + } + + static PerformanceCounter GetCounter(string counterName) => new PerformanceCounter("NServiceBus", counterName, EndpointName, true); + public class MyHandler : IHandleMessages { public Task Handle(MyMessage message, IMessageHandlerContext context) { ManualResetEvent.Set(); - return Task.Delay(TimeSpan.FromMilliseconds(100)); + return Task.Delay(TimeSpan.FromMilliseconds(1000)); } } public class MyMessage : ICommand diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/MockIPerformanceCounter.cs b/src/NServiceBus.Metrics.PerformanceCounters.Tests/MockIPerformanceCounter.cs index 5885842..e7068e7 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/MockIPerformanceCounter.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters.Tests/MockIPerformanceCounter.cs @@ -12,5 +12,10 @@ public void Increment() RawValue++; } + public void IncrementBy(long value) + { + RawValue += value; + } + public long RawValue { get; set; } } \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/NServiceBus.Metrics.PerformanceCounters.Tests.csproj b/src/NServiceBus.Metrics.PerformanceCounters.Tests/NServiceBus.Metrics.PerformanceCounters.Tests.csproj index 7719bf9..c026f82 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/NServiceBus.Metrics.PerformanceCounters.Tests.csproj +++ b/src/NServiceBus.Metrics.PerformanceCounters.Tests/NServiceBus.Metrics.PerformanceCounters.Tests.csproj @@ -1,115 +1,30 @@ - - - - Debug - AnyCPU - {9BCDA27A-5FC2-4197-9DCF-0D0F70424B58} - Library - Properties - Tests - Tests - v4.5.2 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - false - - - full - false - bin\Release\ - TRACE - prompt - 4 - true - false - true - + + + net452 true - - key.snk + - - ..\packages\ApprovalTests.3.0.13\lib\net40\ApprovalTests.dll - True - - - ..\packages\ApprovalUtilities.3.0.13\lib\net45\ApprovalUtilities.dll - True - - - ..\packages\ApprovalUtilities.3.0.13\lib\net45\ApprovalUtilities.Net45.dll - True - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll - True - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll - True - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll - True - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll - True - - - ..\packages\NServiceBus.6.3.4\lib\net452\NServiceBus.Core.dll - - - ..\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll - True - - - - - - + + - - {df381b87-8eb9-4f30-9e92-0849641ed01a} - NServiceBus.Metrics.PerformanceCounters - + + + + + + - - CSharpCodeGenerationTests.Generates.approved.cs - - - - - - - - - - - - - - - - - + + + - + - + \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCounterUpdaterTests.cs b/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCounterUpdaterTests.cs index ccc79cc..e0495e4 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCounterUpdaterTests.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCounterUpdaterTests.cs @@ -2,7 +2,12 @@ { using System; using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; using System.Threading; + using System.Threading.Tasks; + using ApprovalUtilities.Utilities; + using NServiceBus; using NUnit.Framework; [TestFixture] @@ -11,58 +16,36 @@ public class PerformanceCounterUpdaterTests [Test] public void Meters_within_payload_should_be_converted_into_performance_counters() { + var endpointName = "Sender@af016c07"; var cache = new MockPerformanceCountersCache(); - var sut = new PerformanceCounterUpdater(cache, new Dictionary()); - sut.Update(PayloadWithRandomMeters); + var signals = new[] + { + new MockSignalProbe("signal 1"), + new MockSignalProbe("signal 2"), + new MockSignalProbe("signal 3"), + }; + + var sut = new PerformanceCounterUpdater(cache, new Dictionary(), endpointName); + + sut.Observe(new ProbeContext(new IDurationProbe[0], signals)); + + var e = new SignalEvent(); + Enumerable.Range(0, 111).ForEach(_ => signals[0].Observers(ref e)); + Enumerable.Range(0, 222).ForEach(_ => signals[1].Observers(ref e)); + Enumerable.Range(0, 333).ForEach(_ => signals[2].Observers(ref e)); - var performanceCounterOne = cache.Get(new CounterInstanceName("meter 1", "Sender@af016c07")); - var performanceCounterTwo = cache.Get(new CounterInstanceName("meter 2", "Sender@af016c07")); - var performanceCounterThree = cache.Get(new CounterInstanceName("meter 3", "Sender@af016c07")); + var performanceCounterOne = cache.Get(new CounterInstanceName(signals[0].Name, endpointName)); + var performanceCounterTwo = cache.Get(new CounterInstanceName(signals[1].Name, endpointName)); + var performanceCounterThree = cache.Get(new CounterInstanceName(signals[2].Name, endpointName)); Assert.AreEqual(111, performanceCounterOne.RawValue); Assert.AreEqual(222, performanceCounterTwo.RawValue); Assert.AreEqual(333, performanceCounterThree.RawValue); } - const string PayloadWithRandomMeters = @"{ - ""Context"": ""Sender@af016c07"", - ""Meters"": [ - { - ""Name"": ""meter 1"", - ""Count"": 111, - ""MeanRate"": 0.0, - ""OneMinuteRate"": 0.0, - ""FiveMinuteRate"": 0.0, - ""FifteenMinuteRate"": 0.0, - ""Unit"": ""Messages"", - ""RateUnit"": ""s"" - }, - { - ""Name"": ""meter 2"", - ""Count"": 222, - ""MeanRate"": 0.0, - ""OneMinuteRate"": 0.0, - ""FiveMinuteRate"": 0.0, - ""FifteenMinuteRate"": 0.0, - ""Unit"": ""Messages"", - ""RateUnit"": ""s"" - }, - { - ""Name"": ""meter 3"", - ""Count"": 333, - ""MeanRate"": 0.0, - ""OneMinuteRate"": 0.0, - ""FiveMinuteRate"": 0.0, - ""FifteenMinuteRate"": 0.0, - ""Unit"": ""Messages"", - ""RateUnit"": ""s"" - } - ] - }"; - [Test] - public void Meters_that_need_mapping_within_payload_should_be_converted_into_performance_counters() + public void Signals_that_map_to_legacy_names_should_be_converted_to_counters_with_queueAddress_as_instance_name() { var cache = new MockPerformanceCountersCache(); @@ -73,9 +56,22 @@ public void Meters_that_need_mapping_within_payload_should_be_converted_into_per { "# of messages successfully processed / sec", new CounterInstanceName("# of msgs successfully processed / sec", "queueAddress") }, }; - var sut = new PerformanceCounterUpdater(cache, legacyInstanceNameMap); + var sut = new PerformanceCounterUpdater(cache, legacyInstanceNameMap, "Sender@af016c07"); + + var signals = new[] + { + new MockSignalProbe("# of message failures / sec"), + new MockSignalProbe("# of messages pulled from the input queue / sec"), + new MockSignalProbe("# of messages successfully processed / sec"), + }; + + sut.Observe(new ProbeContext(new IDurationProbe[0], signals)); + + var e = new SignalEvent(); - sut.Update(PayloadWithNewMeterNamesThatNeedToBeMappedToLegacyMeterNames); + Enumerable.Range(0, 111).ForEach(_ => signals[0].Observers(ref e)); + Enumerable.Range(0, 222).ForEach(_ => signals[1].Observers(ref e)); + Enumerable.Range(0, 333).ForEach(_ => signals[2].Observers(ref e)); var performanceCounterOne = cache.Get(new CounterInstanceName("# of msgs failures / sec", "queueAddress")); var performanceCounterTwo = cache.Get(new CounterInstanceName("# of msgs pulled from the input queue /sec", "queueAddress")); @@ -86,153 +82,145 @@ public void Meters_that_need_mapping_within_payload_should_be_converted_into_per Assert.AreEqual(333, performanceCounterThree.RawValue); } - const string PayloadWithNewMeterNamesThatNeedToBeMappedToLegacyMeterNames = @"{ - ""Context"": ""Sender@af016c07"", - ""Meters"": [ - { - ""Name"": ""# of message failures / sec"", - ""Count"": 111, - ""MeanRate"": 0.0, - ""OneMinuteRate"": 0.0, - ""FiveMinuteRate"": 0.0, - ""FifteenMinuteRate"": 0.0, - ""Unit"": ""Messages"", - ""RateUnit"": ""s"" - }, - { - ""Name"": ""# of messages pulled from the input queue / sec"", - ""Count"": 222, - ""MeanRate"": 0.0, - ""OneMinuteRate"": 0.0, - ""FiveMinuteRate"": 0.0, - ""FifteenMinuteRate"": 0.0, - ""Unit"": ""Messages"", - ""RateUnit"": ""s"" - }, - { - ""Name"": ""# of messages successfully processed / sec"", - ""Count"": 333, - ""MeanRate"": 0.0, - ""OneMinuteRate"": 0.0, - ""FiveMinuteRate"": 0.0, - ""FifteenMinuteRate"": 0.0, - ""Unit"": ""Messages"", - ""RateUnit"": ""s"" - } - ] - }"; [Test] - public void Timers_within_payload_should_be_converted_into_performance_counters() + public void Duration_probes_within_payload_should_be_converted_into_performance_counters() { var cache = new MockPerformanceCountersCache(); - var sut = new PerformanceCounterUpdater(cache, new Dictionary()); + var sut = new PerformanceCounterUpdater(cache, new Dictionary(), "Sender@af016c07"); - sut.Update(PayloadWithRandomTimers); + var durationProbes = new[] + { + new MockDurationProbe("Critical Time"), + new MockDurationProbe("Processing Time") + }; - var performanceCounterOne = cache.Get(new CounterInstanceName("Critical Time", "Sender@af016c07")); - var performanceCounterTwo = cache.Get(new CounterInstanceName("Processing Time", "Sender@af016c07")); + sut.Observe(new ProbeContext(durationProbes, new ISignalProbe[0])); - Assert.AreEqual(11, performanceCounterOne.RawValue); - Assert.AreEqual(22, performanceCounterTwo.RawValue); + var timeSpan1 = TimeSpan.FromSeconds(11); + var d1 = new DurationEvent(timeSpan1, null); + durationProbes[0].Observers(ref d1); + + var timeSpan2 = TimeSpan.FromSeconds(22); + var d2 = new DurationEvent(timeSpan2, null); + durationProbes[1].Observers(ref d2); + + // asserting the number of accessed counters + Assert.AreEqual(3 + 3, cache.Count); + + var counter1 = cache.Get(new CounterInstanceName("Critical Time", "Sender@af016c07")); + var counter1average = cache.Get(new CounterInstanceName("Critical Time Average", "Sender@af016c07")); + var counter1averageBase = cache.Get(new CounterInstanceName("Critical Time AverageBase", "Sender@af016c07")); + + var counter2 = cache.Get(new CounterInstanceName("Processing Time", "Sender@af016c07")); + var counter2average = cache.Get(new CounterInstanceName("Processing Time Average", "Sender@af016c07")); + var counter2averageBase = cache.Get(new CounterInstanceName("Processing Time AverageBase", "Sender@af016c07")); + + Assert.AreEqual(11, counter1.RawValue); + Assert.AreEqual(CalculateAverageTimerCounterUpdate(timeSpan1), counter1average.RawValue); + Assert.AreEqual(1, counter1averageBase.RawValue); + + Assert.AreEqual(22, counter2.RawValue); + Assert.AreEqual(CalculateAverageTimerCounterUpdate(timeSpan2), counter2average.RawValue); + Assert.AreEqual(1, counter2averageBase.RawValue); } - const string PayloadWithRandomTimers = @"{ - ""Context"": ""Sender@af016c07"", - ""Timers"": [ - { - ""Name"": ""Critical Time"", - ""Count"": 0, - ""ActiveSessions"": 0, - ""TotalTime"": 11, - ""Rate"": { - ""MeanRate"": 0.0, - ""OneMinuteRate"": 0.0, - ""FiveMinuteRate"": 0.0, - ""FifteenMinuteRate"": 0.0 - }, - ""Histogram"": { - ""LastValue"": 11000.0, - ""Min"": 0.0, - ""Mean"": 0.0, - ""StdDev"": 0.0, - ""Median"": 0.0, - ""Percentile75"": 0.0, - ""Percentile95"": 0.0, - ""Percentile98"": 0.0, - ""Percentile99"": 0.0, - ""Percentile999"": 0.0, - ""SampleSize"": 0 - }, - ""Unit"": ""Messages"", - ""RateUnit"": ""s"", - ""DurationUnit"": ""ms"" - }, - { - ""Name"": ""Processing Time"", - ""Count"": 0, - ""ActiveSessions"": 0, - ""TotalTime"": 22, - ""Rate"": { - ""MeanRate"": 0.0, - ""OneMinuteRate"": 0.0, - ""FiveMinuteRate"": 0.0, - ""FifteenMinuteRate"": 0.0 - }, - ""Histogram"": { - ""LastValue"": 22000.0, - ""Min"": 0.0, - ""Mean"": 0.0, - ""StdDev"": 0.0, - ""Median"": 0.0, - ""Percentile75"": 0.0, - ""Percentile95"": 0.0, - ""Percentile98"": 0.0, - ""Percentile99"": 0.0, - ""Percentile999"": 0.0, - ""SampleSize"": 0 - }, - ""Unit"": ""Messages"", - ""RateUnit"": ""s"", - ""DurationUnit"": ""ms"" - } - ] - }"; [Test] - public void Timers_within_payload_should_be_reported_as_zeros_after_specific_period_from_last_observed_pipeline_completion() + public void Duration_probes_within_payload_should_be_converted_into_performance_counters_with_no_raw_value_if_not_critical_or_processing_time() + { + var cache = new MockPerformanceCountersCache(); + var sut = new PerformanceCounterUpdater(cache, new Dictionary(), "Sender@af016c07"); + + var durationProbes = new[] + { + new MockDurationProbe("Any Other Timer"), + }; + + sut.Observe(new ProbeContext(durationProbes, new ISignalProbe[0])); + + var timeSpan = TimeSpan.FromSeconds(11); + var d = new DurationEvent(timeSpan, null); + durationProbes[0].Observers(ref d); + + // asserting the number of accessed counters + Assert.AreEqual(2, cache.Count); + + var counter1 = cache.Get(new CounterInstanceName("Any Other Timer", "Sender@af016c07")); + var counter1average = cache.Get(new CounterInstanceName("Any Other Timer Average", "Sender@af016c07")); + var counter1averageBase = cache.Get(new CounterInstanceName("Any Other Timer AverageBase", "Sender@af016c07")); + + Assert.AreEqual(0, counter1.RawValue); + Assert.AreEqual(CalculateAverageTimerCounterUpdate(timeSpan), counter1average.RawValue); + Assert.AreEqual(1, counter1averageBase.RawValue); + } + + static long CalculateAverageTimerCounterUpdate(TimeSpan d) + { + return d.Ticks * Stopwatch.Frequency / TimeSpan.TicksPerSecond; + } + [Test] + public async Task Durations_should_be_reported_as_zeros_after_specific_period_from_last_observed_pipeline_completion() { + const string endpoint = "Sender@af016c07"; var resetTimersAfter = TimeSpan.FromMilliseconds(100); var cache = new MockPerformanceCountersCache(); - var sut = new PerformanceCounterUpdater(cache, new Dictionary(), resetTimersAfter); + var updater = new PerformanceCounterUpdater(cache, new Dictionary(), endpoint, resetTimersAfter); - Thread.Sleep(TimeSpan.FromTicks(resetTimersAfter.Ticks * 2)); + var durationProbes = new[] + { + new MockDurationProbe("Critical Time"), + new MockDurationProbe("Processing Time") + }; + + // update before timeout + updater.Observe(new ProbeContext(durationProbes, new ISignalProbe[0])); - sut.Update(PayloadWithRandomTimers); + updater.Start(); - var performanceCounterOne = cache.Get(new CounterInstanceName("Critical Time", "Sender@af016c07")); - var performanceCounterTwo = cache.Get(new CounterInstanceName("Processing Time", "Sender@af016c07")); + durationProbes[0].Raise(TimeSpan.FromSeconds(11)); + durationProbes[1].Raise(TimeSpan.FromSeconds(22)); + + await Task.Delay(TimeSpan.FromTicks(resetTimersAfter.Ticks * 2)); + + var performanceCounterOne = cache.Get(new CounterInstanceName("Critical Time", endpoint)); + var performanceCounterTwo = cache.Get(new CounterInstanceName("Processing Time", endpoint)); + + await updater.Stop(); Assert.AreEqual(0, performanceCounterOne.RawValue); Assert.AreEqual(0, performanceCounterTwo.RawValue); } [Test] - public void Timers_within_payload_should_be_reported_properly_after_observed_pipeline_completion() + public void Durations_should_be_reported_properly_after_observed_pipeline_completion() { + const string endpoint = "Sender@af016c07"; var resetTimersAfter = TimeSpan.FromMilliseconds(100); var cache = new MockPerformanceCountersCache(); - var sut = new PerformanceCounterUpdater(cache, new Dictionary(), resetTimersAfter); + var updater = new PerformanceCounterUpdater(cache, new Dictionary(), endpoint, resetTimersAfter); + + var durationProbes = new[] + { + new MockDurationProbe("Critical Time"), + new MockDurationProbe("Processing Time") + }; + + // update before timeout + updater.Observe(new ProbeContext(durationProbes, new ISignalProbe[0])); + + updater.Start(); Thread.Sleep(TimeSpan.FromTicks(resetTimersAfter.Ticks * 2)); - sut.OnReceivePipelineCompleted(); + updater.OnReceivePipelineCompleted(); - sut.Update(PayloadWithRandomTimers); + durationProbes[0].Raise(TimeSpan.FromSeconds(11)); + durationProbes[1].Raise(TimeSpan.FromSeconds(22)); - var performanceCounterOne = cache.Get(new CounterInstanceName("Critical Time", "Sender@af016c07")); - var performanceCounterTwo = cache.Get(new CounterInstanceName("Processing Time", "Sender@af016c07")); + var performanceCounterOne = cache.Get(new CounterInstanceName("Critical Time", endpoint)); + var performanceCounterTwo = cache.Get(new CounterInstanceName("Processing Time", endpoint)); Assert.AreEqual(11, performanceCounterOne.RawValue); Assert.AreEqual(22, performanceCounterTwo.RawValue); @@ -245,5 +233,47 @@ protected override IPerformanceCounterInstance CreateInstance(CounterInstanceNam { return new MockIPerformanceCounter(); } + + public int Count => CountCounters(); + } + + class MockSignalProbe : ISignalProbe + { + public MockSignalProbe(string name) + { + Name = name; + } + + public void Register(OnEvent observer) + { + Observers += observer; + } + + public string Name { get; } + public string Description => string.Empty; + public OnEvent Observers = (ref SignalEvent e) => { }; + } + + class MockDurationProbe : IDurationProbe + { + public MockDurationProbe(string name) + { + Name = name; + } + + public void Register(OnEvent observer) + { + Observers += observer; + } + + public void Raise(TimeSpan timespan, string messageType = null) + { + var duration = new DurationEvent(timespan, messageType); + Observers(ref duration); + } + + public string Name { get; } + public string Description => string.Empty; + public OnEvent Observers = (ref DurationEvent d) => { }; } } \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCountersCacheTests.Should_throw_for_endpoint_name_too_long.approved.txt b/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCountersCacheTests.Should_throw_for_endpoint_name_too_long.approved.txt index 25d7cb5..85a2ab6 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCountersCacheTests.Should_throw_for_endpoint_name_too_long.approved.txt +++ b/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCountersCacheTests.Should_throw_for_endpoint_name_too_long.approved.txt @@ -1 +1 @@ -The endpoint name ('*********************************************************************************************************************************') is too long (longer then 127) to register as a performance counter instance name. Reduce the endpoint name. \ No newline at end of file +The endpoint name ('*********************************************************************************************************************************') is too long (longer then 127) to register as a performance counter instance name. Shorten the endpoint name length. \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCountersCacheTests.cs b/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCountersCacheTests.cs index dc0988c..4f60324 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCountersCacheTests.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters.Tests/PerformanceCountersCacheTests.cs @@ -1,6 +1,7 @@ namespace Tests { using System; + using System.Runtime.CompilerServices; using ApprovalTests; using NUnit.Framework; @@ -25,6 +26,7 @@ public void Get_the_same_counter_twice_returns_the_same() } [Test] + [MethodImpl(MethodImplOptions.NoInlining)] public void Should_throw_for_endpoint_name_too_long() { var cache = new PerformanceCountersCache(); diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/PipelineExtensionsTests.cs b/src/NServiceBus.Metrics.PerformanceCounters.Tests/PipelineExtensionsTests.cs index 55b1ded..1b91500 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/PipelineExtensionsTests.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters.Tests/PipelineExtensionsTests.cs @@ -8,7 +8,7 @@ public class PipelineExtensionsTests { [Test] - public void Should_extract_timesent_from_headers() + public void Should_extract_timeSent_from_headers() { var dateTime = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc); var headers = new Dictionary @@ -22,8 +22,7 @@ public void Should_extract_timesent_from_headers() startedAt: new DateTime(2000, 1, 1, 1, 1, 2, DateTimeKind.Utc), completedAt: new DateTime(2000, 1, 1, 1, 1, 3, DateTimeKind.Utc)); - DateTime timeSent; - pipelineCompleted.TryGetTimeSent(out timeSent); + pipelineCompleted.TryGetTimeSent(out var timeSent); Assert.AreEqual(dateTime, timeSent); } } \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters.Tests/packages.config b/src/NServiceBus.Metrics.PerformanceCounters.Tests/packages.config deleted file mode 100644 index d175419..0000000 --- a/src/NServiceBus.Metrics.PerformanceCounters.Tests/packages.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters.sln b/src/NServiceBus.Metrics.PerformanceCounters.sln index a2f41ea..e86d426 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.sln +++ b/src/NServiceBus.Metrics.PerformanceCounters.sln @@ -1,25 +1,21 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26403.3 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NServiceBus.Metrics.PerformanceCounters", "NServiceBus.Metrics.PerformanceCounters\NServiceBus.Metrics.PerformanceCounters.csproj", "{DF381B87-8EB9-4F30-9E92-0849641ED01A}" +VisualStudioVersion = 15.0.27004.2002 +MinimumVisualStudioVersion = 15.0.26403.3 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NServiceBus.Metrics.PerformanceCounters", "NServiceBus.Metrics.PerformanceCounters\NServiceBus.Metrics.PerformanceCounters.csproj", "{DF381B87-8EB9-4F30-9E92-0849641ED01A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NServiceBus.Metrics.PerformanceCounters.Tests", "NServiceBus.Metrics.PerformanceCounters.Tests\NServiceBus.Metrics.PerformanceCounters.Tests.csproj", "{9BCDA27A-5FC2-4197-9DCF-0D0F70424B58}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NServiceBus.Metrics.PerformanceCounters.Tests", "NServiceBus.Metrics.PerformanceCounters.Tests\NServiceBus.Metrics.PerformanceCounters.Tests.csproj", "{9BCDA27A-5FC2-4197-9DCF-0D0F70424B58}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{54D85933-AF31-49D3-9208-36DC4689B291}" - ProjectSection(SolutionItems) = preProject - ..\packaging\nuget\NServiceBus.Metrics.PerformanceCounters.MsBuild.nuspec = ..\packaging\nuget\NServiceBus.Metrics.PerformanceCounters.MsBuild.nuspec - ..\packaging\nuget\NServiceBus.Metrics.PerformanceCounters.MsBuild.targets = ..\packaging\nuget\NServiceBus.Metrics.PerformanceCounters.MsBuild.targets - ..\packaging\nuget\NServiceBus.Metrics.PerformanceCounters.nuspec = ..\packaging\nuget\NServiceBus.Metrics.PerformanceCounters.nuspec - nuget.config = nuget.config - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptBuilderTask", "ScriptBuilderTask\ScriptBuilderTask.csproj", "{08FD76CB-6988-485A-A535-B3129AF89C60}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptBuilderTask", "ScriptBuilderTask\ScriptBuilderTask.csproj", "{08FD76CB-6988-485A-A535-B3129AF89C60}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptBuilder", "ScriptBuilder\ScriptBuilder.csproj", "{1BDA0A75-91F6-4412-A780-7BE9322B2A4E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptBuilderTask.Tests", "ScriptBuilderTask.Tests\ScriptBuilderTask.Tests.csproj", "{8174164E-52B8-4878-BFB0-34C81A31930E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptBuilderTask.Tests", "ScriptBuilderTask.Tests\ScriptBuilderTask.Tests.csproj", "{8174164E-52B8-4878-BFB0-34C81A31930E}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1B573EC5-07D6-4E25-9687-FB5A536B4FD9}" + ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props + ..\GitVersion.yml = ..\GitVersion.yml + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -39,10 +35,6 @@ Global {08FD76CB-6988-485A-A535-B3129AF89C60}.Debug|Any CPU.Build.0 = Debug|Any CPU {08FD76CB-6988-485A-A535-B3129AF89C60}.Release|Any CPU.ActiveCfg = Release|Any CPU {08FD76CB-6988-485A-A535-B3129AF89C60}.Release|Any CPU.Build.0 = Release|Any CPU - {1BDA0A75-91F6-4412-A780-7BE9322B2A4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1BDA0A75-91F6-4412-A780-7BE9322B2A4E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1BDA0A75-91F6-4412-A780-7BE9322B2A4E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1BDA0A75-91F6-4412-A780-7BE9322B2A4E}.Release|Any CPU.Build.0 = Release|Any CPU {8174164E-52B8-4878-BFB0-34C81A31930E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8174164E-52B8-4878-BFB0-34C81A31930E}.Debug|Any CPU.Build.0 = Debug|Any CPU {8174164E-52B8-4878-BFB0-34C81A31930E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -51,4 +43,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {021BB233-292E-4506-90FA-B10BD9F3F80D} + EndGlobalSection EndGlobal diff --git a/src/NServiceBus.Metrics.PerformanceCounters.sln.DotSettings b/src/NServiceBus.Metrics.PerformanceCounters.sln.DotSettings index 4e4965d..611eecc 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters.sln.DotSettings +++ b/src/NServiceBus.Metrics.PerformanceCounters.sln.DotSettings @@ -1,13 +1,17 @@  - CSharp60 + Experimental + DO_NOT_SHOW + ERROR + ERROR + ERROR True True True False True - ExplicitlyExcluded + ExplicitlyExcluded SOLUTION SUGGESTION SUGGESTION @@ -23,6 +27,7 @@ ERROR ERROR ERROR + DO_NOT_SHOW DO_NOT_SHOW DO_NOT_SHOW DO_NOT_SHOW @@ -45,6 +50,13 @@ ERROR ERROR ERROR + ERROR + ERROR + ERROR + ERROR + ERROR + ERROR + ERROR ERROR ERROR DO_NOT_SHOW @@ -112,6 +124,7 @@ DoHide DoHide DoHide + WARNING ERROR ERROR ERROR @@ -134,11 +147,13 @@ HINT WARNING ERROR - ERROR - ERROR <?xml version="1.0" encoding="utf-16"?><Profile name="Format My Code Using &quot;Particular&quot; conventions"><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_TO_IMPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_IMPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_IMPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSReformatCode>True</CSReformatCode><CSReorderTypeMembers>True</CSReorderTypeMembers><JsInsertSemicolon>True</JsInsertSemicolon><JsReformatCode>True</JsReformatCode><CssReformatCode>True</CssReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><HtmlReformatCode>True</HtmlReformatCode><CSShortenReferences>True</CSShortenReferences><CSharpFormatDocComments>True</CSharpFormatDocComments><CssAlphabetizeProperties>True</CssAlphabetizeProperties></Profile> Default: Reformat Code Format My Code Using "Particular" conventions + Required + Required + Required + Required Implicit Implicit False @@ -148,6 +163,7 @@ ALWAYS_ADD ALWAYS_ADD ALWAYS_ADD + False False False False @@ -155,8 +171,6 @@ False CHOP_ALWAYS CHOP_ALWAYS - True - True ZeroIndent ZeroIndent <?xml version="1.0" encoding="utf-16"?> @@ -535,53 +549,6 @@ II.2.12 <HandlesEvent /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> - $object$_On$event$ - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> @@ -594,12 +561,8 @@ II.2.12 <HandlesEvent /> True True True - True - True - True True - <data /> <data><IncludeFilters /><ExcludeFilters /></data> \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters/AssemblyInfo.cs b/src/NServiceBus.Metrics.PerformanceCounters/AssemblyInfo.cs deleted file mode 100644 index 2bcda94..0000000 --- a/src/NServiceBus.Metrics.PerformanceCounters/AssemblyInfo.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("NServiceBus.Metrics.PerformanceCounters")] -[assembly: AssemblyCopyright("Copyright NServiceBus Ltd. All rights reserved")] -[assembly: AssemblyProduct("NServiceBus.Metrics.PerformanceCounters")] -[assembly: AssemblyCompany("NServiceBus Ltd.")] -[assembly: ComVisible(false)] -[assembly: CLSCompliant(true)] -[assembly: InternalsVisibleTo("Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100D32BC524DCB1205998C155A4F36BF873587D3602822ECD7B49CD775B2E6A006EE6B9164AB2E3103A6A4D1310C6E5C26818A32FE86710141A2D1F02EB564381CD64C88131BCCA478CDB5072F06DB991DE33DAC1C82BAF40D9F61DD6B40300A4673B693B51CD10A8B9B7D8AB64450431FA422514D6DABCAF70DF785B1E4E6E8AAF")] \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters/CounterInstanceName.cs b/src/NServiceBus.Metrics.PerformanceCounters/CounterInstanceName.cs index 6db13dd..60268a3 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/CounterInstanceName.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/CounterInstanceName.cs @@ -9,8 +9,16 @@ public bool Equals(CounterInstanceName other) public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) return false; - return obj is CounterInstanceName && Equals((CounterInstanceName)obj); + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (!(obj is CounterInstanceName)) + { + return false; + } + return Equals((CounterInstanceName)obj); } public override int GetHashCode() diff --git a/src/NServiceBus.Metrics.PerformanceCounters/Counters/IPerformanceCounterInstance.cs b/src/NServiceBus.Metrics.PerformanceCounters/Counters/IPerformanceCounterInstance.cs index 92b9ca8..1fbdc74 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/Counters/IPerformanceCounterInstance.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/Counters/IPerformanceCounterInstance.cs @@ -3,5 +3,6 @@ interface IPerformanceCounterInstance : IDisposable { void Increment(); + void IncrementBy(long value); long RawValue { get; set; } } \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters/Counters/PerformanceCounterInstance.cs b/src/NServiceBus.Metrics.PerformanceCounters/Counters/PerformanceCounterInstance.cs index 638266f..c1827c7 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/Counters/PerformanceCounterInstance.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/Counters/PerformanceCounterInstance.cs @@ -12,6 +12,11 @@ public void Increment() counter.Increment(); } + public void IncrementBy(long value) + { + counter.IncrementBy(value); + } + public void Dispose() { counter?.Dispose(); @@ -21,7 +26,7 @@ public void Dispose() public long RawValue { - get { return counter.RawValue; } - set { counter.RawValue = value; } + get => counter.RawValue; + set => counter.RawValue = value; } } \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters/Counters/PerformanceCountersCache.cs b/src/NServiceBus.Metrics.PerformanceCounters/Counters/PerformanceCountersCache.cs index 1eeb7ee..a5b2b96 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/Counters/PerformanceCountersCache.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/Counters/PerformanceCountersCache.cs @@ -27,7 +27,7 @@ protected virtual IPerformanceCounterInstance CreateInstance(CounterInstanceName if (counterInstanceName.InstanceName.Length > sbyte.MaxValue) { - throw new Exception($"The endpoint name ('{counterInstanceName.InstanceName}') is too long (longer then {sbyte.MaxValue}) to register as a performance counter instance name. Reduce the endpoint name."); + throw new Exception($"The endpoint name ('{counterInstanceName.InstanceName}') is too long (longer then {sbyte.MaxValue}) to register as a performance counter instance name. Shorten the endpoint name length."); } try @@ -42,5 +42,7 @@ protected virtual IPerformanceCounterInstance CreateInstance(CounterInstanceName return new PerformanceCounterInstance(counter); } + protected int CountCounters() => counterCache.Count; + ConcurrentDictionary counterCache = new ConcurrentDictionary(); -} \ No newline at end of file +} diff --git a/src/NServiceBus.Metrics.PerformanceCounters/Extensions.cs b/src/NServiceBus.Metrics.PerformanceCounters/Extensions.cs index fe60015..45628bb 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/Extensions.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/Extensions.cs @@ -7,8 +7,7 @@ static class Extensions public static bool TryGetTimeSent(this ReceivePipelineCompleted completed, out DateTime timeSent) { var headers = completed.ProcessedMessage.Headers; - string timeSentString; - if (headers.TryGetValue(Headers.TimeSent, out timeSentString)) + if (headers.TryGetValue(Headers.TimeSent, out var timeSentString)) { timeSent = DateTimeExtensions.ToUtcDateTime(timeSentString); return true; @@ -17,7 +16,7 @@ public static bool TryGetTimeSent(this ReceivePipelineCompleted completed, out D return false; } - public static void ThrowIfSendonly(this FeatureConfigurationContext context) + public static void ThrowIfSendOnly(this FeatureConfigurationContext context) { var isSendOnly = context.Settings.GetOrDefault("Endpoint.SendOnly"); if (isSendOnly) diff --git a/src/NServiceBus.Metrics.PerformanceCounters/FodyWeavers.xml b/src/NServiceBus.Metrics.PerformanceCounters/FodyWeavers.xml new file mode 100644 index 0000000..4f63d3b --- /dev/null +++ b/src/NServiceBus.Metrics.PerformanceCounters/FodyWeavers.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/NServiceBus.Metrics.PerformanceCounters/InternalsVisibleTo.cs b/src/NServiceBus.Metrics.PerformanceCounters/InternalsVisibleTo.cs new file mode 100644 index 0000000..0a2b32e --- /dev/null +++ b/src/NServiceBus.Metrics.PerformanceCounters/InternalsVisibleTo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("NServiceBus.Metrics.PerformanceCounters.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100D32BC524DCB1205998C155A4F36BF873587D3602822ECD7B49CD775B2E6A006EE6B9164AB2E3103A6A4D1310C6E5C26818A32FE86710141A2D1F02EB564381CD64C88131BCCA478CDB5072F06DB991DE33DAC1C82BAF40D9F61DD6B40300A4673B693B51CD10A8B9B7D8AB64450431FA422514D6DABCAF70DF785B1E4E6E8AAF")] \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters/Meter.cs b/src/NServiceBus.Metrics.PerformanceCounters/Meter.cs deleted file mode 100644 index 61ecd9d..0000000 --- a/src/NServiceBus.Metrics.PerformanceCounters/Meter.cs +++ /dev/null @@ -1,11 +0,0 @@ -struct Meter -{ - public readonly string Name; - public readonly long Count; - - public Meter(string name, long count) - { - Name = name; - Count = count; - } -} \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters/NServiceBus.Metrics.PerformanceCounters.csproj b/src/NServiceBus.Metrics.PerformanceCounters/NServiceBus.Metrics.PerformanceCounters.csproj index 362401c..dd60200 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/NServiceBus.Metrics.PerformanceCounters.csproj +++ b/src/NServiceBus.Metrics.PerformanceCounters/NServiceBus.Metrics.PerformanceCounters.csproj @@ -1,114 +1,28 @@ - - - + + - Debug - AnyCPU - {DF381B87-8EB9-4F30-9E92-0849641ED01A} - Library - Properties - NServiceBus.Metrics.PerformanceCounters - NServiceBus.Metrics.PerformanceCounters - v4.5.2 - 512 + net452 true - ..\NServiceBus.snk - - - - - true - full - false - ..\..\binaries\ - DEBUG;TRACE - prompt - 4 - true - ..\..\binaries\NServiceBus.Metrics.PerformanceCounters.xml - - - - - pdbonly - true + $(SolutionDir)NServiceBus.snk ..\..\binaries\ - TRACE - prompt - 4 - true - ..\..\binaries\NServiceBus.Metrics.PerformanceCounters.xml - - + Enables access to performance counters + - - ..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll - - - ..\packages\NServiceBus.6.3.4\lib\net452\NServiceBus.Core.dll - - - ..\packages\NServiceBus.Metrics.1.0.1\lib\net452\NServiceBus.Metrics.dll - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + - - Designer - + - - - - - - - - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - + \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters/NServiceBus.Metrics.PerformanceCounters.csproj.DotSettings b/src/NServiceBus.Metrics.PerformanceCounters/NServiceBus.Metrics.PerformanceCounters.csproj.DotSettings deleted file mode 100644 index 3fdbc3c..0000000 --- a/src/NServiceBus.Metrics.PerformanceCounters/NServiceBus.Metrics.PerformanceCounters.csproj.DotSettings +++ /dev/null @@ -1,2 +0,0 @@ - - True \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCounterSettingsAttribute.cs b/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCounterSettingsAttribute.cs index 5e8c044..8ef822b 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCounterSettingsAttribute.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCounterSettingsAttribute.cs @@ -23,7 +23,7 @@ public sealed class PerformanceCounterSettingsAttribute : Attribute /// /// Path to promote performance counter installation scripts to. /// The token '$(SolutionDir)' will be replace with the current solution directory. - /// The token '$(ProjectDir)' will be replace witht he current solution directory. + /// The token '$(ProjectDir)' will be replace with the current solution directory. /// The path calculation is performed relative to the current project directory. /// public string ScriptPromotionPath { get; set; } diff --git a/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCounterUpdater.cs b/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCounterUpdater.cs index 77ed25f..21dc58c 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCounterUpdater.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCounterUpdater.cs @@ -1,54 +1,72 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; -using Newtonsoft.Json.Linq; +using System.Diagnostics; +using System.Threading.Tasks; +using NServiceBus; +using NServiceBus.Metrics.PerformanceCounters; class PerformanceCounterUpdater { - public PerformanceCounterUpdater(PerformanceCountersCache cache, Dictionary legacyInstanceNameMap, TimeSpan? resetTimersAfter = null) + public PerformanceCounterUpdater(PerformanceCountersCache cache, Dictionary legacyInstanceNameMap, string endpointName, TimeSpan? resetTimersAfter = null) { - resetAfterTicks = (resetTimersAfter ?? TimeSpan.FromSeconds(2)).Ticks; + resetEvery = resetTimersAfter ?? TimeSpan.FromSeconds(2); this.legacyInstanceNameMap = legacyInstanceNameMap; + this.endpointName = endpointName; this.cache = cache; - + cancellation = new CancellationTokenSource(); // initialize to an armed state OnReceivePipelineCompleted(); } - public void Update(string payload) + public void Start() + { + cleaner = Task.Run(Cleanup); + } + + public Task Stop() { - var rootObject = JObject.Parse(payload); + cancellation.Cancel(); + return cleaner; + } - var context = rootObject.Value("Context"); - var meters = rootObject["Meters"]?.ToObject>() ?? new List(); - foreach (var meter in meters) + public void Observe(ProbeContext context) + { + foreach (var signalProbe in context.Signals) { - CounterInstanceName? instanceName; - legacyInstanceNameMap.TryGetValue(meter.Name, out instanceName); + legacyInstanceNameMap.TryGetValue(signalProbe.Name, out var instanceName); - var performanceCounterInstance = cache.Get(instanceName ?? new CounterInstanceName(meter.Name, context)); - performanceCounterInstance.RawValue = meter.Count; + var performanceCounterInstance = cache.Get(instanceName ?? new CounterInstanceName(signalProbe.Name, endpointName)); + + signalProbe.Register((ref SignalEvent e) => performanceCounterInstance.Increment()); } - var timers = rootObject["Timers"]?.ToObject>() ?? new List(); - foreach (var timer in timers) + foreach (var durationProbe in context.Durations) { - var performanceCounterInstance = cache.Get(new CounterInstanceName(timer.Name, context)); - - var idleFor = NowTicks - Volatile.Read(ref lastCompleted); - if (idleFor > resetAfterTicks) + if (durationProbe.Name == CounterNameConventions.ProcessingTime || durationProbe.Name == CounterNameConventions.CriticalTime) { - performanceCounterInstance.RawValue = 0; + var key = new CounterInstanceName(durationProbe.Name, endpointName); + var performanceCounterInstance = cache.Get(key); + resettable[key] = performanceCounterInstance; + durationProbe.Register((ref DurationEvent d) => performanceCounterInstance.RawValue = (long) d.Duration.TotalSeconds); } - else + + var averageTimerCounter = cache.Get(new CounterInstanceName(durationProbe.Name.GetAverageTimerCounterName(), endpointName)); + var baseAverageTimerCounter = cache.Get(new CounterInstanceName(durationProbe.Name.GetAverageTimerBaseCounterName(), endpointName)); + + durationProbe.Register((ref DurationEvent d) => { - performanceCounterInstance.RawValue = timer.Histogram.LastValue / 1000; - } + var performanceCounterTicks = d.Duration.Ticks * Stopwatch.Frequency / TimeSpan.TicksPerSecond; + averageTimerCounter.IncrementBy(performanceCounterTicks); + baseAverageTimerCounter.Increment(); + }); } } readonly PerformanceCountersCache cache; readonly Dictionary legacyInstanceNameMap; + readonly ConcurrentDictionary resettable = new ConcurrentDictionary(); long lastCompleted; public void OnReceivePipelineCompleted() @@ -56,6 +74,26 @@ public void OnReceivePipelineCompleted() Volatile.Write(ref lastCompleted, NowTicks); } + async Task Cleanup() + { + while (cancellation.IsCancellationRequested == false) + { + await Task.Delay(resetEvery).ConfigureAwait(false); + + var idleFor = NowTicks - Volatile.Read(ref lastCompleted); + if (idleFor > resetEvery.Ticks) + { + foreach (var performanceCounter in resettable) + { + performanceCounter.Value.RawValue = 0; + } + } + } + } + static long NowTicks => DateTime.UtcNow.Ticks; - readonly long resetAfterTicks; + readonly TimeSpan resetEvery; + readonly string endpointName; + Task cleaner; + readonly CancellationTokenSource cancellation; } \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersExtensions.cs b/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersExtensions.cs index 5fd7280..e2c8197 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersExtensions.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersExtensions.cs @@ -14,9 +14,6 @@ public static PerformanceCountersSettings EnableWindowsPerformanceCounters(this { Guard.AgainstNull(nameof(endpointConfiguration), endpointConfiguration); -#pragma warning disable 618 - endpointConfiguration.DisableFeature(); -#pragma warning restore 618 endpointConfiguration.EnableFeature(); return new PerformanceCountersSettings(endpointConfiguration); diff --git a/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersFeature.cs b/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersFeature.cs index cbc69e9..30855d0 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersFeature.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersFeature.cs @@ -11,23 +11,22 @@ public PerformanceCountersFeature() Defaults(s => { options = s.EnableMetrics(); - s.SetDefault(UpdateIntervalKey, TimeSpan.FromSeconds(2)); }); } protected override void Setup(FeatureConfigurationContext context) { - var logicalAddress = context.Settings.LogicalAddress(); + var endpoint = context.Settings.LogicalAddress().EndpointInstance.Endpoint; var legacyInstanceNameMap = new Dictionary { - {"# of message failures / sec", new CounterInstanceName(MessagesFailuresPerSecondCounterName, logicalAddress.EndpointInstance.Endpoint)}, - {"# of messages pulled from the input queue / sec", new CounterInstanceName(MessagesPulledPerSecondCounterName, logicalAddress.EndpointInstance.Endpoint)}, - {"# of messages successfully processed / sec", new CounterInstanceName(MessagesProcessedPerSecondCounterName, logicalAddress.EndpointInstance.Endpoint)} + {"# of message failures / sec", new CounterInstanceName(MessagesFailuresPerSecondCounterName, endpoint)}, + {"# of messages pulled from the input queue / sec", new CounterInstanceName(MessagesPulledPerSecondCounterName, endpoint)}, + {"# of messages successfully processed / sec", new CounterInstanceName(MessagesProcessedPerSecondCounterName, endpoint)} }; cache = new PerformanceCountersCache(); - updater = new PerformanceCounterUpdater(cache, legacyInstanceNameMap); + updater = new PerformanceCounterUpdater(cache, legacyInstanceNameMap, endpoint); context.RegisterStartupTask(new Cleanup(this)); @@ -37,11 +36,10 @@ protected override void Setup(FeatureConfigurationContext context) return TaskExtensions.CompletedTask; }); - options.EnableCustomReport(payload => + options.RegisterObservers(probeContext => { - updater?.Update(payload); - return TaskExtensions.CompletedTask; - }, context.Settings.Get(UpdateIntervalKey)); + updater.Observe(probeContext); + }); } MetricsOptions options; @@ -53,7 +51,6 @@ protected override void Setup(FeatureConfigurationContext context) public const string MessagesFailuresPerSecondCounterName = "# of msgs failures / sec"; public const string CriticalTimeCounterName = "Critical Time"; public const string ProcessingTimeCounterName = "Processing Time"; - public const string UpdateIntervalKey = "PerformanceCounterUpdateInterval"; class Cleanup : FeatureStartupTask, IDisposable { @@ -70,12 +67,13 @@ public void Dispose() protected override Task OnStart(IMessageSession session) { + feature.updater.Start(); return TaskExtensions.CompletedTask; } protected override Task OnStop(IMessageSession session) { - return TaskExtensions.CompletedTask; + return feature.updater.Stop(); } PerformanceCountersFeature feature; diff --git a/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersSettings.cs b/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersSettings.cs index a19415c..27b5e95 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersSettings.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/PerformanceCountersSettings.cs @@ -28,14 +28,12 @@ public void EnableSLAPerformanceCounters(TimeSpan sla) } /// - /// Defines the update interval for the performance counter values. + /// Sets the update interval. /// - /// The update interval. + /// + [ObsoleteEx(Message = "This interval is no longer used for reporting. Counters values are updated as soon as they are reported", RemoveInVersion = "3.0")] public void UpdateCounterEvery(TimeSpan updateInterval) { - Guard.AgainstNegativeAndZero(nameof(updateInterval), updateInterval); - - endpointConfiguration.GetSettings().Set(PerformanceCountersFeature.UpdateIntervalKey, updateInterval); } } } \ No newline at end of file diff --git a/src/NServiceBus.Metrics.PerformanceCounters/SLA/EstimatedTimeToSLABreachCounter.cs b/src/NServiceBus.Metrics.PerformanceCounters/SLA/EstimatedTimeToSLABreachCounter.cs index 09dc358..29abf07 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/SLA/EstimatedTimeToSLABreachCounter.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/SLA/EstimatedTimeToSLABreachCounter.cs @@ -12,8 +12,7 @@ public EstimatedTimeToSLABreachCounter(TimeSpan endpointSla, IPerformanceCounter public void Update(ReceivePipelineCompleted completed) { - DateTime timeSent; - if (completed.TryGetTimeSent(out timeSent)) + if (completed.TryGetTimeSent(out var timeSent)) { Update(timeSent, completed.StartedAt, completed.CompletedAt); } diff --git a/src/NServiceBus.Metrics.PerformanceCounters/SLA/SLAMonitoringFeature.cs b/src/NServiceBus.Metrics.PerformanceCounters/SLA/SLAMonitoringFeature.cs index 239b819..3a31780 100644 --- a/src/NServiceBus.Metrics.PerformanceCounters/SLA/SLAMonitoringFeature.cs +++ b/src/NServiceBus.Metrics.PerformanceCounters/SLA/SLAMonitoringFeature.cs @@ -7,7 +7,7 @@ class SLAMonitoringFeature : Feature { protected override void Setup(FeatureConfigurationContext context) { - context.ThrowIfSendonly(); + context.ThrowIfSendOnly(); var settings = context.Settings; var endpointSla = settings.Get(EndpointSLAKey); diff --git a/src/NServiceBus.Metrics.PerformanceCounters/packages.config b/src/NServiceBus.Metrics.PerformanceCounters/packages.config deleted file mode 100644 index 6c4fbf4..0000000 --- a/src/NServiceBus.Metrics.PerformanceCounters/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/ScriptBuilder/AssemblyInfo.cs b/src/ScriptBuilder/AssemblyInfo.cs deleted file mode 100644 index 14979fd..0000000 --- a/src/ScriptBuilder/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("NServiceBus.Metrics.PerformanceCounters.Builder")] -[assembly: AssemblyProduct("NServiceBus.Metrics.PerformanceCounters.Builder")] \ No newline at end of file diff --git a/src/ScriptBuilder/ScriptBuilder.csproj b/src/ScriptBuilder/ScriptBuilder.csproj deleted file mode 100644 index 296a452..0000000 --- a/src/ScriptBuilder/ScriptBuilder.csproj +++ /dev/null @@ -1,82 +0,0 @@ - - - - - Debug - AnyCPU - {1BDA0A75-91F6-4412-A780-7BE9322B2A4E} - Library - Properties - NServiceBus.Metrics.PerformanceCounters - NServiceBus.Metrics.PerformanceCounters.Builder - v4.5.2 - 512 - true - $(SolutionDir)NServiceBus.snk - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "$(SolutionDir)..\Tools\ilmerge.exe" - $(ProjectDir)bin\$(ConfigurationName)\NServiceBus.Metrics.PerformanceCounters.Builder.dll - $(ProjectDir)bin\$(ConfigurationName)\Mono.Cecil.dll - $(SolutionDir)..\binaries\NServiceBus.Metrics.PerformanceCounters.Builder.dll - - - - - \ No newline at end of file diff --git a/src/ScriptBuilder/Timers/TimerDefinitionReader.cs b/src/ScriptBuilder/Timers/TimerDefinitionReader.cs deleted file mode 100644 index 5d1aea7..0000000 --- a/src/ScriptBuilder/Timers/TimerDefinitionReader.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace NServiceBus.Metrics.PerformanceCounters -{ - using System.Collections.Generic; - using System.Linq; - using Mono.Cecil; - - static class TimerDefinitionReader - { - public static bool TryGetTimerDefinition(TypeDefinition type, out List definitions) - { - definitions = new List(); - if (type.BaseType != null && type.BaseType.FullName == "NServiceBus.Metrics.MetricBuilder") - { - var timerAttributes = type.Fields.Select(f => f.GetSingleAttribute("NServiceBus.Metrics.TimerAttribute")).Where(c => c != null); - - foreach (var timerAttribute in timerAttributes) - { - var name = timerAttribute.ParameterValue("name"); - var description = timerAttribute.ParameterValue("description"); - - definitions.Add(new TimerDefinition(name, description)); - } - } - return definitions.Count > 0; - } - } -} \ No newline at end of file diff --git a/src/ScriptBuilder/packages.config b/src/ScriptBuilder/packages.config deleted file mode 100644 index 88fbc79..0000000 --- a/src/ScriptBuilder/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/ScriptBuilderTask.Tests/CSharpCodeGenerationTests.Generates.approved.cs b/src/ScriptBuilderTask.Tests/CSharpCodeGenerationTests.Generates.approved.cs index 63382af..e22dc50 100644 --- a/src/ScriptBuilderTask.Tests/CSharpCodeGenerationTests.Generates.approved.cs +++ b/src/ScriptBuilderTask.Tests/CSharpCodeGenerationTests.Generates.approved.cs @@ -4,9 +4,9 @@ using System.Runtime.CompilerServices; [CompilerGenerated] -public static class CounterCreator +public static class CounterCreator { - public static void Create() + public static void Create() { var counterCreationCollection = new CounterCreationDataCollection(Counters); try @@ -36,7 +36,7 @@ public static void Create() PerformanceCounter.CloseSharedResources(); } - catch (Exception ex) when (ex is SecurityException || ex is UnauthorizedAccessException) + catch (Exception ex) when(ex is SecurityException || ex is UnauthorizedAccessException) { throw new Exception("Execution requires elevated permissions", ex); } @@ -45,11 +45,16 @@ public static void Create() static CounterCreationData[] Counters = new CounterCreationData[] { new CounterCreationData("SLA violation countdown", "Seconds until the SLA for this endpoint is breached.", PerformanceCounterType.NumberOfItems32), + new CounterCreationData("Critical Time Average", "The time it took from sending to processing the message.", PerformanceCounterType.AverageTimer32), + new CounterCreationData("Critical Time AverageBase", "The time it took from sending to processing the message.", PerformanceCounterType.AverageBase), new CounterCreationData("Critical Time", "The time it took from sending to processing the message.", PerformanceCounterType.NumberOfItems32), + new CounterCreationData("Processing Time Average", "The time it took to successfully process a message.", PerformanceCounterType.AverageTimer32), + new CounterCreationData("Processing Time AverageBase", "The time it took to successfully process a message.", PerformanceCounterType.AverageBase), new CounterCreationData("Processing Time", "The time it took to successfully process a message.", PerformanceCounterType.NumberOfItems32), - new CounterCreationData("# of msgs pulled from the input queue /sec", "The current number of messages pulled from the input queue by the transport per second.", PerformanceCounterType.RateOfCountsPerSecond32), new CounterCreationData("# of msgs failures / sec", "The current number of failed processed messages by the transport per second.", PerformanceCounterType.RateOfCountsPerSecond32), new CounterCreationData("# of msgs successfully processed / sec", "The current number of messages processed successfully by the transport per second.", PerformanceCounterType.RateOfCountsPerSecond32), + new CounterCreationData("# of msgs pulled from the input queue /sec", "The current number of messages pulled from the input queue by the transport per second.", PerformanceCounterType.RateOfCountsPerSecond32), + new CounterCreationData("Retries", "A message has been scheduled for retry (FLR or SLR)", PerformanceCounterType.RateOfCountsPerSecond32), }; } \ No newline at end of file diff --git a/src/ScriptBuilderTask.Tests/PowershellCodeGenerationTests.Generates.approved.ps1 b/src/ScriptBuilderTask.Tests/PowershellCodeGenerationTests.Generates.approved.ps1 index 8040fa7..53d1d67 100644 --- a/src/ScriptBuilderTask.Tests/PowershellCodeGenerationTests.Generates.approved.ps1 +++ b/src/ScriptBuilderTask.Tests/PowershellCodeGenerationTests.Generates.approved.ps1 @@ -1,3 +1,4 @@ + #requires -RunAsAdministrator Function InstallNSBPerfCounters { @@ -5,15 +6,21 @@ Function InstallNSBPerfCounters { $counters = New-Object System.Diagnostics.CounterCreationDataCollection $counters.AddRange(@( New-Object System.Diagnostics.CounterCreationData "SLA violation countdown", "Seconds until the SLA for this endpoint is breached.", NumberOfItems32 + New-Object System.Diagnostics.CounterCreationData "Critical Time Average", "The time it took from sending to processing the message.", AverageTimer32 + New-Object System.Diagnostics.CounterCreationData "Critical Time AverageBase", "The time it took from sending to processing the message.", AverageBase New-Object System.Diagnostics.CounterCreationData "Critical Time", "The time it took from sending to processing the message.", NumberOfItems32 + New-Object System.Diagnostics.CounterCreationData "Processing Time Average", "The time it took to successfully process a message.", AverageTimer32 + New-Object System.Diagnostics.CounterCreationData "Processing Time AverageBase", "The time it took to successfully process a message.", AverageBase New-Object System.Diagnostics.CounterCreationData "Processing Time", "The time it took to successfully process a message.", NumberOfItems32 - New-Object System.Diagnostics.CounterCreationData "# of msgs pulled from the input queue /sec", "The current number of messages pulled from the input queue by the transport per second.", RateOfCountsPerSecond32 New-Object System.Diagnostics.CounterCreationData "# of msgs failures / sec", "The current number of failed processed messages by the transport per second.", RateOfCountsPerSecond32 New-Object System.Diagnostics.CounterCreationData "# of msgs successfully processed / sec", "The current number of messages processed successfully by the transport per second.", RateOfCountsPerSecond32 + New-Object System.Diagnostics.CounterCreationData "# of msgs pulled from the input queue /sec", "The current number of messages pulled from the input queue by the transport per second.", RateOfCountsPerSecond32 + New-Object System.Diagnostics.CounterCreationData "Retries", "A message has been scheduled for retry (FLR or SLR)", RateOfCountsPerSecond32 )) if ([System.Diagnostics.PerformanceCounterCategory]::Exists($category.Name)) { + foreach($counter in $counters){ $exists = [System.Diagnostics.PerformanceCounterCategory]::CounterExists($counter.CounterName, $category.Name) if (!$exists){ @@ -28,11 +35,11 @@ Function InstallNSBPerfCounters { if (![System.Diagnostics.PerformanceCounterCategory]::Exists($category.Name)) { Write-Host "Creating the performance counter category" [void] [System.Diagnostics.PerformanceCounterCategory]::Create($category.Name, $category.Description, [System.Diagnostics.PerformanceCounterCategoryType]::MultiInstance, $counters) - } + } else { Write-Host "No performance counters have to be created" } [System.Diagnostics.PerformanceCounter]::CloseSharedResources() } -InstallNSBPerfCounters \ No newline at end of file +InstallNSBPerfCounters diff --git a/src/ScriptBuilderTask.Tests/PowershellCodeGenerationTests.cs b/src/ScriptBuilderTask.Tests/PowershellCodeGenerationTests.cs index c4832f1..aca44c6 100644 --- a/src/ScriptBuilderTask.Tests/PowershellCodeGenerationTests.cs +++ b/src/ScriptBuilderTask.Tests/PowershellCodeGenerationTests.cs @@ -35,6 +35,8 @@ public void SetUp() [MethodImpl(MethodImplOptions.NoInlining)] public void Generates() { + GenericDiffReporter.RegisterTextFileTypes(".ps1"); + task.Execute(); GenericDiffReporter.RegisterTextFileTypes(".ps1"); diff --git a/src/ScriptBuilderTask.Tests/ScriptBuilderTask.Tests.csproj b/src/ScriptBuilderTask.Tests/ScriptBuilderTask.Tests.csproj index e03e465..508f07b 100644 --- a/src/ScriptBuilderTask.Tests/ScriptBuilderTask.Tests.csproj +++ b/src/ScriptBuilderTask.Tests/ScriptBuilderTask.Tests.csproj @@ -1,72 +1,32 @@ - - - + + - Debug - AnyCPU - {8174164E-52B8-4878-BFB0-34C81A31930E} - Library - Properties - ScriptBuilderTask.Tests - ScriptBuilderTask.Tests - v4.5.2 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 + net452 + true + $(SolutionDir)NServiceBus.snk + + + + + - - ..\packages\ApprovalTests.3.0.13\lib\net40\ApprovalTests.dll - - - ..\packages\ApprovalUtilities.3.0.13\lib\net45\ApprovalUtilities.dll - - - ..\packages\ApprovalUtilities.3.0.13\lib\net45\ApprovalUtilities.Net45.dll - - - ..\packages\NServiceBus.6.3.4\lib\net452\NServiceBus.Core.dll - - - ..\packages\NServiceBus.Metrics.1.0.1\lib\net452\NServiceBus.Metrics.dll - - - ..\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll - - - - + - - - - + - - + + + + + + - - {08fd76cb-6988-485a-a535-b3129af89c60} - ScriptBuilderTask - + + - + \ No newline at end of file diff --git a/src/ScriptBuilderTask.Tests/packages.config b/src/ScriptBuilderTask.Tests/packages.config deleted file mode 100644 index ed9da01..0000000 --- a/src/ScriptBuilderTask.Tests/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/ScriptBuilderTask/AssemblyInfo.cs b/src/ScriptBuilderTask/AssemblyInfo.cs deleted file mode 100644 index d422713..0000000 --- a/src/ScriptBuilderTask/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("NServiceBus.Metrics.PerformanceCounters.Task")] -[assembly: AssemblyProduct("NServiceBus.Metrics.PerformanceCounters.Task")] diff --git a/src/ScriptBuilder/BuildScriptVariant.cs b/src/ScriptBuilderTask/BuildScriptVariant.cs similarity index 100% rename from src/ScriptBuilder/BuildScriptVariant.cs rename to src/ScriptBuilderTask/BuildScriptVariant.cs diff --git a/src/ScriptBuilderTask/CSharpCounterWriter.cs b/src/ScriptBuilderTask/CSharpCounterWriter.cs new file mode 100644 index 0000000..22d2459 --- /dev/null +++ b/src/ScriptBuilderTask/CSharpCounterWriter.cs @@ -0,0 +1,99 @@ +namespace NServiceBus.Metrics.PerformanceCounters +{ + using System.Collections.Generic; + using System.IO; + using System.Text; + + static class CSharpCounterWriter + { + public static void WriteCode(string scriptPath, IEnumerable durations, IEnumerable signals, Dictionary legacyInstanceNameMap) + { + var outputPath = Path.Combine(scriptPath, "Counters.g.cs"); + using (var streamWriter = File.CreateText(outputPath)) + { + var stringBuilder = new StringBuilder(); + + var slaCounterDefinition = @"new CounterCreationData(""SLA violation countdown"", ""Seconds until the SLA for this endpoint is breached."", PerformanceCounterType.NumberOfItems32),"; + stringBuilder.AppendLine(slaCounterDefinition.PadLeft(slaCounterDefinition.Length + 8)); + + foreach (var duration in durations) + { + var averageTimerName = duration.Name.GetAverageTimerCounterName(); + var averageTimerBase = duration.Name.GetAverageTimerBaseCounterName(); + + var durationAverageDefinition = $@"new CounterCreationData(""{averageTimerName}"", ""{duration.Description}"", PerformanceCounterType.AverageTimer32),"; + stringBuilder.AppendLine(durationAverageDefinition.PadLeft(durationAverageDefinition.Length + 8)); + + var durationBaseDefinition = $@"new CounterCreationData(""{averageTimerBase}"", ""{duration.Description}"", PerformanceCounterType.AverageBase),"; + stringBuilder.AppendLine(durationBaseDefinition.PadLeft(durationBaseDefinition.Length + 8)); + + if (duration.Name == CounterNameConventions.ProcessingTime || duration.Name == CounterNameConventions.CriticalTime) + { + var legacyTimerDefinition = $@"new CounterCreationData(""{duration.Name}"", ""{duration.Description}"", PerformanceCounterType.NumberOfItems32),"; + stringBuilder.AppendLine(legacyTimerDefinition.PadLeft(legacyTimerDefinition.Length + 8)); + } + } + + foreach (var signal in signals) + { + legacyInstanceNameMap.TryGetValue(signal.Name, out var instanceName); + + var signalDefinition = $@"new CounterCreationData(""{instanceName ?? signal.Name}"", ""{signal.Description}"", PerformanceCounterType.RateOfCountsPerSecond32),"; + stringBuilder.AppendLine(signalDefinition.PadLeft(signalDefinition.Length + 8)); + } + + streamWriter.Write(Template, stringBuilder); + } + } + + const string Template = @"using System; +using System.Diagnostics; +using System.Security; +using System.Runtime.CompilerServices; + +[CompilerGenerated] +public static class CounterCreator +{{ + public static void Create() + {{ + var counterCreationCollection = new CounterCreationDataCollection(Counters); + try + {{ + var categoryName = ""NServiceBus""; + + if (PerformanceCounterCategory.Exists(categoryName)) + {{ + foreach (CounterCreationData counter in counterCreationCollection) + {{ + if (!PerformanceCounterCategory.CounterExists(counter.CounterName, categoryName)) + {{ + PerformanceCounterCategory.Delete(categoryName); + break; + }} + }} + }} + + if (PerformanceCounterCategory.Exists(categoryName) == false) + {{ + PerformanceCounterCategory.Create( + categoryName: categoryName, + categoryHelp: ""NServiceBus statistics"", + categoryType: PerformanceCounterCategoryType.MultiInstance, + counterData: counterCreationCollection); + }} + + PerformanceCounter.CloseSharedResources(); + }} + catch (Exception ex) when(ex is SecurityException || ex is UnauthorizedAccessException) + {{ + throw new Exception(""Execution requires elevated permissions"", ex); + }} + }} + + static CounterCreationData[] Counters = new CounterCreationData[] + {{ +{0} + }}; +}}"; + } +} \ No newline at end of file diff --git a/src/ScriptBuilder/CecilExtensions.cs b/src/ScriptBuilderTask/CecilExtensions.cs similarity index 86% rename from src/ScriptBuilder/CecilExtensions.cs rename to src/ScriptBuilderTask/CecilExtensions.cs index c9d8ab0..01eebd2 100644 --- a/src/ScriptBuilder/CecilExtensions.cs +++ b/src/ScriptBuilderTask/CecilExtensions.cs @@ -47,10 +47,20 @@ public static IEnumerable AllClasses(this ModuleDefinition modul .Where(x => x.IsClass); } + public static string GetFileName(this TypeDefinition type) { foreach (var method in type.Methods) { + var debugInformation = method.DebugInformation; + if (debugInformation == null) + { + continue; + } + if (!debugInformation.HasSequencePoints != true) + { + continue; + } var body = method.Body; if (body?.Instructions == null) { @@ -58,7 +68,7 @@ public static string GetFileName(this TypeDefinition type) } foreach (var instruction in body.Instructions) { - var point = instruction.SequencePoint; + var point = debugInformation.GetSequencePoint(instruction); if (point?.Document?.Url == null) { continue; diff --git a/src/ScriptBuilderTask/CounterNameConventions.cs b/src/ScriptBuilderTask/CounterNameConventions.cs new file mode 100644 index 0000000..9a4a687 --- /dev/null +++ b/src/ScriptBuilderTask/CounterNameConventions.cs @@ -0,0 +1,18 @@ +namespace NServiceBus.Metrics.PerformanceCounters +{ + static class CounterNameConventions + { + public static string GetAverageTimerCounterName(this string durationName) + { + return $"{durationName} Average"; + } + + public static string GetAverageTimerBaseCounterName(this string durationName) + { + return $"{durationName} AverageBase"; + } + + public const string ProcessingTime = "Processing Time"; + public const string CriticalTime = "Critical Time"; + } +} \ No newline at end of file diff --git a/src/ScriptBuilder/CounterWriter.cs b/src/ScriptBuilderTask/CounterWriter.cs similarity index 89% rename from src/ScriptBuilder/CounterWriter.cs rename to src/ScriptBuilderTask/CounterWriter.cs index cadf1fb..d3bdab2 100644 --- a/src/ScriptBuilder/CounterWriter.cs +++ b/src/ScriptBuilderTask/CounterWriter.cs @@ -8,12 +8,12 @@ public static class CounterWriter { public static void WriteScript(string scriptPath, BuildScriptVariant variant, ModuleDefinition module, Action logError) { - var timers = AllTimersDefinitionReader.GetTimers(module, (exception, type) => + var timers = AllDurationsDefinitionReader.GetDurations(module, (exception, type) => { logError($"Error in '{type.FullName}'. Error:{exception.Message}", type.GetFileName()); }); - var meters = AllMetersDefinitionReader.GetMeters(module, (exception, type) => + var meters = AllSignalsDefinitionReader.GetSignals(module, (exception, type) => { logError($"Error in '{type.FullName}'. Error:{exception.Message}", type.GetFileName()); }); diff --git a/src/ScriptBuilder/Timers/AllTimersDefinitionReader.cs b/src/ScriptBuilderTask/Durations/AllDurationsDefinitionReader.cs similarity index 60% rename from src/ScriptBuilder/Timers/AllTimersDefinitionReader.cs rename to src/ScriptBuilderTask/Durations/AllDurationsDefinitionReader.cs index 803c88e..6220f5a 100644 --- a/src/ScriptBuilder/Timers/AllTimersDefinitionReader.cs +++ b/src/ScriptBuilderTask/Durations/AllDurationsDefinitionReader.cs @@ -4,17 +4,16 @@ using System.Collections.Generic; using Mono.Cecil; - static class AllTimersDefinitionReader + static class AllDurationsDefinitionReader { - public static IEnumerable GetTimers(ModuleDefinition module, Action logError) + public static IEnumerable GetDurations(ModuleDefinition module, Action logError) { - var timerDefinitions = new List(); + var timerDefinitions = new List(); foreach (var type in module.AllClasses()) { try { - List definition; - if (TimerDefinitionReader.TryGetTimerDefinition(type, out definition)) + if (DurationDefinitionReader.TryGetDurationDefinition(type, out var definition)) { timerDefinitions.AddRange(definition); } diff --git a/src/ScriptBuilder/Timers/TimerDefinition.cs b/src/ScriptBuilderTask/Durations/DurationDefinition.cs similarity index 70% rename from src/ScriptBuilder/Timers/TimerDefinition.cs rename to src/ScriptBuilderTask/Durations/DurationDefinition.cs index 719f7ff..86ee1df 100644 --- a/src/ScriptBuilder/Timers/TimerDefinition.cs +++ b/src/ScriptBuilderTask/Durations/DurationDefinition.cs @@ -1,8 +1,8 @@ namespace NServiceBus.Metrics.PerformanceCounters { - class TimerDefinition + class DurationDefinition { - public TimerDefinition(string name, string description) + public DurationDefinition(string name, string description) { Name = name; Description = description; diff --git a/src/ScriptBuilder/Meters/MeterDefinitionReader.cs b/src/ScriptBuilderTask/Durations/DurationDefinitionReader.cs similarity index 52% rename from src/ScriptBuilder/Meters/MeterDefinitionReader.cs rename to src/ScriptBuilderTask/Durations/DurationDefinitionReader.cs index 2f1bc56..5a38e35 100644 --- a/src/ScriptBuilder/Meters/MeterDefinitionReader.cs +++ b/src/ScriptBuilderTask/Durations/DurationDefinitionReader.cs @@ -4,22 +4,21 @@ using System.Linq; using Mono.Cecil; - static class MeterDefinitionReader + static class DurationDefinitionReader { - public static bool TryGetMeterDefinition(TypeDefinition type, out List definitions) + public static bool TryGetDurationDefinition(TypeDefinition type, out List definitions) { - definitions = new List(); - if (type.BaseType != null && type.BaseType.FullName == "NServiceBus.Metrics.MetricBuilder") + definitions = new List(); + if (type.BaseType != null && type.BaseType.FullName == "DurationProbeBuilder") { - var attributes = type.Fields - .Select(f => f.GetSingleAttribute("NServiceBus.Metrics.MeterAttribute")) - .Where(c => c != null); + var attributes = type.CustomAttributes.Where(a => a.AttributeType.FullName == "ProbePropertiesAttribute"); foreach (var attribute in attributes) { var name = attribute.ParameterValue("name"); var description = attribute.ParameterValue("description"); - definitions.Add(new MeterDefinition(name, description)); + + definitions.Add(new DurationDefinition(name, description)); } } return definitions.Count > 0; diff --git a/src/ScriptBuilder/ErrorsException.cs b/src/ScriptBuilderTask/ErrorsException.cs similarity index 100% rename from src/ScriptBuilder/ErrorsException.cs rename to src/ScriptBuilderTask/ErrorsException.cs diff --git a/src/ScriptBuilderTask/ExceptionExtensions.cs b/src/ScriptBuilderTask/ExceptionExtensions.cs index eeb3417..de0bcf6 100644 --- a/src/ScriptBuilderTask/ExceptionExtensions.cs +++ b/src/ScriptBuilderTask/ExceptionExtensions.cs @@ -40,14 +40,6 @@ public static string ToFriendlyString(this Exception exception) stringBuilder.Append(Environment.NewLine); } - if (exception.TargetSite != null) - { - stringBuilder.Append("TargetSite:"); - stringBuilder.Append(Environment.NewLine); - stringBuilder.Append(exception.TargetSite); - stringBuilder.Append(Environment.NewLine); - } - exception = exception.InnerException; } diff --git a/src/ScriptBuilderTask/InnerTask.cs b/src/ScriptBuilderTask/InnerTask.cs index e64ce15..62e83aa 100644 --- a/src/ScriptBuilderTask/InnerTask.cs +++ b/src/ScriptBuilderTask/InnerTask.cs @@ -37,8 +37,7 @@ public void Execute() void PromoteFiles(ModuleDefinition moduleDefinition, string scriptPath) { - string customPath; - if (!ScriptPromotionPathReader.TryRead(moduleDefinition, out customPath)) + if (!ScriptPromotionPathReader.TryRead(moduleDefinition, out var customPath)) { return; } diff --git a/packaging/nuget/NServiceBus.Metrics.PerformanceCounters.MsBuild.nuspec b/src/ScriptBuilderTask/NServiceBus.Metrics.PerformanceCounters.MsBuild.nuspec similarity index 60% rename from packaging/nuget/NServiceBus.Metrics.PerformanceCounters.MsBuild.nuspec rename to src/ScriptBuilderTask/NServiceBus.Metrics.PerformanceCounters.MsBuild.nuspec index 6277bb2..b7fd5ae 100644 --- a/packaging/nuget/NServiceBus.Metrics.PerformanceCounters.MsBuild.nuspec +++ b/src/ScriptBuilderTask/NServiceBus.Metrics.PerformanceCounters.MsBuild.nuspec @@ -1,9 +1,8 @@ - NServiceBus.Metrics.PerformanceCounters.MsBuild + $id$ $version$ - NServiceBus.Metrics.PerformanceCounters.MsBuild $authors$ $owners$ true @@ -11,7 +10,7 @@ $projectUrl$ $requireLicenseAcceptance$ $iconUrl$ - MsBuild Task for building deployment scripts for the NServiceBus.Metrics.PerformanceCounters package. + $description$ $copyright$ $tags$ @@ -19,7 +18,8 @@ - - + + + diff --git a/packaging/nuget/NServiceBus.Metrics.PerformanceCounters.MsBuild.targets b/src/ScriptBuilderTask/NServiceBus.Metrics.PerformanceCounters.MsBuild.targets similarity index 63% rename from packaging/nuget/NServiceBus.Metrics.PerformanceCounters.MsBuild.targets rename to src/ScriptBuilderTask/NServiceBus.Metrics.PerformanceCounters.MsBuild.targets index 9afa68e..8bf8673 100644 --- a/packaging/nuget/NServiceBus.Metrics.PerformanceCounters.MsBuild.targets +++ b/src/ScriptBuilderTask/NServiceBus.Metrics.PerformanceCounters.MsBuild.targets @@ -1,16 +1,29 @@  - - $(ProjectDir)$(IntermediateOutputPath)NServiceBus.Metrics.PerformanceCounters\ - + + + + $(MSBuildThisFileDirectory)..\netstandard\NServiceBus.Metrics.PerformanceCounters.Task.dll + + + + + $(MSBuildThisFileDirectory)..\netclassic\NServiceBus.Metrics.PerformanceCounters.Task.dll + + + + AssemblyFile="$(ScriptBuilderTaskPath)" /> + Name="PerformanceCountersScriptBuilder" + Condition="'$(DesignTimeBuild)' != 'true'"> + + $(ProjectDir)$(IntermediateOutputPath)NServiceBus.Metrics.PerformanceCounters\ + - + + Name="AddScriptsToGetCopyToOutputDirectoryItems" + Condition="'$(DesignTimeBuild)' != 'true'"> diff --git a/src/ScriptBuilderTask/PowerShellCounterWriter.cs b/src/ScriptBuilderTask/PowerShellCounterWriter.cs new file mode 100644 index 0000000..461e338 --- /dev/null +++ b/src/ScriptBuilderTask/PowerShellCounterWriter.cs @@ -0,0 +1,85 @@ +namespace NServiceBus.Metrics.PerformanceCounters +{ + using System.Collections.Generic; + using System.IO; + using System.Text; + + static class PowerShellCounterWriter + { + public static void WriteScript(string scriptPath, IEnumerable durations, IEnumerable signals, Dictionary legacyInstanceNameMap) + { + var outputPath = Path.Combine(scriptPath, "CreateNSBPerfCounters.ps1"); + using (var streamWriter = File.CreateText(outputPath)) + { + var stringBuilder = new StringBuilder(); + + var slaCounterDefinition = @"New-Object System.Diagnostics.CounterCreationData ""SLA violation countdown"", ""Seconds until the SLA for this endpoint is breached."", NumberOfItems32"; + stringBuilder.AppendLine(slaCounterDefinition.PadLeft(slaCounterDefinition.Length + 8)); + + foreach (var duration in durations) + { + var averageTimerName = duration.Name.GetAverageTimerCounterName(); + var averageTimerBase = duration.Name.GetAverageTimerBaseCounterName(); + + var durationAverageDefinition = $@"New-Object System.Diagnostics.CounterCreationData ""{averageTimerName}"", ""{duration.Description}"", AverageTimer32"; + stringBuilder.AppendLine(durationAverageDefinition.PadLeft(durationAverageDefinition.Length + 8)); + + var durationBaseDefinition = $@"New-Object System.Diagnostics.CounterCreationData ""{averageTimerBase}"", ""{duration.Description}"", AverageBase"; + stringBuilder.AppendLine(durationBaseDefinition.PadLeft(durationBaseDefinition.Length + 8)); + + if (duration.Name == CounterNameConventions.ProcessingTime || duration.Name == CounterNameConventions.CriticalTime) + { + var legacyTimerDefinition = $@"New-Object System.Diagnostics.CounterCreationData ""{duration.Name}"", ""{duration.Description}"", NumberOfItems32"; + stringBuilder.AppendLine(legacyTimerDefinition.PadLeft(legacyTimerDefinition.Length + 8)); + } + } + + foreach (var signal in signals) + { + legacyInstanceNameMap.TryGetValue(signal.Name, out var instanceName); + + var signalDefinition = $@"New-Object System.Diagnostics.CounterCreationData ""{instanceName ?? signal.Name}"", ""{signal.Description}"", RateOfCountsPerSecond32"; + stringBuilder.AppendLine(signalDefinition.PadLeft(signalDefinition.Length + 8)); + } + + streamWriter.Write(Template, stringBuilder); + } + } + + const string Template = @" +#requires -RunAsAdministrator +Function InstallNSBPerfCounters {{ + + $category = @{{Name=""NServiceBus""; Description=""NServiceBus statistics""}} + $counters = New-Object System.Diagnostics.CounterCreationDataCollection + $counters.AddRange(@( +{0} + )) + + if ([System.Diagnostics.PerformanceCounterCategory]::Exists($category.Name)) {{ + + foreach($counter in $counters){{ + $exists = [System.Diagnostics.PerformanceCounterCategory]::CounterExists($counter.CounterName, $category.Name) + if (!$exists){{ + Write-Host ""One or more counters are missing.The performance counter category will be recreated"" + [System.Diagnostics.PerformanceCounterCategory]::Delete($category.Name) + + break + }} + }} + }} + + if (![System.Diagnostics.PerformanceCounterCategory]::Exists($category.Name)) {{ + Write-Host ""Creating the performance counter category"" + [void] [System.Diagnostics.PerformanceCounterCategory]::Create($category.Name, $category.Description, [System.Diagnostics.PerformanceCounterCategoryType]::MultiInstance, $counters) + }} + else {{ + Write-Host ""No performance counters have to be created"" + }} + + [System.Diagnostics.PerformanceCounter]::CloseSharedResources() +}} +InstallNSBPerfCounters +"; + } +} \ No newline at end of file diff --git a/src/ScriptBuilderTask/ScriptBuilderTask.cs b/src/ScriptBuilderTask/ScriptBuilderTask.cs index 1bf2863..215a37c 100644 --- a/src/ScriptBuilderTask/ScriptBuilderTask.cs +++ b/src/ScriptBuilderTask/ScriptBuilderTask.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.IO; using System.Linq; + using System.Reflection; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -28,17 +29,17 @@ public class ScriptBuilderTask : Task [Required] public string SolutionDirectory { get; set; } - public Dictionary ReferenceDictionary { get; } = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + public Dictionary ReferenceDictionary { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public override bool Execute() { logger = new BuildLogger(BuildEngine); - logger.LogInfo($"ScriptBuilderTask (version {typeof(ScriptBuilderTask).Assembly.GetName().Version}) Executing"); + logger.LogInfo($"ScriptBuilderTask (version {typeof(ScriptBuilderTask).GetTypeInfo().Assembly.GetName().Version}) Executing"); var stopwatch = Stopwatch.StartNew(); var referenceCopyLocalPaths = ReferenceCopyLocalPaths.Select(x => x.ItemSpec); - var splitReferences = References.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Union(referenceCopyLocalPaths, StringComparer.InvariantCultureIgnoreCase); + var splitReferences = References.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Union(referenceCopyLocalPaths, StringComparer.OrdinalIgnoreCase); foreach (var filePath in splitReferences) { var fileNameWithExtension = Path.GetFileName(filePath); @@ -92,8 +93,7 @@ void ValidateInputs() throw new ErrorsException($"SolutionDirectory '{SolutionDirectory}' does not exist."); } - string filePath; - if (!ReferenceDictionary.TryGetValue("NServiceBus.Metrics.dll", out filePath)) + if (!ReferenceDictionary.TryGetValue("NServiceBus.Metrics.dll", out _)) { throw new ErrorsException("NServiceBus.Metrics.dll is not referenced in this assembly."); } diff --git a/src/ScriptBuilderTask/ScriptBuilderTask.csproj b/src/ScriptBuilderTask/ScriptBuilderTask.csproj index e8bee3e..6f792a2 100644 --- a/src/ScriptBuilderTask/ScriptBuilderTask.csproj +++ b/src/ScriptBuilderTask/ScriptBuilderTask.csproj @@ -1,103 +1,65 @@ - - - + + - Debug - AnyCPU - {08FD76CB-6988-485A-A535-B3129AF89C60} - Library - Properties - NServiceBus.Metrics.PerformanceCounters - NServiceBus.Metrics.PerformanceCounters.Task - v4.5.2 - 512 - NServiceBus.Metrics.PerformanceCounters.MsBuild + net452;netstandard1.5 true + NServiceBus.Metrics.PerformanceCounters.Task $(SolutionDir)NServiceBus.snk + ..\..\binaries\ + $(NoWarn);CS1591 - - true - full - false - bin\Debug - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release - TRACE - prompt - 4 - + + + + + + + + - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll - - - - - - - - - - - - - - - {1BDA0A75-91F6-4412-A780-7BE9322B2A4E} - ScriptBuilder - True - - - - - Designer - + + + + + + - - - + + + NServiceBus.Metrics.PerformanceCounters.MsBuild + MsBuild Task for building deployment scripts for the NServiceBus.Metrics.PerformanceCounters package. + $(MSBuildThisFileDirectory)$(PackageId).nuspec + true + + + - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + id=$(PackageId);version=$(PackageVersion);authors=$(Authors);owners=$(Authors);licenseUrl=$(PackageLicenseUrl);requireLicenseAcceptance=$(PackageRequireLicenseAcceptance);iconUrl=$(PackageIconUrl);projectUrl=$(PackageProjectUrl);description=$(Description);copyright=$(Copyright);tags=$(PackageTags) - - - - + + + + true + + + - "$(SolutionDir)..\Tools\ilmerge.exe" - $(ProjectDir)bin\$(ConfigurationName)\NServiceBus.Metrics.PerformanceCounters.Builder.dll - $(ProjectDir)bin\$(ConfigurationName)\NServiceBus.Metrics.PerformanceCounters.Task.dll - $(ProjectDir)bin\$(ConfigurationName)\Mono.Cecil.dll - $(SolutionDir)..\binaries\NServiceBus.Metrics.PerformanceCounters.Task.dll - $(SolutionDir)..\binaries\NServiceBus.Metrics.PerformanceCounters.Task.pdb - $(SolutionDir)..\packaging\nuget\NServiceBus.Metrics.PerformanceCounters.MsBuild.targets + $(ProjectDir)$(OutputPath)temp - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/src/ScriptBuilder/ScriptPromotionPathReader.cs b/src/ScriptBuilderTask/ScriptPromotionPathReader.cs similarity index 100% rename from src/ScriptBuilder/ScriptPromotionPathReader.cs rename to src/ScriptBuilderTask/ScriptPromotionPathReader.cs diff --git a/src/ScriptBuilder/ScriptVariantReader.cs b/src/ScriptBuilderTask/ScriptVariantReader.cs similarity index 100% rename from src/ScriptBuilder/ScriptVariantReader.cs rename to src/ScriptBuilderTask/ScriptVariantReader.cs diff --git a/src/ScriptBuilder/Meters/AllMetersDefinitionReader.cs b/src/ScriptBuilderTask/Signals/AllSignalsDefinitionReader.cs similarity index 60% rename from src/ScriptBuilder/Meters/AllMetersDefinitionReader.cs rename to src/ScriptBuilderTask/Signals/AllSignalsDefinitionReader.cs index 1dbecef..6b1be48 100644 --- a/src/ScriptBuilder/Meters/AllMetersDefinitionReader.cs +++ b/src/ScriptBuilderTask/Signals/AllSignalsDefinitionReader.cs @@ -4,17 +4,16 @@ using System.Collections.Generic; using Mono.Cecil; - static class AllMetersDefinitionReader + static class AllSignalsDefinitionReader { - public static IEnumerable GetMeters(ModuleDefinition module, Action logError) + public static IEnumerable GetSignals(ModuleDefinition module, Action logError) { - var timerDefinitions = new List(); + var timerDefinitions = new List(); foreach (var type in module.AllClasses()) { try { - List definition; - if (MeterDefinitionReader.TryGetMeterDefinition(type, out definition)) + if (SignalDefinitionReader.TryGetSignalDefinition(type, out var definition)) { timerDefinitions.AddRange(definition); } diff --git a/src/ScriptBuilder/Meters/MeterDefinition.cs b/src/ScriptBuilderTask/Signals/SignalDefinition.cs similarity index 71% rename from src/ScriptBuilder/Meters/MeterDefinition.cs rename to src/ScriptBuilderTask/Signals/SignalDefinition.cs index eb6369e..4a8ee3c 100644 --- a/src/ScriptBuilder/Meters/MeterDefinition.cs +++ b/src/ScriptBuilderTask/Signals/SignalDefinition.cs @@ -1,8 +1,8 @@ namespace NServiceBus.Metrics.PerformanceCounters { - class MeterDefinition + class SignalDefinition { - public MeterDefinition(string name, string description) + public SignalDefinition(string name, string description) { Name = name; Description = description; diff --git a/src/ScriptBuilderTask/Signals/SignalDefinitionReader.cs b/src/ScriptBuilderTask/Signals/SignalDefinitionReader.cs new file mode 100644 index 0000000..76e7693 --- /dev/null +++ b/src/ScriptBuilderTask/Signals/SignalDefinitionReader.cs @@ -0,0 +1,26 @@ +namespace NServiceBus.Metrics.PerformanceCounters +{ + using System.Collections.Generic; + using System.Linq; + using Mono.Cecil; + + static class SignalDefinitionReader + { + public static bool TryGetSignalDefinition(TypeDefinition type, out List definitions) + { + definitions = new List(); + if (type.BaseType != null && type.BaseType.FullName == "SignalProbeBuilder") + { + var attributes = type.CustomAttributes.Where(a => a.AttributeType.FullName == "ProbePropertiesAttribute"); + + foreach (var attribute in attributes) + { + var name = attribute.ParameterValue("name"); + var description = attribute.ParameterValue("description"); + definitions.Add(new SignalDefinition(name, description)); + } + } + return definitions.Count > 0; + } + } +} \ No newline at end of file diff --git a/src/ScriptBuilderTask/packages.config b/src/ScriptBuilderTask/packages.config deleted file mode 100644 index d6cd986..0000000 --- a/src/ScriptBuilderTask/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/nuget.config b/src/nuget.config index 9f16f77..b6d57e1 100644 --- a/src/nuget.config +++ b/src/nuget.config @@ -9,7 +9,6 @@ - diff --git a/tools/ILMerge.exe b/tools/ILMerge.exe deleted file mode 100644 index e401808..0000000 Binary files a/tools/ILMerge.exe and /dev/null differ