From 92b930d016a6444f4bd41c3a02ddb0f255993949 Mon Sep 17 00:00:00 2001 From: mayankbansal018 Date: Tue, 7 Feb 2017 14:17:12 +0530 Subject: [PATCH] Migration to netstandard 1.4 (#406) * Migration to netstandard 1.4 1. Migrating CoreUtilites to netstandard1.4 2. Adding a platform abstraction layer, to implement platform specific requirements * removing additional IEqtTrace.cs * Throw exception if file name empty * Modifying Sln to stop build break * Missed changes * Making EqtTrace.TraceLevel available as public, & Test error fixes * adding test for EqtTrace --- TestPlatform.sln | 20 +- scripts/build.ps1 | 23 +- ...icrosoft.TestPlatform.CoreUtilities.csproj | Bin 4780 -> 1936 bytes .../Tracing/EqtTrace.cs | 456 +++--------------- ...rosoft.TestPlatform.CrossPlatEngine.csproj | 3 + .../Microsoft.TestPlatform.ObjectModel.csproj | Bin 8124 -> 8354 bytes .../Interfaces/Tracing/IEqtTrace.cs | 74 +++ ...t.TestPlatform.PlatformAbstractions.csproj | Bin 0 -> 4256 bytes .../common/Tracing/EqtTrace.cs | 368 ++++++++++++++ .../Tracing/RollingFileTraceListener.cs | 5 +- .../net46/Interfaces/Tracing/IEqtTrace.cs | 26 + .../net46/Tracing/EqtTrace.cs | 72 +++ .../net46}/Tracing/RemoteEqtTrace.cs | 8 +- .../netstandard1.0/Tracing/EqtTrace.cs | 54 +++ src/TestPlatform.ObjectModel.nuspec | 2 + src/TestPlatform.TranslationLayer.nuspec | 2 + ...estPlatform.CoreUtilities.UnitTests.csproj | 14 + .../Tracing/EqtTraceTests.cs | 155 ++++++ .../Client/ProxyOperationManagerTests.cs | 4 + .../EnableDiagArgumentProcessorTests.cs | 14 + 20 files changed, 900 insertions(+), 400 deletions(-) create mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/Interfaces/Tracing/IEqtTrace.cs create mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/Microsoft.TestPlatform.PlatformAbstractions.csproj create mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/common/Tracing/EqtTrace.cs rename src/{Microsoft.TestPlatform.CoreUtilities => Microsoft.TestPlatform.PlatformAbstractions/common}/Tracing/RollingFileTraceListener.cs (98%) create mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/net46/Interfaces/Tracing/IEqtTrace.cs create mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/net46/Tracing/EqtTrace.cs rename src/{Microsoft.TestPlatform.CoreUtilities => Microsoft.TestPlatform.PlatformAbstractions/net46}/Tracing/RemoteEqtTrace.cs (87%) create mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/Tracing/EqtTrace.cs create mode 100644 test/Microsoft.TestPlatform.CoreUtilities.UnitTests/Tracing/EqtTraceTests.cs diff --git a/TestPlatform.sln b/TestPlatform.sln index 1ec85c83de..8fa37dece3 100644 --- a/TestPlatform.sln +++ b/TestPlatform.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 +VisualStudioVersion = 15.0.26127.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED0C35EB-7F31-4841-A24F-8EB708FFA959}" EndProject @@ -124,8 +124,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleTestProject3", "test\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "datacollector.UnitTests", "test\datacollector.UnitTests\datacollector.UnitTests.csproj", "{0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.PlatformAbstractions", "src\Microsoft.TestPlatform.PlatformAbstractions\Microsoft.TestPlatform.PlatformAbstractions.csproj", "{CAE652AF-6801-425E-AAF3-AB20DE7DF88E}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "datacollector.PlatformTests", "test\datacollector.PlatformTests\datacollector.PlatformTests.csproj", "{FF80D706-8309-4E02-BAC0-D28B4CBCF600}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platform", "Platform", "{7D4082EA-7AC9-4DFB-98E8-C5E08BDC0EC3}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OutOfProcDataCollector", "test\TestAssets\OutOfProcDataCollector\OutOfProcDataCollector.csproj", "{CB6FA3C6-38E2-4DD1-AAB7-A705EFE114BC}" EndProject Global @@ -690,6 +694,18 @@ Global {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Release|x64.Build.0 = Release|x64 {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Release|x86.ActiveCfg = Release|x86 {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Release|x86.Build.0 = Release|x86 + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Debug|x64.ActiveCfg = Debug|x64 + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Debug|x64.Build.0 = Debug|x64 + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Debug|x86.ActiveCfg = Debug|x86 + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Debug|x86.Build.0 = Debug|x86 + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Release|Any CPU.Build.0 = Release|Any CPU + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Release|x64.ActiveCfg = Release|x64 + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Release|x64.Build.0 = Release|x64 + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Release|x86.ActiveCfg = Release|x86 + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E}.Release|x86.Build.0 = Release|x86 {FF80D706-8309-4E02-BAC0-D28B4CBCF600}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FF80D706-8309-4E02-BAC0-D28B4CBCF600}.Debug|Any CPU.Build.0 = Debug|Any CPU {FF80D706-8309-4E02-BAC0-D28B4CBCF600}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -771,6 +787,8 @@ Global {0D85D957-6FF2-4620-B766-B708801D97F3} = {8DA7CBD9-F17E-41B6-90C4-CFF55848A25A} {9549C1A4-CB57-4689-B3EB-F752F65F863F} = {8DA7CBD9-F17E-41B6-90C4-CFF55848A25A} {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} + {CAE652AF-6801-425E-AAF3-AB20DE7DF88E} = {7D4082EA-7AC9-4DFB-98E8-C5E08BDC0EC3} + {7D4082EA-7AC9-4DFB-98E8-C5E08BDC0EC3} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} {FF80D706-8309-4E02-BAC0-D28B4CBCF600} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} {CB6FA3C6-38E2-4DD1-AAB7-A705EFE114BC} = {8DA7CBD9-F17E-41B6-90C4-CFF55848A25A} EndGlobalSection diff --git a/scripts/build.ps1 b/scripts/build.ps1 index fd7a02314c..b907f1c65f 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -195,6 +195,7 @@ function Publish-Package $dataCollectorProject = Join-Path $env:TP_ROOT_DIR "src\datacollector\datacollector.csproj" Write-Log "Package: Publish package\*.csproj" + Publish-Package-Internal $packageProject $TPB_TargetFramework $fullCLRPackageDir Publish-Package-Internal $packageProject $TPB_TargetFrameworkCore $coreCLRPackageDir @@ -245,7 +246,7 @@ function Publish-Package foreach($file in $loggers) { Write-Verbose "Move-Item $fullCLRPackageDir\$file $fullCLRExtensionsDir -Force" Move-Item $fullCLRPackageDir\$file $fullCLRExtensionsDir -Force - + Write-Verbose "Move-Item $coreCLRPackageDir\$file $coreCLRExtensionsDir -Force" Move-Item $coreCLRPackageDir\$file $coreCLRExtensionsDir -Force } @@ -254,6 +255,26 @@ function Publish-Package Copy-PackageItems "Microsoft.TestPlatform.Build" Write-Log "Publish-Package: Complete. {$(Get-ElapsedTime($timer))}" + + Publish-PlatfromAbstractions-Internal +} + +function Publish-PlatfromAbstractions-Internal +{ + Write-Log "Publish-PlatfromAbstractions-Internal: Started." + + $timer = Start-Timer + $fullCLRPackageDir = Get-FullCLRPackageDirectory + $coreCLRPackageDir = Get-CoreCLRPackageDirectory + + $platformAbstraction = Join-Path $env:TP_ROOT_DIR "src\Microsoft.TestPlatform.PlatformAbstractions\bin\$TPB_Configuration" + $platformAbstractionNet46 = Join-Path $platformAbstraction $TPB_TargetFramework + $platformAbstractionNetCore = Join-Path $platformAbstraction $TPB_TargetFrameworkCore + + Copy-Item $platformAbstractionNet46\* $fullCLRPackageDir -Force + Copy-Item $platformAbstractionNetCore\* $coreCLRPackageDir -Force + + Write-Log "Publish-PlatfromAbstractions-Internal:: Complete. {$(Get-ElapsedTime($timer))}" } diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Microsoft.TestPlatform.CoreUtilities.csproj b/src/Microsoft.TestPlatform.CoreUtilities/Microsoft.TestPlatform.CoreUtilities.csproj index b1771909553de2e974734e881b24fc3aa826501e..f8b3af1bda251dff5694ebc3375b8e7bef1ea327 100644 GIT binary patch literal 1936 zcmb7FTTk0C6n-AR!m^MGny|}O&@_@DR4%H-7@`I3p)YQHS~3zlvK=nJZ4diN`wKg{ zHYqI|QXX=SeJ2a{-T^s!q zLPy5(!KdG%&}ggYj$NHi7`iB#XdT)y9zuwNKZiwxNkqXL;FmJ24xBb4Z|NPM8HaO9|fy z=)_t`X7S6FNFZ1e+sQZ725wyxBTld$?}Sve6ot+WCVA54!3GM;I-#U6a-R*3&>S2h z{MBt`^tA{d!~&{S5yvxhw3#J6B%m9++bg*3*69%%Z11d1w|gYjbBI6=`bRmpViv<* z-qyj#r$~MA_}ZwA=i?x0%i=7Vfs`O`!0OC|Kt?KzGYLMeJ$BmsF$4CQmPf)z?Mz-{ z{Wto-VGg>(;|lg#N0P}PRos#i}T1tmeb+f=KdD}X#*d$ppt z>b4YKBZtE5SXld&=-xtDXs%=gL$PJRL(wL0>c=_KGt?3qug9C;Cgf6Bhu-g*OEcHP z(xT4e-Axsw)jt1$?L$56*Qf-C=u!op8C4JElbLl!gt^}Ad-meVr})Nf&{StalS?s! z*r#1_mqdB_qma*1n~JbKQ12p}iFoWX8EMw(d}X?J6Ci~+npPj8cf1eN;(eHQDz=}6 LB76R{23vmtt;&-P literal 4780 zcmds5ZBNrs6h5C#{0|K=QDW?-GGkp=ecL)c70o! zff&S#1}_?$Us7gQrJG$}3R41I?y%zWew+F&Z0q zAIXJG!R2GUA#V_ero4q7_0oZziKogF%TL)izD*&;QYobexe@F;hP*EBL+A>j4MoB*9usYRzA@S8X|f^%K|` z8tdnC&V1CfoOuf2?*vjJ=uXGH%xYp~0D8uWSY&=n$mtOzkMO%AMd&TJk@*b4cWUhPVJq!rCK=;$EvzA0lHkVrwFh}>%Z-tJ4OtyT zKz(Keh#%7TP35*^eYU!W3RN5|k~XjX7}9#E-L8qOXJl)P_welFx|mUv;g^_HBvff$ z1(n5cl}Dr_!YQ-9b*qR(AF;TFH=30es(Jkmzg?5-0eYG0UXzx*lpBMu_a<`nb)`{P zzm{TTaa7Sib`2f}@Pgf{kG?@9jnSb(_%uLN4q$r^8JQXiR$!JULQlxQa}7!(#AYQ^ zGY!Zrw~HMhyZYEDs6s0}9pV$>!^jlJ=mZtczRc*mvV)8h>j5Imx7;(>U9@{p275z# z53rRwzgKl+4Sc$PvhuR4^Oh4Q=}ODnZc(LuVG(^19_sn(A!4*;fG%tCRo~|({BD|> z`S*PGFcT0DUDSx~9WM4p`|khnvJAx@Jii61zaR$OjaVBt+lP3kmB1bt-UHub6w$7S`V48P1kvdd}!Cn_oc;s zM(5fg&~<5cD^9;U-)5(@Wp(_GoT8j;qw`%M8=;ANc9Oh5E-h-+Lq>$NGtU;>l}_=@ zxsBPr&%V6_dY;y}U$J6cvs)D-B~9yrM<-fV{}jBewqlAj>ec!!aK!LnAAA8Ov9yfr zTArI)c(UN6%J0~C&(lt)ayCgUEaOdUBJF&PZ3dRT_8ffskN%^WHoC1le2nqB8-4!os^2thG)o0gt)PG~_+<)uS!<^vHQz!WI3O~!w>(>6{A0)N;56poOl>h($ diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/EqtTrace.cs b/src/Microsoft.TestPlatform.CoreUtilities/Tracing/EqtTrace.cs index 46860c8b6b..f2a01d4762 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/EqtTrace.cs +++ b/src/Microsoft.TestPlatform.CoreUtilities/Tracing/EqtTrace.cs @@ -4,15 +4,9 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel { using System; - using System.Collections.Generic; using System.Diagnostics; using System.Globalization; - using System.IO; using System.Text; - using System.Threading; - - using Microsoft.VisualStudio.TestPlatform.CoreUtilities; - using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Resources; /// /// Wrapper class for tracing. @@ -29,106 +23,52 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel /// public static class EqtTrace { - /// - /// Name of the trace listener. - /// - private const string ListenerName = "TptTraceListener"; - - /// - /// Use a custom trace source. This doesn't pollute the default tracing for user applications. - /// - private static readonly TraceSource Source = new TraceSource("TpTrace", SourceLevels.Off); - - /// - /// Create static maps for TraceLevel to SourceLevels. The APIs need to provide TraceLevel - /// for backward compatibility with older versions of Object Model. - /// - private static readonly Dictionary TraceSourceLevelsMap = - new Dictionary - { - { TraceLevel.Error, SourceLevels.Error }, - { TraceLevel.Info, SourceLevels.Information }, - { TraceLevel.Off, SourceLevels.Off }, - { TraceLevel.Verbose, SourceLevels.Verbose }, - { TraceLevel.Warning, SourceLevels.Warning } - }; - - /// - /// Create static maps for SourceLevels to TraceLevel. The APIs need to provide TraceLevel - /// for backward compatibility with older versions of Object Model. - /// - private static readonly Dictionary SourceTraceLevelsMap = - new Dictionary - { - { SourceLevels.Error, TraceLevel.Error }, - { SourceLevels.Information, TraceLevel.Info }, - { SourceLevels.Off, TraceLevel.Off }, - { SourceLevels.Verbose, TraceLevel.Verbose }, - { SourceLevels.Warning, TraceLevel.Warning }, - { SourceLevels.All, TraceLevel.Verbose } - }; - - /// - /// Create static maps for SourceLevels to TraceLevel. The APIs need to provide TraceLevel - /// for backward compatibility with older versions of Object Model. - /// - private static readonly Dictionary TraceLevelEventTypeMap = - new Dictionary - { - { TraceLevel.Error, TraceEventType.Error }, - { TraceLevel.Info, TraceEventType.Information }, - { TraceLevel.Verbose, TraceEventType.Verbose }, - { TraceLevel.Warning, TraceEventType.Warning } - }; - - // Current process name/id that called trace so that it's easier to read logs. - // We cache them for performance reason. - private static readonly string ProcessName = GetProcessName(); - - private static readonly int ProcessId = GetProcessId(); - - /// - /// Specifies whether the trace is initialized or not - /// - private static bool isListenerInitialized = false; - - /// - /// Lock over initialization - /// - private static object isInitializationLock = new object(); + private static IPlatformEqtTrace traceImpl = new PlatformEqtTrace(); - private static int traceFileSize = 0; - private static int defaultTraceFileSize = 10240; // 10Mb. +#if NET46 + public static void SetupRemoteEqtTraceListeners(AppDomain childDomain) + { + traceImpl.SetupRemoteEqtTraceListeners(childDomain); + } - /// - /// Gets the log file for tracing. - /// - public static string LogFile + public static void SetupListener(TraceListener listener) { - get; - private set; + traceImpl.SetupListener(listener); } - /// - /// Gets or sets the trace level. - /// public static TraceLevel TraceLevel { get { - return SourceTraceLevelsMap[Source.Switch.Level]; + return (TraceLevel)traceImpl.GetTraceLevel(); + } + set + { + traceImpl.SetTraceLevel((PlatformTraceLevel)value); } + } + +#endif +#if NETSTANDARD1_4 + public static PlatformTraceLevel TraceLevel + { + get + { + return traceImpl.GetTraceLevel(); + } set { - try - { - Source.Switch.Level = TraceSourceLevelsMap[value]; - } - catch (ArgumentException e) - { - LogIgnoredException(e); - } + traceImpl.SetTraceLevel(value); + } + } +#endif + + public static string LogFile + { + get + { + return traceImpl.GetLogFile(); } } @@ -139,7 +79,7 @@ public static bool IsErrorEnabled { get { - return ShouldTrace(TraceLevel.Error); + return traceImpl.ShouldTrace(PlatformTraceLevel.Error); } } @@ -150,7 +90,7 @@ public static bool IsInfoEnabled { get { - return ShouldTrace(TraceLevel.Info); + return traceImpl.ShouldTrace(PlatformTraceLevel.Info); } } @@ -161,7 +101,7 @@ public static bool IsVerboseEnabled { get { - return ShouldTrace(TraceLevel.Verbose); + return traceImpl.ShouldTrace(PlatformTraceLevel.Verbose); } } @@ -172,7 +112,7 @@ public static bool IsWarningEnabled { get { - return ShouldTrace(TraceLevel.Warning); + return traceImpl.ShouldTrace(PlatformTraceLevel.Warning); } } @@ -183,93 +123,9 @@ public static bool IsWarningEnabled /// A custom log file for trace messages. public static void InitializeVerboseTrace(string customLogFile) { - isListenerInitialized = false; - - LogFile = customLogFile; - TraceLevel = TraceLevel.Verbose; - Source.Switch.Level = SourceLevels.All; - } - -#if NET46 - /// - /// Setup remote trace listener in the child domain. - /// If calling domain, doesn't have tracing enabled nothing is done. - /// - /// Child AppDomain. - public static void SetupRemoteEqtTraceListeners(AppDomain childDomain) - { - Debug.Assert(childDomain != null, "domain"); - if (childDomain != null) - { - RemoteEqtTrace remoteEqtTrace = (RemoteEqtTrace)childDomain.CreateInstanceFromAndUnwrap( - typeof(RemoteEqtTrace).Assembly.Location, - typeof(RemoteEqtTrace).FullName); - - remoteEqtTrace.TraceLevel = TraceLevel; - - if (!Enum.Equals(TraceLevel, TraceLevel.Off)) - { - TraceListener tptListner = null; - foreach (TraceListener listener in Trace.Listeners) - { - if (string.Equals(listener.Name, ListenerName, StringComparison.OrdinalIgnoreCase)) - { - Debug.Assert(tptListner == null, "Multiple TptListeners found."); - tptListner = listener; - } - } - - remoteEqtTrace.SetupRemoteListeners(tptListner); - } - } - } -#endif - - /// - /// Setup a custom trace listener instead of default trace listener created by test platform. - /// This is needed by DTA Agent where it needs to listen test platform traces but doesn't use test platform listener. - /// - /// - /// The listener. - /// - public static void SetupListener(TraceListener listener) - { - lock (isInitializationLock) - { - // Add new listeners. - if (listener != null) - { - Source.Listeners.Add(listener); - } - - isListenerInitialized = true; - } + traceImpl.InitializeVerboseTrace(customLogFile); } - /// - /// Gets a value indicating if tracing is enabled for a trace level. - /// - /// Trace level. - /// True if tracing is enabled. - public static bool ShouldTrace(TraceLevel traceLevel) - { - switch (traceLevel) - { - case TraceLevel.Off: - return false; - case TraceLevel.Error: - return Source.Switch.ShouldTrace(TraceEventType.Error); - case TraceLevel.Warning: - return Source.Switch.ShouldTrace(TraceEventType.Warning); - case TraceLevel.Info: - return Source.Switch.ShouldTrace(TraceEventType.Information); - case TraceLevel.Verbose: - return Source.Switch.ShouldTrace(TraceEventType.Verbose); - default: - Debug.Fail("Should never get here!"); - return false; - } - } /// /// Prints an error message and prompts with a Debug dialog @@ -305,9 +161,9 @@ public static void Fail(string format, params object[] args) [Conditional("TRACE")] public static void Error(string message) { - if (ShouldTrace(TraceLevel.Error)) + if (traceImpl.ShouldTrace(PlatformTraceLevel.Error)) { - WriteLine(TraceLevel.Error, message); + traceImpl.WriteLine(PlatformTraceLevel.Error, message); } } @@ -344,7 +200,7 @@ public static void ErrorUnless(bool condition, string message) /// Level for trace. /// Trace message. [Conditional("TRACE")] - public static void ErrorUnlessAlterTrace(bool condition, TraceLevel bumpLevel, string message) + public static void ErrorUnlessAlterTrace(bool condition, PlatformTraceLevel bumpLevel, string message) { if (condition) { @@ -367,7 +223,7 @@ public static void Error(string format, params object[] args) Debug.Assert(format != null, "format != null"); // Check level before doing string.Format to avoid string creation if tracing is off. - if (ShouldTrace(TraceLevel.Error)) + if (traceImpl.ShouldTrace(PlatformTraceLevel.Error)) { Error(string.Format(CultureInfo.InvariantCulture, format, args)); } @@ -394,7 +250,7 @@ public static void ErrorUnless(bool condition, string format, params object[] ar /// Message format. /// Trace message format arguments. [Conditional("TRACE")] - public static void ErrorUnlessAlterTrace(bool condition, TraceLevel bumpLevel, string format, params object[] args) + public static void ErrorUnlessAlterTrace(bool condition, PlatformTraceLevel bumpLevel, string format, params object[] args) { if (condition) { @@ -446,10 +302,10 @@ public static void Error(Exception exceptionToTrace) // Write only if tracing for error is enabled. // Done upfront to avoid perf hit. - if (ShouldTrace(TraceLevel.Error)) + if (traceImpl.ShouldTrace(PlatformTraceLevel.Error)) { // Write at error level - WriteLine(TraceLevel.Error, FormatException(exceptionToTrace)); + traceImpl.WriteLine(PlatformTraceLevel.Error, FormatException(exceptionToTrace)); } } @@ -460,9 +316,9 @@ public static void Error(Exception exceptionToTrace) [Conditional("TRACE")] public static void Warning(string message) { - if (ShouldTrace(TraceLevel.Warning)) + if (traceImpl.ShouldTrace(PlatformTraceLevel.Warning)) { - WriteLine(TraceLevel.Warning, message); + traceImpl.WriteLine(PlatformTraceLevel.Warning, message); } } @@ -499,7 +355,7 @@ public static void WarningUnless(bool condition, string message) /// Trace message level. /// Message to trace. [Conditional("TRACE")] - public static void WarningUnlessAlterTrace(bool condition, TraceLevel bumpLevel, string message) + public static void WarningUnlessAlterTrace(bool condition, PlatformTraceLevel bumpLevel, string message) { if (condition) { @@ -522,7 +378,7 @@ public static void Warning(string format, params object[] args) Debug.Assert(format != null, "format != null"); // Check level before doing string.Format to avoid string creation if tracing is off. - if (ShouldTrace(TraceLevel.Warning)) + if (traceImpl.ShouldTrace(PlatformTraceLevel.Warning)) { Warning(string.Format(CultureInfo.InvariantCulture, format, args)); } @@ -564,7 +420,7 @@ public static void WarningUnless(bool condition, string format, params object[] /// Format of the trace message. /// Arguments for trace message. [Conditional("TRACE")] - public static void WarningUnlessAlterTrace(bool condition, TraceLevel bumpLevel, string format, params object[] args) + public static void WarningUnlessAlterTrace(bool condition, PlatformTraceLevel bumpLevel, string format, params object[] args) { if (condition) { @@ -583,9 +439,9 @@ public static void WarningUnlessAlterTrace(bool condition, TraceLevel bumpLevel, [Conditional("TRACE")] public static void Info(string message) { - if (ShouldTrace(TraceLevel.Info)) + if (traceImpl.ShouldTrace(PlatformTraceLevel.Info)) { - WriteLine(TraceLevel.Info, message); + traceImpl.WriteLine(PlatformTraceLevel.Info, message); } } @@ -622,7 +478,7 @@ public static void InfoUnless(bool condition, string message) /// Trace message level. /// Trace message. [Conditional("TRACE")] - public static void InfoUnlessAlterTrace(bool condition, TraceLevel bumpLevel, string message) + public static void InfoUnlessAlterTrace(bool condition, PlatformTraceLevel bumpLevel, string message) { if (condition) { @@ -645,7 +501,7 @@ public static void Info(string format, params object[] args) Debug.Assert(format != null, "format != null"); // Check level before doing string.Format to avoid string creation if tracing is off. - if (ShouldTrace(TraceLevel.Info)) + if (traceImpl.ShouldTrace(PlatformTraceLevel.Info)) { Info(string.Format(CultureInfo.InvariantCulture, format, args)); } @@ -687,7 +543,7 @@ public static void InfoUnless(bool condition, string format, params object[] arg /// Trace message format. /// Trace message arguments. [Conditional("TRACE")] - public static void InfoUnlessAlterTrace(bool condition, TraceLevel bumpLevel, string format, params object[] args) + public static void InfoUnlessAlterTrace(bool condition, PlatformTraceLevel bumpLevel, string format, params object[] args) { if (condition) { @@ -706,9 +562,9 @@ public static void InfoUnlessAlterTrace(bool condition, TraceLevel bumpLevel, st [Conditional("TRACE")] public static void Verbose(string message) { - if (ShouldTrace(TraceLevel.Verbose)) + if (traceImpl.ShouldTrace(PlatformTraceLevel.Verbose)) { - WriteLine(TraceLevel.Verbose, message); + traceImpl.WriteLine(PlatformTraceLevel.Verbose, message); } } @@ -745,7 +601,7 @@ public static void VerboseUnless(bool condition, string message) /// Trace message level. /// Trace message. [Conditional("TRACE")] - public static void VerboseUnlessAlterTrace(bool condition, TraceLevel level, string message) + public static void VerboseUnlessAlterTrace(bool condition, PlatformTraceLevel level, string message) { if (condition) { @@ -768,7 +624,7 @@ public static void Verbose(string format, params object[] args) Debug.Assert(format != null, "format != null"); // Check level before doing string.Format to avoid string creation if tracing is off. - if (ShouldTrace(TraceLevel.Verbose)) + if (traceImpl.ShouldTrace(PlatformTraceLevel.Verbose)) { Verbose(string.Format(CultureInfo.InvariantCulture, format, args)); } @@ -810,7 +666,7 @@ public static void VerboseUnless(bool condition, string format, params object[] /// Format of the trace message. /// Arguments for the trace message format. [Conditional("TRACE")] - public static void VerboseUnlessAlterTrace(bool condition, TraceLevel level, string format, params object[] args) + public static void VerboseUnlessAlterTrace(bool condition, PlatformTraceLevel level, string format, params object[] args) { if (condition) { @@ -822,64 +678,6 @@ public static void VerboseUnlessAlterTrace(bool condition, TraceLevel level, str } } - /// - /// Setup trace listeners. It should be called when setting trace listener for child domain. - /// - /// New listener. - internal static void SetupRemoteListeners(TraceListener listener) - { - lock (isInitializationLock) - { - // Add new listeners. - if (listener != null) - { - Source.Listeners.Add(listener); - } - - isListenerInitialized = true; - } - } - - /// - /// Ensure the trace is initialized - /// - private static void EnsureTraceIsInitialized() - { - if (isListenerInitialized) - { - return; - } - - lock (isInitializationLock) - { - if (isListenerInitialized) - { - return; - } - - string logsDirectory = Path.GetTempPath(); - - // Set the trace level and add the trace listener - if (LogFile == null) - { - using (var process = Process.GetCurrentProcess()) - { - // In case of parallel execution, there may be several processes with same name. - // Add a process id to make the traces unique. - LogFile = Path.Combine( - logsDirectory, - Path.GetFileNameWithoutExtension(process.MainModule.FileName) + "." + process.Id + ".TpTrace.log"); - } - } - - // Add a default listener - traceFileSize = defaultTraceFileSize; - Source.Listeners.Add(new RollingFileTraceListener(LogFile, ListenerName, traceFileSize)); - - isListenerInitialized = true; - } - } - /// /// Formats an exception into a nice looking message. /// @@ -949,81 +747,22 @@ private static string FormatException(Exception exceptionToTrace) return message.ToString(); } - /// - /// Get the process name. Note: we cache it, use m_processName. - /// - /// Name of the process. - private static string GetProcessName() - { - try - { - // return ProcessHelper.GetProcessName(); - string processName = null; - - string[] args = Environment.GetCommandLineArgs(); - - if (args != null && args.Length != 0) - { - // Leave the extension if specified, otherwise don't add it (e.g. case a.exe.exe). - // It seems that if .exe suffix is not specified Framework adds .EXE to agrs[0]. - processName = Path.GetFileName(args[0]); - } - - // If we still have not got process name from command line - use the slow way. - // This should never happen unless the process is called from execv with empty cmdline. - if (string.IsNullOrEmpty(processName)) - { - Debug.Fail("Could not get process name from command line, will try to use the slow way."); - using (var process = Process.GetCurrentProcess()) - { - processName = process.ProcessName; - } - } - - return processName; - } - catch (Exception e) - { - // valid suppress - Debug.Fail("Could not get process name: " + e); - LogIgnoredException(e); - return Resources.Utility_ProcessNameWhenCannotGetIt; - } - } - - private static int GetProcessId() - { - try - { - using (var process = Process.GetCurrentProcess()) - { - return process.Id; - } - } - catch (InvalidOperationException e) - { - Debug.Fail("Could not get process id: " + e); - LogIgnoredException(e); - return -1; - } - } - - private static void WriteAtLevel(TraceLevel level, string message) + private static void WriteAtLevel(PlatformTraceLevel level, string message) { switch (level) { - case TraceLevel.Off: + case PlatformTraceLevel.Off: return; - case TraceLevel.Error: + case PlatformTraceLevel.Error: Error(message); break; - case TraceLevel.Warning: + case PlatformTraceLevel.Warning: Warning(message); break; - case TraceLevel.Info: + case PlatformTraceLevel.Info: Info(message); break; - case TraceLevel.Verbose: + case PlatformTraceLevel.Verbose: Verbose(message); break; default: @@ -1032,71 +771,10 @@ private static void WriteAtLevel(TraceLevel level, string message) } } - private static void WriteAtLevel(TraceLevel level, string format, params object[] args) + private static void WriteAtLevel(PlatformTraceLevel level, string format, params object[] args) { Debug.Assert(format != null, "format != null"); WriteAtLevel(level, string.Format(CultureInfo.InvariantCulture, format, args)); } - - /// - /// Adds the message to the trace log. - /// The line becomes: - /// [I, PID, ThreadID, 2003/06/11 11:56:07.445] CallingAssemblyName: message. - /// - /// Trace level. - /// The message to add to trace. - private static void WriteLine(TraceLevel level, string message) - { - Debug.Assert(message != null, "message != null"); - Debug.Assert(!string.IsNullOrEmpty(ProcessName), "!string.IsNullOrEmpty(ProcessName)"); - - // Ensure trace is initlized - EnsureTraceIsInitialized(); - - // The format below is a CSV so that Excel could be used easily to - // view/filter the logs. - var log = string.Format( - CultureInfo.InvariantCulture, - "{0}, {1}, {2:yyyy}/{2:MM}/{2:dd}, {2:HH}:{2:mm}:{2:ss}.{2:fff}, {5}, {3}, {4}", - ProcessId, - Thread.CurrentThread.ManagedThreadId, - DateTime.Now, - ProcessName, - message, - Stopwatch.GetTimestamp()); - - try - { - Source.TraceEvent(TraceLevelEventTypeMap[level], 0, log); - Source.Flush(); - } - catch (Exception e) - { - // valid suppress - // Log exception from tracing into event viewer. - LogIgnoredException(e); - } - } - - /// - /// Auxiliary method: logs the exception that is being ignored. - /// - /// The exception to log. - private static void LogIgnoredException(Exception e) - { - Debug.Assert(e != null, "e != null"); - - EnsureTraceIsInitialized(); - - try - { - // Note: Debug.WriteLine may throw if there is a problem in .config file. - Debug.WriteLine("Ignore exception: " + e); - } - catch - { - // Ignore everything at this point. - } - } } } \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Microsoft.TestPlatform.CrossPlatEngine.csproj b/src/Microsoft.TestPlatform.CrossPlatEngine/Microsoft.TestPlatform.CrossPlatEngine.csproj index 4980803b66..e5de06306c 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Microsoft.TestPlatform.CrossPlatEngine.csproj +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Microsoft.TestPlatform.CrossPlatEngine.csproj @@ -30,6 +30,9 @@ 4.3.0 + + 4.3.0 + diff --git a/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj b/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj index 6aaf37270f91fed142e983fae807cdd2c468f97c..d2ab2dc72d6023ec01ff4ad9431009e10e6cfd2a 100644 GIT binary patch delta 70 zcmdmEzsPaJAyG!o$%1^Y$}S9<42cZs40#Os48;s3KwdJC)?)}@C<2NkGo&&UPc9Ub WoIFoJWHKLb$7BIkfz4cEn>Yc2zY(AS delta 20 ccmZ4FxW|6OA<@YK{4A5-$+~R*AhwAU09$GZasU7T diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/Interfaces/Tracing/IEqtTrace.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/Interfaces/Tracing/IEqtTrace.cs new file mode 100644 index 0000000000..51132bb553 --- /dev/null +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/Interfaces/Tracing/IEqtTrace.cs @@ -0,0 +1,74 @@ +namespace Microsoft.VisualStudio.TestPlatform.ObjectModel +{ + // + // Summary: + // Specifies what messages to output for the System.Diagnostics.Debug, System.Diagnostics.Trace + // and System.Diagnostics.TraceSwitch classes. + public enum PlatformTraceLevel + { + // + // Summary: + // Output no tracing and debugging messages. + Off = 0, + // + // Summary: + // Output error-handling messages. + Error = 1, + // + // Summary: + // Output warnings and error-handling messages. + Warning = 2, + // + // Summary: + // Output informational messages, warnings, and error-handling messages. + Info = 3, + // + // Summary: + // Output all debugging and tracing messages. + Verbose = 4 + } + + + public partial interface IPlatformEqtTrace + { + /// + /// Adds the message to the trace log. + /// The line becomes: + /// [I, PID, ThreadID, 2003/06/11 11:56:07.445] CallingAssemblyName: message. + /// + /// Trace level. + /// The message to add to trace. + void WriteLine(PlatformTraceLevel level, string message); + + /// + /// Initializes the verbose tracing with custom log file + /// And overrides if any trace is set before + /// + /// A custom log file for trace messages. + void InitializeVerboseTrace(string customLogFile); + + /// + /// Gets a value indicating if tracing is enabled for a trace level. + /// + /// Trace level. + /// True if tracing is enabled. + bool ShouldTrace(PlatformTraceLevel traceLevel); + + /// + /// Gets file path for trace log file. + /// + /// True if tracing is enabled. + string GetLogFile(); + + /// + /// Sets platfrom specific trace value for tracing verbosity. + /// + /// PlatformTraceLevel. + void SetTraceLevel(PlatformTraceLevel value); + + /// + /// Gets platfrom specific trace value for tracing verbosity. + /// + PlatformTraceLevel GetTraceLevel(); + } +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/Microsoft.TestPlatform.PlatformAbstractions.csproj b/src/Microsoft.TestPlatform.PlatformAbstractions/Microsoft.TestPlatform.PlatformAbstractions.csproj new file mode 100644 index 0000000000000000000000000000000000000000..59eb92501f09a8f8b2b4820a2ea86306d03d715a GIT binary patch literal 4256 zcmds*TTc@~6vxl2CVq#FF;Prxi=Yo$N(i7aQ9_{67hY;xJnc?S;x~ulEo->Dq(a#K!i@s*D6VJ$4VQ#dC%EqGZ`Kfc6kN+1}@U>?BtC zp4exbva8Q})t=*rnynzmTN$Beu+;CF*mryDY@5O*rSg4EF~9 z@E(vqgeK7+&hq&6Y*o0Ap=;swab|6mT=s}rBuSdxgLWIPE$6F_ZNat6+Z4}D9HNC0 z(PK8(B8PXSysDi@2ZXx~*nmsLhTwYzqP59)+WRr7#4?Sb&_w0#&(W$EV#2-=d zbYj(wPp7&v&!m|cyyEX`;Z~5Ko4VNVy&r^IVxH8{Rj+aqzWtlq0saiP<%7ceX4yS0 L)j#~_pkcoN8UMA5 literal 0 HcmV?d00001 diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/common/Tracing/EqtTrace.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/common/Tracing/EqtTrace.cs new file mode 100644 index 0000000000..318d55f96b --- /dev/null +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/common/Tracing/EqtTrace.cs @@ -0,0 +1,368 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.ObjectModel +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Globalization; + using System.IO; + using System.Threading; + + /// + /// Wrapper class for tracing. + /// - Shortcut-methods for Error, Warning, Info, Verbose. + /// - Adds additional information to the trace: calling process name, PID, ThreadID, Time. + /// - Uses custom switch EqtTraceLevel from .config file. + /// - By default tracing if OFF. + /// - Our build environment always sets the /d:TRACE so this class is always enabled, + /// the Debug class is enabled only in debug builds (/d:DEBUG). + /// - We ignore exceptions thrown by underlying TraceSwitch (e.g. due to config file error). + /// We log ignored exceptions to system Application log. + /// We pass through exceptions thrown due to incorrect arguments to EqtTrace methods. + /// Usage: EqtTrace.Info("Here's how to trace info"); + /// + public partial class PlatformEqtTrace : IPlatformEqtTrace + { + /// + /// Name of the trace listener. + /// + private const string ListenerName = "TptTraceListener"; + + /// + /// Use a custom trace source. This doesn't pollute the default tracing for user applications. + /// + private static readonly TraceSource Source = new TraceSource("TpTrace", SourceLevels.Off); + + /// + /// Create static maps for TraceLevel to SourceLevels. The APIs need to provide TraceLevel + /// for backward compatibility with older versions of Object Model. + /// + private static readonly Dictionary TraceSourceLevelsMap = + new Dictionary + { + { TraceLevel.Error, SourceLevels.Error }, + { TraceLevel.Info, SourceLevels.Information }, + { TraceLevel.Off, SourceLevels.Off }, + { TraceLevel.Verbose, SourceLevels.Verbose }, + { TraceLevel.Warning, SourceLevels.Warning } + }; + + /// + /// Create static maps for SourceLevels to TraceLevel. The APIs need to provide TraceLevel + /// for backward compatibility with older versions of Object Model. + /// + private static readonly Dictionary SourceTraceLevelsMap = + new Dictionary + { + { SourceLevels.Error, TraceLevel.Error }, + { SourceLevels.Information, TraceLevel.Info }, + { SourceLevels.Off, TraceLevel.Off }, + { SourceLevels.Verbose, TraceLevel.Verbose }, + { SourceLevels.Warning, TraceLevel.Warning }, + { SourceLevels.All, TraceLevel.Verbose } + }; + + /// + /// Create static maps for SourceLevels to TraceLevel. The APIs need to provide TraceLevel + /// for backward compatibility with older versions of Object Model. + /// + private static readonly Dictionary TraceLevelEventTypeMap = + new Dictionary + { + { TraceLevel.Error, TraceEventType.Error }, + { TraceLevel.Info, TraceEventType.Information }, + { TraceLevel.Verbose, TraceEventType.Verbose }, + { TraceLevel.Warning, TraceEventType.Warning } + }; + + // Current process name/id that called trace so that it's easier to read logs. + // We cache them for performance reason. + private static readonly string ProcessName = GetProcessName(); + + private static readonly int ProcessId = GetProcessId(); + + /// + /// Specifies whether the trace is initialized or not + /// + private static bool isInitialized = false; + + /// + /// Lock over initialization + /// + private static object isInitializationLock = new object(); + + private static int traceFileSize = 0; + private static int defaultTraceFileSize = 10240; // 10Mb. + + public static string LogFile + { + get; + private set; + } + + /// + /// Gets or sets the trace level. + /// + public static TraceLevel TraceLevel + { + get + { + return SourceTraceLevelsMap[Source.Switch.Level]; + } + + set + { + try + { + Source.Switch.Level = TraceSourceLevelsMap[value]; + } + catch (ArgumentException e) + { + LogIgnoredException(e); + } + } + } + + /// + /// Setup trace listeners. It should be called when setting trace listener for child domain. + /// + /// New listener. + internal static void SetupRemoteListeners(TraceListener listener) + { + lock (isInitializationLock) + { + // Add new listeners. + if (listener != null) + { + Source.Listeners.Add((TraceListener)listener); + } + + isInitialized = true; + } + } + + /// + public void InitializeVerboseTrace(string customLogFile) + { + isInitialized = false; + + LogFile = customLogFile; + TraceLevel = TraceLevel.Verbose; + Source.Switch.Level = SourceLevels.All; + } + + /// + public bool ShouldTrace(PlatformTraceLevel traceLevel) + { + switch (traceLevel) + { + case PlatformTraceLevel.Off: + return false; + case PlatformTraceLevel.Error: + return Source.Switch.ShouldTrace(TraceEventType.Error); + case PlatformTraceLevel.Warning: + return Source.Switch.ShouldTrace(TraceEventType.Warning); + case PlatformTraceLevel.Info: + return Source.Switch.ShouldTrace(TraceEventType.Information); + case PlatformTraceLevel.Verbose: + return Source.Switch.ShouldTrace(TraceEventType.Verbose); + default: + Debug.Fail("Should never get here!"); + return false; + } + } + + /// + public string GetLogFile() + { + return LogFile; + } + + /// + /// Ensure the trace is initialized + /// + private static void EnsureTraceIsInitialized() + { + if (isInitialized) + { + return; + } + + lock (isInitializationLock) + { + if (isInitialized) + { + return; + } + + string logsDirectory = Path.GetTempPath(); + + // Set the trace level and add the trace listener + if (LogFile == null) + { + using (var process = Process.GetCurrentProcess()) + { + // In case of parallel execution, there may be several processes with same name. + // Add a process id to make the traces unique. + LogFile = Path.Combine( + logsDirectory, + Path.GetFileNameWithoutExtension(process.MainModule.FileName) + "." + process.Id + ".TpTrace.log"); + } + } + + // Add a default listener + traceFileSize = defaultTraceFileSize; + Source.Listeners.Add(new RollingFileTraceListener(LogFile, ListenerName, traceFileSize)); + + isInitialized = true; + } + } + + /// + /// Get the process name. Note: we cache it, use m_processName. + /// + /// Name of the process. + private static string GetProcessName() + { + try + { + string processName = null; + + string[] args = Environment.GetCommandLineArgs(); + + if (args != null && args.Length != 0) + { + // Leave the extension if specified, otherwise don't add it (e.g. case a.exe.exe). + // It seems that if .exe suffix is not specified Framework adds .EXE to agrs[0]. + processName = Path.GetFileName(args[0]); + } + + // If we still have not got process name from command line - use the slow way. + // This should never happen unless the process is called from execv with empty cmdline. + if (string.IsNullOrEmpty(processName)) + { + Debug.Fail("Could not get process name from command line, will try to use the slow way."); + using (var process = Process.GetCurrentProcess()) + { + processName = process.ProcessName; + } + } + + return processName; + } + catch (Exception e) + { + // valid suppress + Debug.Fail("Could not get process name: " + e); + LogIgnoredException(e); + return e.Message; + } + } + + private static int GetProcessId() + { + try + { + using (var process = Process.GetCurrentProcess()) + { + return process.Id; + } + } + catch (InvalidOperationException e) + { + Debug.Fail("Could not get process id: " + e); + LogIgnoredException(e); + return -1; + } + } + + + /// + public void WriteLine(PlatformTraceLevel level, string message) + { + Debug.Assert(message != null, "message != null"); + Debug.Assert(!string.IsNullOrEmpty(ProcessName), "!string.IsNullOrEmpty(ProcessName)"); + + // Ensure trace is initlized + EnsureTraceIsInitialized(); + + // The format below is a CSV so that Excel could be used easily to + // view/filter the logs. + var log = string.Format( + CultureInfo.InvariantCulture, + "{0}, {1}, {2:yyyy}/{2:MM}/{2:dd}, {2:HH}:{2:mm}:{2:ss}.{2:fff}, {5}, {3}, {4}", + ProcessId, + Thread.CurrentThread.ManagedThreadId, + DateTime.Now, + ProcessName, + message, + Stopwatch.GetTimestamp()); + + try + { + Source.TraceEvent(TraceLevelEventTypeMap[MapPlatformTraceToTrace(level)], 0, log); + Source.Flush(); + } + catch (Exception e) + { + // valid suppress + // Log exception from tracing into event viewer. + LogIgnoredException(e); + } + } + + /// + /// Auxiliary method: logs the exception that is being ignored. + /// + /// The exception to log. + private static void LogIgnoredException(Exception e) + { + Debug.Assert(e != null, "e != null"); + + EnsureTraceIsInitialized(); + + try + { + // Note: Debug.WriteLine may throw if there is a problem in .config file. + Debug.WriteLine("Ignore exception: " + e); + } + catch + { + // Ignore everything at this point. + } + } + + /// + public void SetTraceLevel(PlatformTraceLevel value) + { + Source.Switch.Level = TraceSourceLevelsMap[MapPlatformTraceToTrace(value)]; + } + + public PlatformTraceLevel GetTraceLevel() + { + return (PlatformTraceLevel)SourceTraceLevelsMap[Source.Switch.Level]; + } + + public TraceLevel MapPlatformTraceToTrace(PlatformTraceLevel traceLevel) + { + switch (traceLevel) + { + case PlatformTraceLevel.Off: + return TraceLevel.Off; + case PlatformTraceLevel.Error: + return TraceLevel.Error; + case PlatformTraceLevel.Warning: + return TraceLevel.Warning; + case PlatformTraceLevel.Info: + return TraceLevel.Info; + case PlatformTraceLevel.Verbose: + return TraceLevel.Verbose; + default: + Debug.Fail("Should never get here!"); + return TraceLevel.Verbose; + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/RollingFileTraceListener.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/common/Tracing/RollingFileTraceListener.cs similarity index 98% rename from src/Microsoft.TestPlatform.CoreUtilities/Tracing/RollingFileTraceListener.cs rename to src/Microsoft.TestPlatform.PlatformAbstractions/common/Tracing/RollingFileTraceListener.cs index 0eff163ea3..37f30b30d6 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/RollingFileTraceListener.cs +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/common/Tracing/RollingFileTraceListener.cs @@ -9,9 +9,6 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel using System.IO; using System.Text; - using Microsoft.VisualStudio.TestPlatform.CoreUtilities; - using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Resources; - /// /// Performs logging to a file and rolls the output file when either time or size thresholds are /// exceeded. @@ -37,7 +34,7 @@ public RollingFileTraceListener( { if (string.IsNullOrWhiteSpace(fileName)) { - throw new ArgumentException(Resources.CannotBeNullOrEmpty, nameof(fileName)); + throw new ArgumentException(nameof(fileName)); } if (rollSizeKB <= 0) diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/net46/Interfaces/Tracing/IEqtTrace.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/net46/Interfaces/Tracing/IEqtTrace.cs new file mode 100644 index 0000000000..170d9b801d --- /dev/null +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/net46/Interfaces/Tracing/IEqtTrace.cs @@ -0,0 +1,26 @@ +using System; +using System.Diagnostics; + +namespace Microsoft.VisualStudio.TestPlatform.ObjectModel +{ + + public partial interface IPlatformEqtTrace + { + /// + /// Setup remote trace listener in the child domain. + /// If calling domain, doesn't have tracing enabled nothing is done. + /// + /// Child AppDomain. + void SetupRemoteEqtTraceListeners(AppDomain childDomain); + + /// + /// Setup a custom trace listener instead of default trace listener created by test platform. + /// This is needed by DTA Agent where it needs to listen test platform traces but doesn't use test platform listener. + /// + /// + /// The listener. + /// + void SetupListener(TraceListener listener); + + } +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/net46/Tracing/EqtTrace.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/net46/Tracing/EqtTrace.cs new file mode 100644 index 0000000000..581c8fa225 --- /dev/null +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/net46/Tracing/EqtTrace.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.ObjectModel +{ + using System; + using System.Diagnostics; + + /// + /// Wrapper class for tracing. + /// - Shortcut-methods for Error, Warning, Info, Verbose. + /// - Adds additional information to the trace: calling process name, PID, ThreadID, Time. + /// - Uses custom switch EqtTraceLevel from .config file. + /// - By default tracing if OFF. + /// - Our build environment always sets the /d:TRACE so this class is always enabled, + /// the Debug class is enabled only in debug builds (/d:DEBUG). + /// - We ignore exceptions thrown by underlying TraceSwitch (e.g. due to config file error). + /// We log ignored exceptions to system Application log. + /// We pass through exceptions thrown due to incorrect arguments to EqtTrace methods. + /// Usage: EqtTrace.Info("Here's how to trace info"); + /// + public partial class PlatformEqtTrace : IPlatformEqtTrace + { + /// + /// Setup remote trace listener in the child domain. + /// If calling domain, doesn't have tracing enabled nothing is done. + /// + /// Child AppDomain. + public void SetupRemoteEqtTraceListeners(AppDomain childDomain) + { + Debug.Assert(childDomain != null, "domain"); + if (childDomain != null) + { + RemoteEqtTrace remoteEqtTrace = (RemoteEqtTrace)childDomain.CreateInstanceFromAndUnwrap( + typeof(RemoteEqtTrace).Assembly.Location, + typeof(RemoteEqtTrace).FullName); + + remoteEqtTrace.TraceLevel = TraceLevel; + + if (!Enum.Equals(TraceLevel, TraceLevel.Off)) + { + TraceListener tptListner = null; + foreach (TraceListener listener in Trace.Listeners) + { + if (string.Equals(listener.Name, ListenerName, StringComparison.OrdinalIgnoreCase)) + { + Debug.Assert(tptListner == null, "Multiple TptListeners found."); + tptListner = listener; + } + } + + remoteEqtTrace.SetupRemoteListeners(tptListner); + } + } + } + + /// + public void SetupListener(TraceListener listener) + { + lock (isInitializationLock) + { + // Add new listeners. + if (listener != null) + { + Source.Listeners.Add(listener); + } + + isInitialized = true; + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/RemoteEqtTrace.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/net46/Tracing/RemoteEqtTrace.cs similarity index 87% rename from src/Microsoft.TestPlatform.CoreUtilities/Tracing/RemoteEqtTrace.cs rename to src/Microsoft.TestPlatform.PlatformAbstractions/net46/Tracing/RemoteEqtTrace.cs index 25f730a0d7..7ec4cd7285 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/RemoteEqtTrace.cs +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/net46/Tracing/RemoteEqtTrace.cs @@ -3,7 +3,6 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel { -#if NET46 using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -20,12 +19,12 @@ public TraceLevel TraceLevel { get { - return EqtTrace.TraceLevel; + return PlatformEqtTrace.TraceLevel; } set { - EqtTrace.TraceLevel = value; + PlatformEqtTrace.TraceLevel = value; } } @@ -36,8 +35,7 @@ public TraceLevel TraceLevel [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Used in remote objects.")] internal void SetupRemoteListeners(TraceListener listener) { - EqtTrace.SetupRemoteListeners(listener); + PlatformEqtTrace.SetupRemoteListeners(listener); } } -#endif } diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/Tracing/EqtTrace.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/Tracing/EqtTrace.cs new file mode 100644 index 0000000000..209fda1143 --- /dev/null +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/Tracing/EqtTrace.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.ObjectModel +{ + using System; + using System.Diagnostics; + + /// + /// Wrapper class for tracing. + /// - Shortcut-methods for Error, Warning, Info, Verbose. + /// - Adds additional information to the trace: calling process name, PID, ThreadID, Time. + /// - Uses custom switch EqtTraceLevel from .config file. + /// - By default tracing if OFF. + /// - Our build environment always sets the /d:TRACE so this class is always enabled, + /// the Debug class is enabled only in debug builds (/d:DEBUG). + /// - We ignore exceptions thrown by underlying TraceSwitch (e.g. due to config file error). + /// We log ignored exceptions to system Application log. + /// We pass through exceptions thrown due to incorrect arguments to EqtTrace methods. + /// Usage: EqtTrace.Info("Here's how to trace info"); + /// + public class PlatformEqtTrace : IPlatformEqtTrace + { + public void WriteLine(PlatformTraceLevel level, string message) + { + throw new NotImplementedException(); + } + + public void InitializeVerboseTrace(string customLogFile) + { + throw new NotImplementedException(); + } + + public bool ShouldTrace(PlatformTraceLevel traceLevel) + { + throw new NotImplementedException(); + } + + public string GetLogFile() + { + throw new NotImplementedException(); + } + + public void SetTraceLevel(PlatformTraceLevel value) + { + throw new NotImplementedException(); + } + + public PlatformTraceLevel GetTraceLevel() + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/TestPlatform.ObjectModel.nuspec b/src/TestPlatform.ObjectModel.nuspec index cfba78533b..5c9467fa93 100644 --- a/src/TestPlatform.ObjectModel.nuspec +++ b/src/TestPlatform.ObjectModel.nuspec @@ -49,9 +49,11 @@ + + diff --git a/src/TestPlatform.TranslationLayer.nuspec b/src/TestPlatform.TranslationLayer.nuspec index 1c6c181794..e41ae1363d 100644 --- a/src/TestPlatform.TranslationLayer.nuspec +++ b/src/TestPlatform.TranslationLayer.nuspec @@ -47,11 +47,13 @@ + + diff --git a/test/Microsoft.TestPlatform.CoreUtilities.UnitTests/Microsoft.TestPlatform.CoreUtilities.UnitTests.csproj b/test/Microsoft.TestPlatform.CoreUtilities.UnitTests/Microsoft.TestPlatform.CoreUtilities.UnitTests.csproj index 1140979e15..51b77ff7a0 100644 --- a/test/Microsoft.TestPlatform.CoreUtilities.UnitTests/Microsoft.TestPlatform.CoreUtilities.UnitTests.csproj +++ b/test/Microsoft.TestPlatform.CoreUtilities.UnitTests/Microsoft.TestPlatform.CoreUtilities.UnitTests.csproj @@ -14,6 +14,20 @@ + + + 4.3.0 + + + 4.3.0 + + + 4.3.0 + + + 4.3.0 + + diff --git a/test/Microsoft.TestPlatform.CoreUtilities.UnitTests/Tracing/EqtTraceTests.cs b/test/Microsoft.TestPlatform.CoreUtilities.UnitTests/Tracing/EqtTraceTests.cs new file mode 100644 index 0000000000..93b2451b4b --- /dev/null +++ b/test/Microsoft.TestPlatform.CoreUtilities.UnitTests/Tracing/EqtTraceTests.cs @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace TestPlatform.CoreUtilities.UnitTests +{ + using System.Diagnostics; + using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using System; + using System.Text; + + [TestClass] + public class EqtTraceTests + { + private static string dirPath = null; + private static string logFile = null; + + [ClassInitialize] + public static void Init(TestContext testContext) + { + dirPath = Path.Combine(Path.GetTempPath(), "TraceUT"); + try + { + Directory.CreateDirectory(dirPath); + logFile = Path.Combine(dirPath, "trace.log"); + + } + catch(Exception ex) + { + Console.WriteLine(ex.Message); + } + + EqtTrace.InitializeVerboseTrace(logFile); + } + + [TestMethod] + public void CheckInitializeLogFileTest() + { + Assert.AreEqual(logFile, EqtTrace.LogFile, "Expected log file to be {0}", logFile); + } + + [TestMethod] + public void CheckIfTraceStateIsVerboseEnabled() + { +#if NET46 + EqtTrace.TraceLevel = TraceLevel.Verbose; +#else + EqtTrace.TraceLevel = PlatformTraceLevel.Verbose; +#endif + Assert.AreEqual(true, EqtTrace.IsVerboseEnabled, "Expected trace state to be verbose actual state {0}", EqtTrace.IsVerboseEnabled); + } + + [TestMethod] + public void CheckIfTraceStateIsErrorEnabled() + { +#if NET46 + EqtTrace.TraceLevel = TraceLevel.Error; +#else + EqtTrace.TraceLevel = PlatformTraceLevel.Error; +#endif + Assert.AreEqual(true, EqtTrace.IsErrorEnabled, "Expected trace state to be error actual state {0}", EqtTrace.IsErrorEnabled); + } + + [TestMethod] + public void CheckIfTraceStateIsInfoEnabled() + { +#if NET46 + EqtTrace.TraceLevel = TraceLevel.Info; +#else + EqtTrace.TraceLevel = PlatformTraceLevel.Info; +#endif + Assert.AreEqual(true, EqtTrace.IsInfoEnabled, "Expected trace state to be info actual state {0}", EqtTrace.IsInfoEnabled); + } + + [TestMethod] + public void CheckIfTraceStateIsWarningEnabled() + { +#if NET46 + EqtTrace.TraceLevel = TraceLevel.Warning; +#else + EqtTrace.TraceLevel = PlatformTraceLevel.Warning; +#endif + Assert.AreEqual(true, EqtTrace.IsWarningEnabled, "Expected trace state to be warning actual state {0}", EqtTrace.IsWarningEnabled); + } + + [TestMethod] + public void TraceShouldWriteError() + { +#if NET46 + EqtTrace.TraceLevel = TraceLevel.Error; +#else + EqtTrace.TraceLevel = PlatformTraceLevel.Error; +#endif + EqtTrace.Error(new NotImplementedException()); + Assert.IsNotNull(ReadLogFile(), "Expected error message"); + } + + [TestMethod] + public void TraceShouldWriteWarning() + { +#if NET46 + EqtTrace.TraceLevel = TraceLevel.Warning; +#else + EqtTrace.TraceLevel = PlatformTraceLevel.Warning; +#endif + EqtTrace.Warning("Dummy Warning Message"); + Assert.IsTrue(ReadLogFile().Contains("Dummy Warning Message"), "Expected Warning message"); + } + + [TestMethod] + public void TraceShouldWriteVerbose() + { +#if NET46 + EqtTrace.TraceLevel = TraceLevel.Verbose; +#else + EqtTrace.TraceLevel = PlatformTraceLevel.Verbose; +#endif + EqtTrace.Verbose("Dummy Verbose Message"); + Assert.IsTrue(ReadLogFile().Contains("Dummy Verbose Message"), "Expected Verbose message"); + } + [TestMethod] + public void TraceShouldWriteInfo() + { +#if NET46 + EqtTrace.TraceLevel = TraceLevel.Info; +#else + EqtTrace.TraceLevel = PlatformTraceLevel.Info; +#endif + EqtTrace.Info("Dummy Info Message"); + Assert.IsTrue(ReadLogFile().Contains("Dummy Info Message"), "Expected Info message"); + } + + private string ReadLogFile() + { + string log = null; + try + { + using (var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + using (var sr = new StreamReader(fs)) + { + log = sr.ReadToEnd(); + } + } + } + catch(Exception ex) + { + Console.WriteLine(ex.Message); + } + + return log; + } + } +} diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs index dc8f68d97f..c1c9df1ad1 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs @@ -79,7 +79,11 @@ public void SetupChannelShouldCreateTimestampedLogFileForHost() It.Is( t => t.LogFile.Contains("log.host." + DateTime.Now.ToString("yy-MM-dd")) && t.LogFile.Contains("_" + Thread.CurrentThread.ManagedThreadId + ".txt")))); +#if NET46 EqtTrace.TraceLevel = TraceLevel.Off; +#else + EqtTrace.TraceLevel = PlatformTraceLevel.Off; +#endif } [TestMethod] diff --git a/test/vstest.console.UnitTests/Processors/EnableDiagArgumentProcessorTests.cs b/test/vstest.console.UnitTests/Processors/EnableDiagArgumentProcessorTests.cs index 9e343c27fd..7c60cfe10a 100644 --- a/test/vstest.console.UnitTests/Processors/EnableDiagArgumentProcessorTests.cs +++ b/test/vstest.console.UnitTests/Processors/EnableDiagArgumentProcessorTests.cs @@ -33,8 +33,14 @@ public EnableDiagArgumentProcessorTests() this.diagProcessor = new TestableEnableDiagArgumentProcessor(this.mockFileHelper.Object); // Saving the EqtTrace state +#if NET46 traceLevel = EqtTrace.TraceLevel; EqtTrace.TraceLevel = TraceLevel.Off; +#else + traceLevel = (TraceLevel)EqtTrace.TraceLevel; + EqtTrace.TraceLevel = (PlatformTraceLevel)TraceLevel.Off; +#endif + traceFileName = EqtTrace.LogFile; } @@ -43,7 +49,11 @@ public void Cleanup() { // Restoring to initial state for EqtTrace EqtTrace.InitializeVerboseTrace(traceFileName); +#if NET46 EqtTrace.TraceLevel = traceLevel; +#else + EqtTrace.TraceLevel = (PlatformTraceLevel)traceLevel; +#endif } [TestMethod] @@ -106,7 +116,11 @@ public void EnableDiagArgumentProcessorExecutorShouldEnableVerboseLogging() this.diagProcessor.Executor.Value.Initialize(this.dummyFilePath); Assert.IsTrue(EqtTrace.IsVerboseEnabled); +#if NET46 EqtTrace.TraceLevel = TraceLevel.Off; +#else + EqtTrace.TraceLevel = PlatformTraceLevel.Off; +#endif } private class TestableEnableDiagArgumentProcessor : EnableDiagArgumentProcessor