diff --git a/Dependencies.props b/Dependencies.props
index cd375491..d4b7ecac 100644
--- a/Dependencies.props
+++ b/Dependencies.props
@@ -36,6 +36,7 @@
3.1.2
3.1.2
3.1.2
+ 4.5.3
4.7.0
2.1.0
2.1.0
diff --git a/src/Extensions/Abstractions/Activities/ActivityExtensions.cs b/src/Extensions/Abstractions/Activities/ActivityExtensions.cs
new file mode 100644
index 00000000..32f4514b
--- /dev/null
+++ b/src/Extensions/Abstractions/Activities/ActivityExtensions.cs
@@ -0,0 +1,94 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System;
+using System.Diagnostics;
+using System.Globalization;
+
+namespace Microsoft.Omex.Extensions.Abstractions.Activities
+{
+ ///
+ /// Extensions for Activity
+ ///
+ public static class ActivityExtensions
+ {
+ ///
+ /// Get user hash from activity
+ ///
+ public static string GetUserHash(this Activity activity) =>
+ activity.GetBaggageItem(UserHashKey) ?? string.Empty;
+
+
+ ///
+ /// Returns true if activity is transaction
+ ///
+ public static bool IsTransaction(this Activity activity) =>
+ string.Equals(
+ activity.GetBaggageItem(TransactionMarkerKey),
+ TransactionMarkerValue,
+ StringComparison.OrdinalIgnoreCase);
+
+
+ ///
+ /// Set user hash for the activity
+ ///
+ /// This property would be transfered to child activity and via web requests
+ public static Activity SetUserHash(this Activity activity, string userHash) =>
+ activity.AddBaggage(UserHashKey, userHash);
+
+
+ ///
+ /// Mark activity as transaction
+ ///
+ /// This property would be transfered to child activity and via web requests
+ public static Activity MarkAsTransaction(this Activity activity) =>
+ activity.AddBaggage(TransactionMarkerKey, TransactionMarkerValue);
+
+
+ ///
+ /// Get correlation guid that is used by old Omex services
+ ///
+ [Obsolete(CorrelationIdObsoleteMessage, false)]
+ public static Guid? GetObsoleteCorrelationId(this Activity activity) =>
+ Guid.TryParse(activity.GetBaggageItem(ObsoleteCorrelationId), out Guid correlation)
+ ? correlation
+ : (Guid?)null;
+
+
+ ///
+ /// Set correlation guid that is used by old Omex services
+ ///
+ /// This property would be transfered to child activity and via web requests
+ [Obsolete(CorrelationIdObsoleteMessage, false)]
+ public static Activity SetObsoleteCorrelationId(this Activity activity, Guid correlation) =>
+ activity.AddBaggage(ObsoleteCorrelationId, correlation.ToString());
+
+
+ ///
+ /// Get transaction id that is used by old Omex services
+ ///
+ [Obsolete(TransactionIdObsoleteMessage, false)]
+ public static uint? GetObsolteteTransactionId(this Activity activity) =>
+ uint.TryParse(activity.GetBaggageItem(ObsoleteTransactionId), out uint transactionId)
+ ? transactionId
+ : (uint?)null;
+
+
+ ///
+ /// Set transaction id that is used by old Omex services
+ ///
+ /// This property would be transfered to child activity and via web requests
+ [Obsolete(TransactionIdObsoleteMessage, false)]
+ public static Activity SetObsoleteTransactionId(this Activity activity, uint transactionId) =>
+ activity.AddBaggage(ObsoleteTransactionId, transactionId.ToString(CultureInfo.InvariantCulture));
+
+
+ private const string UserHashKey = "UserHash";
+ private const string TransactionMarkerKey = "TransactionMarkerKey";
+ private const string TransactionMarkerValue = "true";
+ private const string ObsoleteCorrelationId = "ObsoleteCorrelationId";
+ private const string ObsoleteTransactionId = "ObsoleteTransactionId";
+ private const string CorrelationIdObsoleteMessage = "Please use Activity.Id for new services instead";
+ private const string TransactionIdObsoleteMessage = "Please use Activity.TraceId for new services instead";
+ }
+}
diff --git a/src/Extensions/TimedScopes/ITimedScopeProvider.cs b/src/Extensions/Abstractions/Activities/ITimedScopeProvider.cs
similarity index 76%
rename from src/Extensions/TimedScopes/ITimedScopeProvider.cs
rename to src/Extensions/Abstractions/Activities/ITimedScopeProvider.cs
index 51000d50..44ec8ba1 100644
--- a/src/Extensions/TimedScopes/ITimedScopeProvider.cs
+++ b/src/Extensions/Abstractions/Activities/ITimedScopeProvider.cs
@@ -1,9 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
-using Microsoft.Omex.Extensions.Abstractions;
-
-namespace Microsoft.Omex.Extensions.TimedScopes
+namespace Microsoft.Omex.Extensions.Abstractions.Activities
{
///
/// Interface to create TimedScope
@@ -13,12 +11,12 @@ public interface ITimedScopeProvider
///
/// Creates and start TimedScope
///
- TimedScope CreateAndStart(TimedScopeDefinition name, TimedScopeResult result);
+ TimedScope CreateAndStart(TimedScopeDefinition name, TimedScopeResult result = TimedScopeResult.SystemError);
///
/// Creates TimedScope
///
- TimedScope Create(TimedScopeDefinition name, TimedScopeResult result);
+ TimedScope Create(TimedScopeDefinition name, TimedScopeResult result = TimedScopeResult.SystemError);
}
}
diff --git a/src/Extensions/Abstractions/Activities/Processing/ActivityResultStrings.cs b/src/Extensions/Abstractions/Activities/Processing/ActivityResultStrings.cs
new file mode 100644
index 00000000..821c8fdf
--- /dev/null
+++ b/src/Extensions/Abstractions/Activities/Processing/ActivityResultStrings.cs
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System;
+
+namespace Microsoft.Omex.Extensions.Abstractions.Activities.Processing
+{
+ ///
+ /// Class with activity result enum string values to avoid alocations
+ ///
+ public static class ActivityResultStrings
+ {
+ ///
+ /// Activity SystemError result string
+ ///
+ public static string SystemError { get; } = "SystemError";
+
+
+ ///
+ /// Activity ExpectedError result string
+ ///
+ public static string ExpectedError { get; } = "ExpectedError";
+
+
+ ///
+ /// Activity Success result string
+ ///
+ public static string Success { get; } = "Success";
+
+
+ ///
+ /// Activity Unknown result string
+ ///
+ public static string Unknown { get; } = "Unknown";
+
+
+ ///
+ /// Returns corresponding to enum string value with creating new string
+ ///
+ public static string ResultToString(TimedScopeResult result) =>
+ result switch
+ {
+ TimedScopeResult.SystemError => SystemError,
+ TimedScopeResult.ExpectedError => ExpectedError,
+ TimedScopeResult.Success => Success,
+ _ => throw new ArgumentException(FormattableString.Invariant($"Unsupported enum value '{result}'"))
+ };
+ }
+}
diff --git a/src/Extensions/Abstractions/Activities/Processing/ActivityTagKeys.cs b/src/Extensions/Abstractions/Activities/Processing/ActivityTagKeys.cs
new file mode 100644
index 00000000..e68cdfe6
--- /dev/null
+++ b/src/Extensions/Abstractions/Activities/Processing/ActivityTagKeys.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Microsoft.Omex.Extensions.Abstractions.Activities.Processing
+{
+ ///
+ /// Activity does not have methods to extract tags efficiently, so we need to expose keys to provide ability of extracting tags
+ ///
+ public static class ActivityTagKeys
+ {
+ ///
+ /// Activity result tag key
+ ///
+ public static string Result { get; } = "Result";
+
+
+ ///
+ /// Activity sub type tag key
+ ///
+ public static string SubType { get; } = "SubType";
+
+
+ ///
+ /// Activity metadata tag key
+ ///
+ public static string Metadata { get; } = "Metadata";
+ }
+}
diff --git a/src/Extensions/Abstractions/ReplayableLogs/IActivityProvider.cs b/src/Extensions/Abstractions/Activities/Processing/IActivityProvider.cs
similarity index 67%
rename from src/Extensions/Abstractions/ReplayableLogs/IActivityProvider.cs
rename to src/Extensions/Abstractions/Activities/Processing/IActivityProvider.cs
index 7dd01095..8d04b807 100644
--- a/src/Extensions/Abstractions/ReplayableLogs/IActivityProvider.cs
+++ b/src/Extensions/Abstractions/Activities/Processing/IActivityProvider.cs
@@ -3,11 +3,12 @@
using System.Diagnostics;
-namespace Microsoft.Omex.Extensions.Abstractions.ReplayableLogs
+namespace Microsoft.Omex.Extensions.Abstractions.Activities.Processing
{
///
/// Provides activities
///
+ /// This interface would be deleted after move to net 5.0, since inheritance won't be a supported extension model for Activity
public interface IActivityProvider
{
///
diff --git a/src/Extensions/Abstractions/Activities/Processing/IActivityStartObserver.cs b/src/Extensions/Abstractions/Activities/Processing/IActivityStartObserver.cs
new file mode 100644
index 00000000..bebca40b
--- /dev/null
+++ b/src/Extensions/Abstractions/Activities/Processing/IActivityStartObserver.cs
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.Diagnostics;
+
+namespace Microsoft.Omex.Extensions.Abstractions.Activities.Processing
+{
+ ///
+ /// Interface to monitor activity start
+ ///
+ public interface IActivityStartObserver
+ {
+ ///
+ /// Method will be called after activity start
+ ///
+ void OnStart(Activity activity, object? payload);
+ }
+}
diff --git a/src/Extensions/Abstractions/Activities/Processing/IActivityStopObserver.cs b/src/Extensions/Abstractions/Activities/Processing/IActivityStopObserver.cs
new file mode 100644
index 00000000..b67641cf
--- /dev/null
+++ b/src/Extensions/Abstractions/Activities/Processing/IActivityStopObserver.cs
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.Diagnostics;
+
+namespace Microsoft.Omex.Extensions.Abstractions.Activities.Processing
+{
+ ///
+ /// Interface to monitor activity stop
+ ///
+ public interface IActivityStopObserver
+ {
+ ///
+ /// Method will be called after activity stop
+ ///
+ void OnStop(Activity activity, object? payload);
+ }
+}
diff --git a/src/Extensions/TimedScopes/TaskExtensions.cs b/src/Extensions/Abstractions/Activities/TaskExtensions.cs
similarity index 89%
rename from src/Extensions/TimedScopes/TaskExtensions.cs
rename to src/Extensions/Abstractions/Activities/TaskExtensions.cs
index 1a3b4317..226d5e16 100644
--- a/src/Extensions/TimedScopes/TaskExtensions.cs
+++ b/src/Extensions/Abstractions/Activities/TaskExtensions.cs
@@ -2,9 +2,8 @@
// Licensed under the MIT license.
using System.Threading.Tasks;
-using Microsoft.Omex.Extensions.Abstractions;
-namespace Microsoft.Omex.Extensions.TimedScopes
+namespace Microsoft.Omex.Extensions.Abstractions.Activities
{
///
/// Extensions for Task to wrap them in TimedScope
@@ -18,7 +17,7 @@ public static async ValueTask WithTimedScope(this ValueTask
+ /// Logs duration of activity
+ ///
+ /// This class will be replaced with Activity after move to net 5, since it will be trackable and disposable
+ public class TimedScope : IDisposable
+ {
+ ///
+ /// Creates TimedScope instance
+ ///
+ /// activity connected to this timedscope
+ /// TimedScope initial result
+ public TimedScope(Activity activity, TimedScopeResult result)
+ {
+ Activity = activity;
+ this.SetResult(result);
+ }
+
+
+ ///
+ /// Starts TimedScope activity
+ ///
+ public TimedScope Start()
+ {
+ s_listener.StartActivity(Activity, this);
+ return this;
+ }
+
+
+ ///
+ /// Stop TimedScope and log informations about it
+ ///
+ public void Stop() => s_listener.StopActivity(Activity, this);
+
+
+ internal Activity Activity { get; }
+
+
+ void IDisposable.Dispose() => Stop();
+
+
+ private static readonly DiagnosticListener s_listener = new DiagnosticListener("TimedScopesListener");
+ }
+}
diff --git a/src/Extensions/Abstractions/TimedScopeDefinition.cs b/src/Extensions/Abstractions/Activities/TimedScopeDefinition.cs
similarity index 97%
rename from src/Extensions/Abstractions/TimedScopeDefinition.cs
rename to src/Extensions/Abstractions/Activities/TimedScopeDefinition.cs
index 9976e4e0..00e05f9c 100644
--- a/src/Extensions/Abstractions/TimedScopeDefinition.cs
+++ b/src/Extensions/Abstractions/Activities/TimedScopeDefinition.cs
@@ -3,7 +3,7 @@
using System;
-namespace Microsoft.Omex.Extensions.Abstractions
+namespace Microsoft.Omex.Extensions.Abstractions.Activities
{
///
/// Store Timed Scope name
diff --git a/src/Extensions/TimedScopes/TimedScopeResult.cs b/src/Extensions/Abstractions/Activities/TimedScopeResult.cs
similarity index 89%
rename from src/Extensions/TimedScopes/TimedScopeResult.cs
rename to src/Extensions/Abstractions/Activities/TimedScopeResult.cs
index 624adcba..94292a3b 100644
--- a/src/Extensions/TimedScopes/TimedScopeResult.cs
+++ b/src/Extensions/Abstractions/Activities/TimedScopeResult.cs
@@ -4,7 +4,7 @@
using System;
using System.Runtime.Serialization;
-namespace Microsoft.Omex.Extensions.TimedScopes
+namespace Microsoft.Omex.Extensions.Abstractions.Activities
{
///
/// Defines the possible scope results
@@ -21,7 +21,7 @@ public enum TimedScopeResult : int
///
/// Result should always be set to one of the other values explicitly. Unknown causes an error to be logged, and the scope is assumed failed.
[EnumMember]
- [Obsolete("Default value, not to be used explicitly", error: true)]
+ [Obsolete("Default value, not to be used explicitly", error: false)]
Unknown = 0,
diff --git a/src/Extensions/Abstractions/Activities/TimedScopesExtensions.cs b/src/Extensions/Abstractions/Activities/TimedScopesExtensions.cs
new file mode 100644
index 00000000..a6b43695
--- /dev/null
+++ b/src/Extensions/Abstractions/Activities/TimedScopesExtensions.cs
@@ -0,0 +1,45 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
+
+namespace Microsoft.Omex.Extensions.Abstractions.Activities
+{
+ ///
+ /// Extensions to TimedScopes class to set additional information
+ ///
+ public static class TimedScopesExtensions
+ {
+ ///
+ /// Set result
+ ///
+ /// This property won't be transfered to child activity or via web requests
+ public static TimedScope SetResult(this TimedScope timedScope, TimedScopeResult result)
+ {
+ timedScope.Activity.AddTag(ActivityTagKeys.Result, ActivityResultStrings.ResultToString(result));
+ return timedScope;
+ }
+
+
+ ///
+ /// Set sub type
+ ///
+ /// This property won't be transfered to child activity or via web requests
+ public static TimedScope SetSubType(this TimedScope timedScope, string subType)
+ {
+ timedScope.Activity.AddTag(ActivityTagKeys.SubType, subType);
+ return timedScope;
+ }
+
+
+ ///
+ /// Set metadata
+ ///
+ /// This property won't be transfered to child activity or via web requests
+ public static TimedScope SetMetadata(this TimedScope timedScope, string metadata)
+ {
+ timedScope.Activity.AddTag(ActivityTagKeys.Metadata, metadata);
+ return timedScope;
+ }
+ }
+}
diff --git a/src/Extensions/Abstractions/Microsoft.Omex.Extensions.Abstractions.csproj b/src/Extensions/Abstractions/Microsoft.Omex.Extensions.Abstractions.csproj
index 70c67353..5cace99f 100644
--- a/src/Extensions/Abstractions/Microsoft.Omex.Extensions.Abstractions.csproj
+++ b/src/Extensions/Abstractions/Microsoft.Omex.Extensions.Abstractions.csproj
@@ -8,6 +8,9 @@
+
+
+
diff --git a/src/Extensions/Compatibility/OmexCompatibilityIntializer.cs b/src/Extensions/Compatibility/OmexCompatibilityIntializer.cs
index 46d33b72..6b496e9c 100644
--- a/src/Extensions/Compatibility/OmexCompatibilityIntializer.cs
+++ b/src/Extensions/Compatibility/OmexCompatibilityIntializer.cs
@@ -5,10 +5,10 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.Omex.Extensions.Compatibility.Logger;
using Microsoft.Omex.Extensions.Compatibility.TimedScopes;
using Microsoft.Omex.Extensions.Compatibility.Validation;
-using Microsoft.Omex.Extensions.TimedScopes;
namespace Microsoft.Omex.Extensions.Compatibility
{
diff --git a/src/Extensions/Compatibility/ServiceCollectionExtensions.cs b/src/Extensions/Compatibility/ServiceCollectionExtensions.cs
index f460d60b..e425e323 100644
--- a/src/Extensions/Compatibility/ServiceCollectionExtensions.cs
+++ b/src/Extensions/Compatibility/ServiceCollectionExtensions.cs
@@ -17,7 +17,7 @@ public static class ServiceCollectionExtensions
public static IHostBuilder AddOmexCompatibilityServices(this IHostBuilder builder) =>
builder.ConfigureServices((context, collection) =>
{
- collection.AddTransient();
+ collection.AddHostedService();
});
}
}
diff --git a/src/Extensions/Compatibility/TimedScopes/TimedScopeDefinitionExtensions.cs b/src/Extensions/Compatibility/TimedScopes/TimedScopeDefinitionExtensions.cs
index 6e372d90..fed02696 100644
--- a/src/Extensions/Compatibility/TimedScopes/TimedScopeDefinitionExtensions.cs
+++ b/src/Extensions/Compatibility/TimedScopes/TimedScopeDefinitionExtensions.cs
@@ -2,8 +2,7 @@
// Licensed under the MIT license.
using System;
-using Microsoft.Omex.Extensions.Abstractions;
-using Microsoft.Omex.Extensions.TimedScopes;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
namespace Microsoft.Omex.Extensions.Compatibility.TimedScopes
{
diff --git a/src/Extensions/Hosting.Services/HostBuilderExtensions.cs b/src/Extensions/Hosting.Services/HostBuilderExtensions.cs
index 17ef7468..f15c2bdb 100644
--- a/src/Extensions/Hosting.Services/HostBuilderExtensions.cs
+++ b/src/Extensions/Hosting.Services/HostBuilderExtensions.cs
@@ -126,8 +126,8 @@ private static IHost BuildServiceFabricService(
{
collection
.AddOmexServiceFabricDependencies()
- .AddTransient()
- .AddSingleton();
+ .AddSingleton()
+ .AddHostedService();
})
.UseDefaultServiceProvider(options =>
{
diff --git a/src/Extensions/Hosting.Services/Internal/OmexHostedService.cs b/src/Extensions/Hosting.Services/Internal/OmexHostedService.cs
index e8589048..402356f7 100644
--- a/src/Extensions/Hosting.Services/Internal/OmexHostedService.cs
+++ b/src/Extensions/Hosting.Services/Internal/OmexHostedService.cs
@@ -14,58 +14,24 @@ namespace Microsoft.Omex.Extensions.Hosting.Services
///
/// Wraps service run into HostedService
///
- internal sealed class OmexHostedService : IHostedService
+ internal sealed class OmexHostedService : BackgroundService
{
- private readonly IHostApplicationLifetime m_lifetime;
private readonly IOmexServiceRunner m_runner;
private readonly ILogger m_logger;
- private readonly CancellationTokenSource m_tokenSource;
- public OmexHostedService(IOmexServiceRunner runner, IHostApplicationLifetime lifetime, ILogger logger)
+ public OmexHostedService(IOmexServiceRunner runner, ILogger logger)
{
m_runner = runner;
- m_lifetime = lifetime;
m_logger = logger;
- m_tokenSource = new CancellationTokenSource();
}
- public Task StartAsync(CancellationToken cancellationToken)
- {
- m_lifetime.ApplicationStarted.Register(OnServiceStarted);
- m_lifetime.ApplicationStopping.Register(OnServiceStopping);
- return Task.CompletedTask;
- }
-
-
- public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
-
-
- private void OnServiceStarted()
- {
- RunServiceAsync()
- .ContinueWith(OnRunnerCompleted)
- .ConfigureAwait(false);
- }
-
-
- private void OnServiceStopping()
- {
- if (m_tokenSource.IsCancellationRequested)
- {
- return;
- }
-
- m_tokenSource.Cancel();
- }
-
-
- private async Task RunServiceAsync()
+ protected override async Task ExecuteAsync(CancellationToken token)
{
try
{
- ConfiguredTaskAwaitable task = m_runner.RunServiceAsync(m_tokenSource.Token).ConfigureAwait(false);
+ ConfiguredTaskAwaitable task = m_runner.RunServiceAsync(token).ConfigureAwait(false);
m_logger.LogInformation(Tag.Create(), "ServiceFabricHost initialized");
@@ -77,25 +43,5 @@ private async Task RunServiceAsync()
throw;
}
}
-
-
- private Task OnRunnerCompleted(Task task)
- {
- if (task.IsFaulted)
- {
- m_logger.LogCritical(Tag.Create(), task.Exception, "Service stoped due to exeption");
- }
- else if (task.IsCanceled)
- {
- m_logger.LogInformation(Tag.Create(), "Service canceled");
- }
- else
- {
- m_logger.LogInformation(Tag.Create(), "Service stopped");
- }
-
- m_lifetime.StopApplication();
- return Task.CompletedTask;
- }
}
}
diff --git a/src/Extensions/Logging/ILogEventSender.cs b/src/Extensions/Logging/ILogEventSender.cs
index 4307296b..0faeb234 100644
--- a/src/Extensions/Logging/ILogEventSender.cs
+++ b/src/Extensions/Logging/ILogEventSender.cs
@@ -32,6 +32,6 @@ public interface ILogEventSender
/// event Id
/// Id of the thread
/// Log message
- void LogMessage(Activity activity, string category, LogLevel level, EventId eventId, int threadId, string message);
+ void LogMessage(Activity? activity, string category, LogLevel level, EventId eventId, int threadId, string message);
}
}
diff --git a/src/Extensions/Logging/Internal/EventSource/ActivityEnhancementObserver.cs b/src/Extensions/Logging/Internal/EventSource/ActivityEnhancementObserver.cs
new file mode 100644
index 00000000..ff3e25f7
--- /dev/null
+++ b/src/Extensions/Logging/Internal/EventSource/ActivityEnhancementObserver.cs
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System;
+using System.Diagnostics;
+using Microsoft.Extensions.Options;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
+
+namespace Microsoft.Omex.Extensions.Logging
+{
+ internal class ActivityEnhancementObserver : IActivityStartObserver
+ {
+ private readonly IOptions m_options;
+
+ public ActivityEnhancementObserver(IOptions options)
+ {
+ m_options = options;
+ }
+
+ public void OnStart(Activity activity, object? payload)
+ {
+ if (m_options.Value.AddObsoleteCorrelationToActivity)
+ {
+#pragma warning disable CS0618 // if we are supporting old correlation we need to add it for new activities
+ if (activity.GetObsoleteCorrelationId() == null)
+ {
+ activity.SetObsoleteCorrelationId(Guid.NewGuid());
+ }
+#pragma warning disable CS0618
+ }
+ }
+ }
+}
diff --git a/src/Extensions/Logging/Internal/EventSource/OmexLogEventSender.cs b/src/Extensions/Logging/Internal/EventSource/OmexLogEventSender.cs
index 6c097da5..2eb8e961 100644
--- a/src/Extensions/Logging/Internal/EventSource/OmexLogEventSender.cs
+++ b/src/Extensions/Logging/Internal/EventSource/OmexLogEventSender.cs
@@ -4,9 +4,9 @@
using System;
using System.Diagnostics;
using System.Globalization;
-using System.Text;
using Microsoft.Extensions.Logging;
-using Microsoft.Omex.Extensions.Abstractions.ReplayableLogs;
+using Microsoft.Extensions.Options;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.Omex.Extensions.Logging.Replayable;
namespace Microsoft.Omex.Extensions.Logging
@@ -20,65 +20,88 @@ static OmexLogEventSender()
}
- public OmexLogEventSender(OmexLogEventSource eventSource, IExecutionContext machineInformation, IServiceContext context)
+ public OmexLogEventSender(OmexLogEventSource eventSource, IExecutionContext executionContext, IServiceContext context, IOptions options)
{
m_eventSource = eventSource;
- m_machineInformation = machineInformation;
+ m_executionContext = executionContext;
m_serviceContext = context;
+ m_options = options;
}
- public void LogMessage(Activity activity, string category, LogLevel level, EventId eventId, int threadId, string message)
+ public void LogMessage(Activity? activity, string category, LogLevel level, EventId eventId, int threadId, string message)
{
if (!IsEnabled(level))
{
return;
}
- string activityId = activity?.Id ?? string.Empty;
- ActivityTraceId traceId = activity?.TraceId ?? default;
Guid partitionId = m_serviceContext.PartitionId;
long replicaId = m_serviceContext.ReplicaOrInstanceId;
- string applicationName = m_machineInformation.ApplicationName;
- string serviceName = m_machineInformation.ServiceName;
- string buildVersion = m_machineInformation.BuildVersion;
- string machineId = m_machineInformation.MachineId;
+ string applicationName = m_executionContext.ApplicationName;
+ string serviceName = m_executionContext.ServiceName;
+ string buildVersion = m_executionContext.BuildVersion;
+ string machineId = m_executionContext.MachineId;
string tagName = eventId.Name;
// In case if tag created using Tag.Create (line number and file in description) it's better to display decimal number
string tagId = string.IsNullOrWhiteSpace(eventId.Name)
-#pragma warning disable 618 // need to be used for to process reserved tags from GitTagger
+#pragma warning disable CS0618 // Need to be used for to process reserved tags from GitTagger
? TagsExtensions.TagIdAsString(eventId.Id)
-#pragma warning restore 618
+#pragma warning restore CS0618
: eventId.Id.ToString(CultureInfo.InvariantCulture);
- string traceIdAsString = traceId.ToHexString();
+ string activityId = string.Empty;
+ ActivityTraceId activityTraceId = default;
+ Guid obsoleteCorrelationId = Guid.Empty;
+ uint obsoleteTransactionId = 0u;
+ if (activity != null)
+ {
+ activityId = activity.Id ?? string.Empty;
+ activityTraceId = activity.TraceId;
+
+ if (m_options.Value.AddObsoleteCorrelationToActivity)
+ {
+#pragma warning disable CS0618 // We are using obsolete correlation to support logging correlation from old Omex services
+ obsoleteCorrelationId = activity.GetObsoleteCorrelationId() ?? Guid.Empty;
+ obsoleteTransactionId = activity.GetObsolteteTransactionId() ?? 0u;
+#pragma warning restore CS0618
+ }
+ }
+
+ string traceIdAsString = activityTraceId.ToHexString();
//Event methods should have all information as parameters so we are passing them each time
// Posible Breaking changes:
- // 1. CorrelationId type changed from Guid ?? Guid.Empty
- // 2. TransactionId type Changed from uint ?? 0u
- // 3. ThreadId type Changed from string
- // 4. TagName to events so it should be also send
+ // 1. ThreadId type Changed from string to avoid useless string creation
+ // 2. New fileds added:
+ // a. tagName to events since it will have more useful information
+ // b. activityId required for tracking net core activity
+ // c. activityTraceId required for tracking net core activity
switch (level)
{
case LogLevel.None:
break;
case LogLevel.Trace:
- m_eventSource.LogSpamServiceMessage(applicationName, serviceName, machineId, buildVersion, s_processName, partitionId, replicaId, activityId, traceIdAsString, "Spam", category, tagId, tagName, threadId, message);
+ m_eventSource.LogSpamServiceMessage(applicationName, serviceName, machineId, buildVersion, s_processName, partitionId, replicaId,
+ activityId, traceIdAsString, obsoleteCorrelationId, obsoleteTransactionId, "Spam", category, tagId, tagName, threadId, message);
break;
case LogLevel.Debug:
- m_eventSource.LogVerboseServiceMessage(applicationName, serviceName, machineId, buildVersion, s_processName, partitionId, replicaId, activityId, traceIdAsString, "Verbose", category, tagId, tagName, threadId, message);
+ m_eventSource.LogVerboseServiceMessage(applicationName, serviceName, machineId, buildVersion, s_processName, partitionId, replicaId,
+ activityId, traceIdAsString, obsoleteCorrelationId, obsoleteTransactionId, "Verbose", category, tagId, tagName, threadId, message);
break;
case LogLevel.Information:
- m_eventSource.LogInfoServiceMessage(applicationName, serviceName, machineId, buildVersion, s_processName, partitionId, replicaId, activityId, traceIdAsString, "Info", category, tagId, tagName, threadId, message);
+ m_eventSource.LogInfoServiceMessage(applicationName, serviceName, machineId, buildVersion, s_processName, partitionId, replicaId,
+ activityId, traceIdAsString, obsoleteCorrelationId, obsoleteTransactionId, "Info", category, tagId, tagName, threadId, message);
break;
case LogLevel.Warning:
- m_eventSource.LogWarningServiceMessage(applicationName, serviceName, machineId, buildVersion, s_processName, partitionId, replicaId, activityId, traceIdAsString, "Warning", category, tagId, tagName, threadId, message);
+ m_eventSource.LogWarningServiceMessage(applicationName, serviceName, machineId, buildVersion, s_processName, partitionId, replicaId,
+ activityId, traceIdAsString, obsoleteCorrelationId, obsoleteTransactionId, "Warning", category, tagId, tagName, threadId, message);
break;
case LogLevel.Error:
case LogLevel.Critical:
- m_eventSource.LogErrorServiceMessage(applicationName, serviceName, machineId, buildVersion, s_processName, partitionId, replicaId, activityId, traceIdAsString, "Error", category, tagId, eventId.Name, threadId, message);
+ m_eventSource.LogErrorServiceMessage(applicationName, serviceName, machineId, buildVersion, s_processName, partitionId, replicaId,
+ activityId, traceIdAsString, obsoleteCorrelationId, obsoleteTransactionId, "Error", category, tagId, eventId.Name, threadId, message);
break;
default:
throw new ArgumentException(FormattableString.Invariant($"Unknown EventLevel: {level}"));
@@ -123,7 +146,8 @@ public void ReplayLogs(Activity activity)
private readonly OmexLogEventSource m_eventSource;
private readonly IServiceContext m_serviceContext;
- private readonly IExecutionContext m_machineInformation;
+ private readonly IOptions m_options;
+ private readonly IExecutionContext m_executionContext;
private static readonly string s_processName;
}
}
diff --git a/src/Extensions/Logging/Internal/EventSource/OmexLogEventSource.cs b/src/Extensions/Logging/Internal/EventSource/OmexLogEventSource.cs
index c9f4db52..d5816746 100644
--- a/src/Extensions/Logging/Internal/EventSource/OmexLogEventSource.cs
+++ b/src/Extensions/Logging/Internal/EventSource/OmexLogEventSource.cs
@@ -19,15 +19,18 @@ public void LogErrorServiceMessage(
string processName,
Guid partitionId,
long replicaId,
- string correlationId,
- string transactionId,
+ string activityId,
+ string activityTraceId,
+ Guid correlationId,
+ uint transactionId,
string level,
string category,
string tagId,
string tagName,
int threadId,
string message) =>
- WriteEvent((int)EventSourcesEventIds.LogError, applicationName, serviceName, agentName, buildVersion, processName, partitionId, replicaId, correlationId, transactionId, level, category, tagId, tagName, threadId, message);
+ WriteEvent((int)EventSourcesEventIds.LogError, applicationName, serviceName, agentName, buildVersion, processName, partitionId, replicaId,
+ activityId, activityTraceId, correlationId, transactionId, level, category, tagId, tagName, threadId, message);
[Event((int)EventSourcesEventIds.LogWarning, Level = EventLevel.Warning, Message = "{13}", Version = 6)]
@@ -39,15 +42,18 @@ public void LogWarningServiceMessage(
string processName,
Guid partitionId,
long replicaId,
- string correlationId,
- string transactionId,
+ string activityId,
+ string activityTraceId,
+ Guid correlationId,
+ uint transactionId,
string level,
string category,
string tagId,
string tagName,
int threadId,
string message) =>
- WriteEvent((int)EventSourcesEventIds.LogWarning, applicationName, serviceName, agentName, buildVersion, processName, partitionId, replicaId, correlationId, transactionId, level, category, tagId, tagName, threadId, message);
+ WriteEvent((int)EventSourcesEventIds.LogWarning, applicationName, serviceName, agentName, buildVersion, processName, partitionId, replicaId,
+ activityId, activityTraceId, correlationId, transactionId, level, category, tagId, tagName, threadId, message);
[Event((int)EventSourcesEventIds.LogInfo, Level = EventLevel.Informational, Message = "{13}", Version = 6)]
@@ -59,15 +65,18 @@ public void LogInfoServiceMessage(
string processName,
Guid partitionId,
long replicaId,
- string correlationId,
- string transactionId,
+ string activityId,
+ string activityTraceId,
+ Guid correlationId,
+ uint transactionId,
string level,
string category,
string tagId,
string tagName,
int threadId,
string message) =>
- WriteEvent((int)EventSourcesEventIds.LogInfo, applicationName, serviceName, agentName, buildVersion, processName, partitionId, replicaId, correlationId, transactionId, level, category, tagId, tagName, threadId, message);
+ WriteEvent((int)EventSourcesEventIds.LogInfo, applicationName, serviceName, agentName, buildVersion, processName, partitionId, replicaId,
+ activityId, activityTraceId, correlationId, transactionId, level, category, tagId, tagName, threadId, message);
[Event((int)EventSourcesEventIds.LogVerbose, Level = EventLevel.Verbose, Message = "{13}", Version = 6)]
@@ -79,15 +88,18 @@ public void LogVerboseServiceMessage(
string processName,
Guid partitionId,
long replicaId,
- string correlationId,
- string transactionId,
+ string activityId,
+ string activityTraceId,
+ Guid correlationId,
+ uint transactionId,
string level,
string category,
string tagId,
string tagName,
int threadId,
string message) =>
- WriteEvent((int)EventSourcesEventIds.LogVerbose, applicationName, serviceName, agentName, buildVersion, processName, partitionId, replicaId, correlationId, transactionId, level, category, tagId, tagName, threadId, message);
+ WriteEvent((int)EventSourcesEventIds.LogVerbose, applicationName, serviceName, agentName, buildVersion, processName, partitionId, replicaId,
+ activityId, activityTraceId, correlationId, transactionId, level, category, tagId, tagName, threadId, message);
[Event((int)EventSourcesEventIds.LogSpam, Level = EventLevel.Verbose, Message = "{13}", Version = 6)]
@@ -99,15 +111,18 @@ public void LogSpamServiceMessage(
string processName,
Guid partitionId,
long replicaId,
- string correlationId,
- string transactionId,
+ string activityId,
+ string activityTraceId,
+ Guid correlationId,
+ uint transactionId,
string level,
string category,
string tagId,
string tagName,
int threadId,
string message) =>
- WriteEvent((int)EventSourcesEventIds.LogSpam, applicationName, serviceName, agentName, buildVersion, processName, partitionId, replicaId, correlationId, transactionId, level, category, tagId, tagName, threadId, message);
+ WriteEvent((int)EventSourcesEventIds.LogSpam, applicationName, serviceName, agentName, buildVersion, processName, partitionId, replicaId,
+ activityId, activityTraceId, correlationId, transactionId, level, category, tagId, tagName, threadId, message);
public static OmexLogEventSource Instance { get; } = new OmexLogEventSource();
diff --git a/src/Extensions/Logging/Internal/OmexLogger.cs b/src/Extensions/Logging/Internal/OmexLogger.cs
index 0cd13a34..6fe70fce 100644
--- a/src/Extensions/Logging/Internal/OmexLogger.cs
+++ b/src/Extensions/Logging/Internal/OmexLogger.cs
@@ -34,7 +34,7 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except
string message = formatter(state, exception);
int threadId = Thread.CurrentThread.ManagedThreadId;
- Activity activity = Activity.Current;
+ Activity? activity = Activity.Current;
m_logsEventSender.LogMessage(activity, m_categoryName, logLevel, eventId, threadId, message);
diff --git a/src/Extensions/Abstractions/ReplayableLogs/ILogEventReplayer.cs b/src/Extensions/Logging/Internal/Replayable/ILogEventReplayer.cs
similarity index 80%
rename from src/Extensions/Abstractions/ReplayableLogs/ILogEventReplayer.cs
rename to src/Extensions/Logging/Internal/Replayable/ILogEventReplayer.cs
index 67bf7b70..0421acd7 100644
--- a/src/Extensions/Abstractions/ReplayableLogs/ILogEventReplayer.cs
+++ b/src/Extensions/Logging/Internal/Replayable/ILogEventReplayer.cs
@@ -3,12 +3,12 @@
using System.Diagnostics;
-namespace Microsoft.Omex.Extensions.Abstractions.ReplayableLogs
+namespace Microsoft.Omex.Extensions.Logging.Replayable
{
///
/// Replays activity logs if activity collects them
///
- public interface ILogEventReplayer
+ internal interface ILogEventReplayer
{
///
/// Replays activity logs if activity supports it
diff --git a/src/Extensions/Logging/Internal/Replayable/ReplayableActivityProvider.cs b/src/Extensions/Logging/Internal/Replayable/ReplayableActivityProvider.cs
index ffc8eae4..8e785124 100644
--- a/src/Extensions/Logging/Internal/Replayable/ReplayableActivityProvider.cs
+++ b/src/Extensions/Logging/Internal/Replayable/ReplayableActivityProvider.cs
@@ -3,8 +3,8 @@
using System.Diagnostics;
using Microsoft.Extensions.Options;
-using Microsoft.Omex.Extensions.Abstractions;
-using Microsoft.Omex.Extensions.Abstractions.ReplayableLogs;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
namespace Microsoft.Omex.Extensions.Logging.Replayable
{
diff --git a/src/Extensions/Logging/Internal/Replayable/ReplayableActivityStopObserver.cs b/src/Extensions/Logging/Internal/Replayable/ReplayableActivityStopObserver.cs
new file mode 100644
index 00000000..5b26393b
--- /dev/null
+++ b/src/Extensions/Logging/Internal/Replayable/ReplayableActivityStopObserver.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System;
+using System.Diagnostics;
+using System.Linq;
+using Microsoft.Extensions.Options;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
+
+namespace Microsoft.Omex.Extensions.Logging.Replayable
+{
+ internal class ReplayableActivityStopObserver : IActivityStopObserver
+ {
+ private readonly ILogEventReplayer m_logReplayer;
+ private readonly IOptions m_options;
+
+ public ReplayableActivityStopObserver(ILogEventReplayer logReplayer, IOptions options)
+ {
+ m_logReplayer = logReplayer;
+ m_options = options;
+ }
+
+ public void OnStop(Activity activity, object? payload)
+ {
+ if (m_options.Value.ReplayLogsInCaseOfError && ShouldReplayEvents(activity))
+ {
+ m_logReplayer.ReplayLogs(activity);
+ }
+ }
+
+ private bool ShouldReplayEvents(Activity activity)
+ {
+ string resultTagValue = activity.Tags.FirstOrDefault(p => string.Equals(p.Key, ActivityTagKeys.Result, StringComparison.Ordinal)).Value;
+ return string.Equals(ActivityResultStrings.SystemError, resultTagValue, StringComparison.Ordinal);
+ }
+ }
+}
diff --git a/src/Extensions/Logging/OmexLoggingOptions.cs b/src/Extensions/Logging/OmexLoggingOptions.cs
index 2d8c363f..16edc5c2 100644
--- a/src/Extensions/Logging/OmexLoggingOptions.cs
+++ b/src/Extensions/Logging/OmexLoggingOptions.cs
@@ -15,6 +15,12 @@ public class OmexLoggingOptions
public bool ReplayLogsInCaseOfError { get; set; } = false;
+ ///
+ /// Enabling this option will add CorrelationId guid to activity that will increase its size
+ ///
+ public bool AddObsoleteCorrelationToActivity { get; set; } = false;
+
+
///
/// Maximum number of events that activity can store for replay
///
diff --git a/src/Extensions/Logging/ServiceCollectionExtensions.cs b/src/Extensions/Logging/ServiceCollectionExtensions.cs
index 7ee349a2..4f11a3a6 100644
--- a/src/Extensions/Logging/ServiceCollectionExtensions.cs
+++ b/src/Extensions/Logging/ServiceCollectionExtensions.cs
@@ -4,7 +4,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
-using Microsoft.Omex.Extensions.Abstractions.ReplayableLogs;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
using Microsoft.Omex.Extensions.Logging.Replayable;
namespace Microsoft.Omex.Extensions.Logging
@@ -48,13 +48,14 @@ public static IServiceCollection AddOmexLogging(this IServiceCollection serviceC
serviceCollection.TryAddTransient();
serviceCollection.TryAddTransient();
serviceCollection.TryAddTransient();
-
serviceCollection.TryAddTransient();
serviceCollection.TryAddSingleton(p => OmexLogEventSource.Instance);
serviceCollection.TryAddTransient();
serviceCollection.TryAddTransient();
+ serviceCollection.TryAddEnumerable(ServiceDescriptor.Transient());
+ serviceCollection.TryAddEnumerable(ServiceDescriptor.Transient());
serviceCollection.TryAddEnumerable(ServiceDescriptor.Singleton());
return serviceCollection;
}
diff --git a/src/Extensions/TimedScopes/ActivityExtensions.cs b/src/Extensions/TimedScopes/ActivityExtensions.cs
deleted file mode 100644
index c58b2ca4..00000000
--- a/src/Extensions/TimedScopes/ActivityExtensions.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-using System.Diagnostics;
-
-namespace Microsoft.Omex.Extensions.TimedScopes
-{
- ///
- /// Extensions for Activity
- ///
- public static class ActivityExtensions
- {
- ///
- /// Get user hash from activity
- ///
- public static string GetUserHash(this Activity activity) =>
- activity.GetBaggageItem(UserHashKey) ?? string.Empty;
-
-
- ///
- /// Returns true if activity is transaction
- ///
- public static bool IsTransaction(this Activity activity) =>
- string.Equals(
- activity.GetBaggageItem(TransactionMarkerKey),
- TransactionMarkerValue,
- StringComparison.OrdinalIgnoreCase);
-
-
- ///
- /// Set user hash for the activity
- ///
- public static void SetUserHash(this Activity activity, string userHash) =>
- activity.AddBaggage(UserHashKey, userHash);
-
-
- ///
- /// Mark activity as transaction
- ///
- public static void MarkAsTransaction(this Activity activity) =>
- activity.AddBaggage(TransactionMarkerKey, TransactionMarkerValue);
-
-
- private const string UserHashKey = "UserHash";
- private const string TransactionMarkerKey = "TransactionMarkerKey";
- private const string TransactionMarkerValue = "true";
- }
-}
diff --git a/src/Extensions/TimedScopes/ITimedScopeEventSource.cs b/src/Extensions/TimedScopes/ITimedScopeEventSender.cs
similarity index 67%
rename from src/Extensions/TimedScopes/ITimedScopeEventSource.cs
rename to src/Extensions/TimedScopes/ITimedScopeEventSender.cs
index 86eee93b..cd912f35 100644
--- a/src/Extensions/TimedScopes/ITimedScopeEventSource.cs
+++ b/src/Extensions/TimedScopes/ITimedScopeEventSender.cs
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
+using System.Diagnostics;
+
namespace Microsoft.Omex.Extensions.TimedScopes
{
///
@@ -9,9 +11,8 @@ namespace Microsoft.Omex.Extensions.TimedScopes
public interface ITimedScopeEventSender
{
///
- /// Log timed scope end information
+ /// Log information about activity stop
///
- /// Ended timed scope
- void LogTimedScopeEndEvent(TimedScope scope);
+ void LogActivityStop(Activity activity);
}
}
diff --git a/src/Extensions/TimedScopes/Internal/ActivityObserversIntializer.cs b/src/Extensions/TimedScopes/Internal/ActivityObserversIntializer.cs
new file mode 100644
index 00000000..61910e2b
--- /dev/null
+++ b/src/Extensions/TimedScopes/Internal/ActivityObserversIntializer.cs
@@ -0,0 +1,94 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
+
+namespace Microsoft.Omex.Extensions.TimedScopes
+{
+ internal sealed class ActivityObserversIntializer : IHostedService, IObserver, IObserver>
+ {
+ private readonly IActivityStartObserver[] m_activityStartObservers;
+ private readonly IActivityStopObserver[] m_activityStopObservers;
+ private readonly LinkedList m_disposables;
+ private IDisposable? m_observerLifetime;
+
+ public ActivityObserversIntializer(
+ IEnumerable activityStartObservers,
+ IEnumerable activityStopObservers)
+ {
+ m_activityStartObservers = activityStartObservers.ToArray();
+ m_activityStopObservers = activityStopObservers.ToArray();
+ m_disposables = new LinkedList();
+ }
+
+ public Task StartAsync(CancellationToken cancellationToken)
+ {
+ m_observerLifetime = DiagnosticListener.AllListeners.Subscribe(this);
+ return Task.CompletedTask;
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ foreach (IDisposable disposable in m_disposables)
+ {
+ disposable.Dispose();
+ }
+
+ m_observerLifetime?.Dispose();
+ return Task.CompletedTask;
+ }
+
+ private bool IsActivityStart(string eventName) => m_activityStartObservers.Length > 0 && eventName.EndsWith(".Start", StringComparison.Ordinal);
+
+ private bool IsActivityStop(string eventName) => m_activityStopObservers.Length > 0 && eventName.EndsWith(".Stop", StringComparison.Ordinal);
+
+ private bool IsEnabled(string eventName) => IsActivityStart(eventName) || IsActivityStop(eventName);
+
+ void IObserver.OnCompleted() { }
+
+ void IObserver.OnError(Exception error) { }
+
+ void IObserver.OnNext(DiagnosticListener value) => m_disposables.AddLast(value.Subscribe(this, IsEnabled));
+
+ void IObserver>.OnCompleted() { }
+
+ void IObserver>.OnError(Exception error) { }
+
+ void IObserver>.OnNext(KeyValuePair value)
+ {
+ Activity activity = Activity.Current;
+
+ if (IsActivityStart(value.Key))
+ {
+ OnActivityStarted(activity, value.Value);
+ }
+ else if (IsActivityStop(value.Key))
+ {
+ OnActivityStoped(activity, value.Value);
+ }
+ }
+
+ private void OnActivityStarted(Activity activity, object payload)
+ {
+ foreach (IActivityStartObserver startHandler in m_activityStartObservers)
+ {
+ startHandler.OnStart(activity, payload);
+ }
+ }
+
+ private void OnActivityStoped(Activity activity, object payload)
+ {
+ foreach (IActivityStopObserver stopHandler in m_activityStopObservers)
+ {
+ stopHandler.OnStop(activity, payload);
+ }
+ }
+ }
+}
diff --git a/src/Extensions/TimedScopes/Internal/ActivityStopObserver.cs b/src/Extensions/TimedScopes/Internal/ActivityStopObserver.cs
new file mode 100644
index 00000000..40a019d0
--- /dev/null
+++ b/src/Extensions/TimedScopes/Internal/ActivityStopObserver.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.Diagnostics;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
+
+namespace Microsoft.Omex.Extensions.TimedScopes
+{
+ internal sealed class ActivityStopObserver : IActivityStopObserver
+ {
+ private readonly ITimedScopeEventSender m_eventSender;
+
+ public ActivityStopObserver(ITimedScopeEventSender timedScopeEventSender) =>
+ m_eventSender = timedScopeEventSender;
+
+ public void OnStop(Activity activity, object? payload) =>
+ m_eventSender.LogActivityStop(activity);
+ }
+}
diff --git a/src/Extensions/TimedScopes/Internal/SimpleActivityProvider.cs b/src/Extensions/TimedScopes/Internal/SimpleActivityProvider.cs
index 199373b9..ca3dc4c5 100644
--- a/src/Extensions/TimedScopes/Internal/SimpleActivityProvider.cs
+++ b/src/Extensions/TimedScopes/Internal/SimpleActivityProvider.cs
@@ -2,8 +2,8 @@
// Licensed under the MIT license.
using System.Diagnostics;
-using Microsoft.Omex.Extensions.Abstractions;
-using Microsoft.Omex.Extensions.Abstractions.ReplayableLogs;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
namespace Microsoft.Omex.Extensions.TimedScopes
{
diff --git a/src/Extensions/TimedScopes/Internal/TimedScopeEventSender.cs b/src/Extensions/TimedScopes/Internal/TimedScopeEventSender.cs
index 415867eb..8f9d2489 100644
--- a/src/Extensions/TimedScopes/Internal/TimedScopeEventSender.cs
+++ b/src/Extensions/TimedScopes/Internal/TimedScopeEventSender.cs
@@ -2,11 +2,14 @@
// Licensed under the MIT license.
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Omex.Extensions.Abstractions;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
namespace Microsoft.Omex.Extensions.TimedScopes
{
@@ -20,7 +23,7 @@ public TimedScopeEventSender(TimedScopeEventSource eventSource, IHostEnvironment
}
- public void LogTimedScopeEndEvent(TimedScope scope)
+ public void LogActivityStop(Activity activity)
{
if (!m_eventSource.IsEnabled())
{
@@ -28,23 +31,37 @@ public void LogTimedScopeEndEvent(TimedScope scope)
}
string serviceName = m_serviceName;
- string subtype = scope.SubType;
- string metadata = scope.Metadata;
- TimedScopeResult result = scope.Result;
- Activity activity = scope.Activity;
string name = activity.OperationName;
string correlationId = activity.Id;
double durationMs = activity.Duration.TotalMilliseconds;
string userHash = activity.GetUserHash(); //TODO: We need add middleware that will set userhash in compliant way and IsTransaction GitHub Issue #166
bool isTransaction = activity.IsTransaction();
+ string subtype = NullPlaceholder;
+ string metadata = NullPlaceholder;
+ string resultAsString = NullPlaceholder;
+ foreach (KeyValuePair pair in activity.Tags)
+ {
+ if (string.Equals(ActivityTagKeys.Result, pair.Key, StringComparison.Ordinal))
+ {
+ resultAsString = pair.Value;
+ }
+ else if (string.Equals(ActivityTagKeys.SubType, pair.Key, StringComparison.Ordinal))
+ {
+ subtype = pair.Value;
+ }
+ else if (string.Equals(ActivityTagKeys.Metadata, pair.Key, StringComparison.Ordinal))
+ {
+ metadata = pair.Value;
+ }
+ }
+
string nameAsString = SanitizeString(name, nameof(name), name);
string subTypeAsString = SanitizeString(subtype, nameof(subtype), name);
string metaDataAsString = SanitizeString(metadata, nameof(metadata), name);
string userHashAsString = SanitizeString(userHash, nameof(userHash), name);
string serviceNameAsString = SanitizeString(serviceName, nameof(serviceName), name);
string correlationIdAsString = SanitizeString(correlationId, nameof(correlationId), name);
- string resultAsString = result.ToString();
long durationMsAsLong = Convert.ToInt64(durationMs, CultureInfo.InvariantCulture);
if (isTransaction)
@@ -93,5 +110,6 @@ private string SanitizeString(string value, string name, string activityName)
private readonly TimedScopeEventSource m_eventSource;
private readonly string m_serviceName;
private readonly ILogger m_logger;
+ private const string NullPlaceholder = "null";
}
}
diff --git a/src/Extensions/TimedScopes/Internal/TimedScopeProvider.cs b/src/Extensions/TimedScopes/Internal/TimedScopeProvider.cs
index 33845094..82fd7ae4 100644
--- a/src/Extensions/TimedScopes/Internal/TimedScopeProvider.cs
+++ b/src/Extensions/TimedScopes/Internal/TimedScopeProvider.cs
@@ -1,22 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
-using Microsoft.Omex.Extensions.Abstractions;
-using Microsoft.Omex.Extensions.Abstractions.ReplayableLogs;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
namespace Microsoft.Omex.Extensions.TimedScopes
{
internal sealed class TimedScopeProvider : ITimedScopeProvider
{
- public TimedScopeProvider(
- ITimedScopeEventSender eventSource,
- IActivityProvider activityProvider,
- ILogEventReplayer? logReplayer = null)
- {
+ public TimedScopeProvider(IActivityProvider activityProvider) =>
m_activityProvider = activityProvider;
- m_eventSender = eventSource;
- m_logReplayer = logReplayer;
- }
public TimedScope CreateAndStart(TimedScopeDefinition name, TimedScopeResult result) =>
@@ -24,11 +17,9 @@ public TimedScope CreateAndStart(TimedScopeDefinition name, TimedScopeResult res
public TimedScope Create(TimedScopeDefinition name, TimedScopeResult result) =>
- new TimedScope(m_eventSender, m_activityProvider.Create(name), result, m_logReplayer);
+ new TimedScope(m_activityProvider.Create(name), result);
- private readonly ITimedScopeEventSender m_eventSender;
private readonly IActivityProvider m_activityProvider;
- private readonly ILogEventReplayer? m_logReplayer;
}
}
diff --git a/src/Extensions/TimedScopes/ServiceCollectionExtensions.cs b/src/Extensions/TimedScopes/ServiceCollectionExtensions.cs
index 724b62ef..83172f55 100644
--- a/src/Extensions/TimedScopes/ServiceCollectionExtensions.cs
+++ b/src/Extensions/TimedScopes/ServiceCollectionExtensions.cs
@@ -4,7 +4,8 @@
using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
-using Microsoft.Omex.Extensions.Abstractions.ReplayableLogs;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
namespace Microsoft.Omex.Extensions.TimedScopes
{
@@ -19,6 +20,9 @@ public static class ServiceCollectionExtensions
public static IServiceCollection AddTimedScopes(this IServiceCollection serviceCollection)
{
Activity.DefaultIdFormat = ActivityIdFormat.W3C;
+ serviceCollection.AddHostedService();
+ serviceCollection.TryAddEnumerable(ServiceDescriptor.Transient());
+
serviceCollection.TryAddTransient();
serviceCollection.TryAddTransient();
serviceCollection.TryAddTransient();
diff --git a/src/Extensions/TimedScopes/TimedScope.cs b/src/Extensions/TimedScopes/TimedScope.cs
deleted file mode 100644
index dfd10625..00000000
--- a/src/Extensions/TimedScopes/TimedScope.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-using System.Diagnostics;
-using Microsoft.Omex.Extensions.Abstractions.ReplayableLogs;
-
-namespace Microsoft.Omex.Extensions.TimedScopes
-{
- ///
- /// Logs duration of activity
- ///
- public class TimedScope : IDisposable
- {
- ///
- /// TimedScope result
- ///
- public TimedScopeResult Result { get; set; }
-
-
- ///
- /// TimedScope sub type
- ///
- public string SubType { get; set; }
-
-
- ///
- /// TimedScope meta data
- ///
- public string Metadata { get; set; }
-
-
- ///
- /// Activity connected with this TimedScope
- ///
- public Activity Activity { get; }
-
-
- ///
- /// Indicates if activty was finished
- ///
- public bool IsFinished { get; private set; }
-
-
- ///
- /// Indicates if activty was started
- ///
- public bool IsStarted { get; private set; }
-
-
- ///
- /// Creates TimedScope instance
- ///
- /// event sender to write timedscope end information
- /// activity connected to this timedscope
- /// TimedScope initial result
- /// Log replayer that might be used to replay logs in case of error
- protected internal TimedScope(ITimedScopeEventSender eventSender, Activity activity, TimedScopeResult result, ILogEventReplayer? logReplayer = null)
- {
- m_eventSender = eventSender;
- Activity = activity;
- Result = result;
- m_logReplayer = logReplayer;
- SubType = NullPlaceholder;
- Metadata = NullPlaceholder;
- IsStarted = false;
- IsFinished = false;
- }
-
-
- ///
- /// Starts TimedScope activity
- ///
- public TimedScope Start()
- {
- if (IsStarted)
- {
- throw new InvalidOperationException("Activity already started");
- }
-
- Activity.Start();
- IsStarted = true;
- return this;
- }
-
-
- ///
- /// Stop TimedScope and log informations about it
- ///
- public void Stop()
- {
- if (IsFinished)
- {
- return;
- }
-
- IsFinished = true;
-
- Activity.Stop();
-
- m_eventSender.LogTimedScopeEndEvent(this);
-
- if (m_logReplayer != null && ShouldReplayEvents)
- {
- m_logReplayer.ReplayLogs(Activity);
- }
- }
-
-
- void IDisposable.Dispose() => Stop();
-
-
- private bool ShouldReplayEvents =>
- Result switch
- {
- TimedScopeResult.SystemError => true,
- _ => false,
- };
-
-
- private readonly ITimedScopeEventSender m_eventSender;
- private const string NullPlaceholder = "null";
- private readonly ILogEventReplayer? m_logReplayer;
- }
-}
diff --git a/tests/Extensions/TimedScopes.UnitTests/ActivityExtensionsTests.cs b/tests/Extensions/Abstractions.UnitTests/Activities/ActivityExtensionsTests.cs
similarity index 50%
rename from tests/Extensions/TimedScopes.UnitTests/ActivityExtensionsTests.cs
rename to tests/Extensions/Abstractions.UnitTests/Activities/ActivityExtensionsTests.cs
index 109df82a..67baedd3 100644
--- a/tests/Extensions/TimedScopes.UnitTests/ActivityExtensionsTests.cs
+++ b/tests/Extensions/Abstractions.UnitTests/Activities/ActivityExtensionsTests.cs
@@ -1,12 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
+using System;
using System.Diagnostics;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.Omex.Extensions.TimedScopes.UnitTests
{
[TestClass]
+ [TestCategory(nameof(Activity))]
public class ActivityExtensionsTests
{
[TestMethod]
@@ -23,7 +26,6 @@ public void SetUserHash_SetsHash()
Assert.AreNotEqual(userHash, activity2.GetUserHash());
}
-
[TestMethod]
public void MarkAsTransaction_AddsMarker()
{
@@ -35,5 +37,33 @@ public void MarkAsTransaction_AddsMarker()
Assert.IsTrue(activity1.IsTransaction());
Assert.IsFalse(activity2.IsTransaction());
}
+
+ [TestMethod]
+ [Obsolete]
+ public void SetObsoleteCorrelationId_SetsValue()
+ {
+ Activity activity1 = new Activity("CorrelationTest1");
+ Activity activity2 = new Activity("CorrelationTest2");
+ Guid correlation = Guid.NewGuid();
+
+ activity1.SetObsoleteCorrelationId(correlation);
+
+ Assert.AreEqual(correlation, activity1.GetObsoleteCorrelationId());
+ Assert.AreNotEqual(correlation, activity2.GetObsoleteCorrelationId());
+ }
+
+ [TestMethod]
+ [Obsolete]
+ public void SetObsoleteTransactionId_SetsValue()
+ {
+ Activity activity1 = new Activity("TransactionIdTest1");
+ Activity activity2 = new Activity("TransactionIdTest2");
+ uint id = 117u;
+
+ activity1.SetObsoleteTransactionId(id);
+
+ Assert.AreEqual(id, activity1.GetObsolteteTransactionId());
+ Assert.AreNotEqual(id, activity2.GetObsolteteTransactionId());
+ }
}
}
diff --git a/tests/Extensions/Abstractions.UnitTests/Activities/HelperExtensions.cs b/tests/Extensions/Abstractions.UnitTests/Activities/HelperExtensions.cs
new file mode 100644
index 00000000..ba7e0b57
--- /dev/null
+++ b/tests/Extensions/Abstractions.UnitTests/Activities/HelperExtensions.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System;
+using System.Linq;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Microsoft.Omex.Extensions.TimedScopes.UnitTests
+{
+ internal static class HelperExtensions
+ {
+ public static void AssertResult(this TimedScope scope, TimedScopeResult expectedResult) =>
+ Assert.AreEqual(ActivityResultStrings.ResultToString(expectedResult), scope.GetTag(ActivityTagKeys.Result));
+
+
+ public static void AssertTag(this TimedScope scope, string tag, string expectedValue) =>
+ Assert.AreEqual(expectedValue, scope.GetTag(tag));
+
+
+ public static string GetTag(this TimedScope scope, string tag) =>
+ scope.Activity.Tags.FirstOrDefault(p => string.Equals(p.Key, tag, StringComparison.Ordinal)).Value;
+ }
+}
diff --git a/tests/Extensions/TimedScopes.UnitTests/TaskExtensionsTests.cs b/tests/Extensions/Abstractions.UnitTests/Activities/TaskExtensionsTests.cs
similarity index 90%
rename from tests/Extensions/TimedScopes.UnitTests/TaskExtensionsTests.cs
rename to tests/Extensions/Abstractions.UnitTests/Activities/TaskExtensionsTests.cs
index 46094482..9aad0f2f 100644
--- a/tests/Extensions/TimedScopes.UnitTests/TaskExtensionsTests.cs
+++ b/tests/Extensions/Abstractions.UnitTests/Activities/TaskExtensionsTests.cs
@@ -5,13 +5,14 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
-using Microsoft.Omex.Extensions.Abstractions;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace Microsoft.Omex.Extensions.TimedScopes.UnitTests
{
[TestClass]
+ [TestCategory(nameof(Activity))]
public class TaskExtensionsTests
{
[TestMethod]
@@ -61,11 +62,10 @@ private void TestExecution(
TimedScopeResult expectedResult)
{
Mock providerMock = new Mock();
- Mock mockSender = new Mock();
TimedScopeDefinition timedScopeDefinition = new TimedScopeDefinition(scopeName);
Activity activity = new Activity(scopeName);
- TimedScope scope = new TimedScope(mockSender.Object, activity, TimedScopeResult.SystemError, null);
+ TimedScope scope = new TimedScope(activity, TimedScopeResult.SystemError);
providerMock.Setup(p => p.CreateAndStart(timedScopeDefinition, TimedScopeResult.SystemError)).Returns(scope);
TaskCompletionSource taskCompletionSource = new TaskCompletionSource();
@@ -73,12 +73,11 @@ private void TestExecution(
createTask(taskCompletionSource.Task, providerMock.Object, timedScopeDefinition);
providerMock.Verify(p => p.CreateAndStart(timedScopeDefinition, TimedScopeResult.SystemError), Times.Once);
- Assert.AreEqual(scope.Result, TimedScopeResult.SystemError);
+ scope.AssertResult(TimedScopeResult.SystemError);
finishTask(taskCompletionSource);
- Assert.IsTrue(scope.IsFinished);
- Assert.AreEqual(scope.Result, expectedResult);
+ scope.AssertResult(expectedResult);
}
diff --git a/tests/Extensions/TimedScopes.UnitTests/TimedScopeDefinitionsTests.cs b/tests/Extensions/Abstractions.UnitTests/Activities/TimedScopeDefinitionsTests.cs
similarity index 96%
rename from tests/Extensions/TimedScopes.UnitTests/TimedScopeDefinitionsTests.cs
rename to tests/Extensions/Abstractions.UnitTests/Activities/TimedScopeDefinitionsTests.cs
index c2af3f39..aa93b088 100644
--- a/tests/Extensions/TimedScopes.UnitTests/TimedScopeDefinitionsTests.cs
+++ b/tests/Extensions/Abstractions.UnitTests/Activities/TimedScopeDefinitionsTests.cs
@@ -2,12 +2,14 @@
// Licensed under the MIT license.
using System;
-using Microsoft.Omex.Extensions.Abstractions;
+using System.Diagnostics;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.Omex.Extensions.TimedScopes.UnitTests
{
[TestClass]
+ [TestCategory(nameof(Activity))]
public class TimedScopeDefinitionsTests
{
[DataTestMethod]
diff --git a/tests/Extensions/Abstractions.UnitTests/Activities/TimedScopeExtensionsTests.cs b/tests/Extensions/Abstractions.UnitTests/Activities/TimedScopeExtensionsTests.cs
new file mode 100644
index 00000000..b16b21bb
--- /dev/null
+++ b/tests/Extensions/Abstractions.UnitTests/Activities/TimedScopeExtensionsTests.cs
@@ -0,0 +1,62 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.Diagnostics;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Microsoft.Omex.Extensions.TimedScopes.UnitTests
+{
+ [TestClass]
+ [TestCategory(nameof(Activity))]
+ public class TimedScopeExtensionsTests
+ {
+ [DataTestMethod]
+ [DataRow(TimedScopeResult.SystemError)]
+ [DataRow(TimedScopeResult.ExpectedError)]
+ [DataRow(TimedScopeResult.Success)]
+ public void SetResult_SetsValue(TimedScopeResult result)
+ {
+ TimedScope scope1 = CreateScope("SetResultTest1");
+ TimedScope scope2 = CreateScope("SetResultTest2");
+
+ scope1.SetResult(result);
+
+ scope1.AssertResult(result);
+ scope2.AssertResult(TimedScopeResult.SystemError);
+ }
+
+
+ [TestMethod]
+ public void SetSubType_SetsValue()
+ {
+ TimedScope scope1 = CreateScope("SetSubTypeTest1");
+ TimedScope scope2 = CreateScope("SetSubTypeTest2");
+ string value = "Some sub type";
+
+ scope1.SetSubType(value);
+
+ Assert.AreEqual(value, scope1.GetTag(ActivityTagKeys.SubType));
+ Assert.IsNull(scope2.GetTag(ActivityTagKeys.SubType));
+ }
+
+
+ [TestMethod]
+ public void SetMetadata_SetsValue()
+ {
+ TimedScope scope1 = CreateScope("SetMetadataTest1");
+ TimedScope scope2 = CreateScope("SetMetadataTest2");
+ string value = "Some metadata";
+
+ scope1.SetMetadata(value);
+
+ Assert.AreEqual(value, scope1.GetTag(ActivityTagKeys.Metadata));
+ Assert.IsNull(scope2.GetTag(ActivityTagKeys.Metadata));
+ }
+
+
+ private TimedScope CreateScope(string name) =>
+ new TimedScope(new Activity(name), TimedScopeResult.SystemError);
+ }
+}
diff --git a/tests/Extensions/Abstractions.UnitTests/Activities/TimedScopeTests.cs b/tests/Extensions/Abstractions.UnitTests/Activities/TimedScopeTests.cs
new file mode 100644
index 00000000..11c87c0b
--- /dev/null
+++ b/tests/Extensions/Abstractions.UnitTests/Activities/TimedScopeTests.cs
@@ -0,0 +1,71 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System;
+using System.Diagnostics;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+
+namespace Microsoft.Omex.Extensions.TimedScopes.UnitTests
+{
+ [TestClass]
+ [TestCategory(nameof(Activity))]
+ public class TimedScopeTests
+ {
+ [TestMethod]
+ public void Constructor_WorksProperly()
+ {
+ CreateTimedScope();
+ }
+
+
+ [TestMethod]
+ public void Start_StartsActivity()
+ {
+ TimedScope scope = CreateTimedScope();
+
+ Assert.IsNull(scope.Activity.Id);
+
+ scope.Start();
+
+ Assert.IsNotNull(scope.Activity.Id);
+ }
+
+
+ [TestMethod]
+ public void Stop_WhenCalledMultipleTimes_IgnoresSuperfluousCalls()
+ {
+ TimedScope scope = CreateTimedScope();
+ scope.Start();
+ scope.Stop();
+ scope.Stop();
+ }
+
+
+ [TestMethod]
+ public void Dispose_WhenCalledMultipleTimes_IgnoresSuperfluousCalls()
+ {
+ TimedScope scope = CreateTimedScope();
+ scope.Start();
+
+ IDisposable disposable = scope;
+ disposable.Dispose();
+ disposable.Dispose();
+ }
+
+
+ private TimedScope CreateTimedScope()
+ {
+ Activity activity = new Activity("TestName");
+ TimedScopeResult result = TimedScopeResult.Success;
+
+ TimedScope scope = new TimedScope(activity, result);
+
+ Assert.ReferenceEquals(activity, scope.Activity);
+ scope.AssertResult(result);
+
+ return scope;
+ }
+ }
+}
diff --git a/tests/Extensions/Compatibility.UnitTests/ServiceCollectionExtensionsTests.cs b/tests/Extensions/Compatibility.UnitTests/ServiceCollectionExtensionsTests.cs
index d893fadf..2950e02c 100644
--- a/tests/Extensions/Compatibility.UnitTests/ServiceCollectionExtensionsTests.cs
+++ b/tests/Extensions/Compatibility.UnitTests/ServiceCollectionExtensionsTests.cs
@@ -2,10 +2,13 @@
// Licensed under the MIT license.
using System;
+using System.Diagnostics;
+using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
-using Microsoft.Omex.Extensions.Abstractions;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
using Microsoft.Omex.Extensions.Compatibility.Logger;
using Microsoft.Omex.Extensions.Compatibility.TimedScopes;
using Microsoft.Omex.Extensions.Compatibility.Validation;
@@ -54,13 +57,23 @@ public void AddOmexCompatibilityServices_RegisterTypes()
Code.Validate(false, logMessage, eventId);
Assert.AreEqual(1, mockLogger.Invocations.Count, "Code.Validate not calling ILogger");
- TimedScope startedTimedScope = new TimedScopeDefinition("TestStartedTimedScope").Create(TimedScopeResult.SystemError);
- Assert.IsTrue(startedTimedScope.IsStarted);
- Assert.AreEqual(TimedScopeResult.SystemError, startedTimedScope.Result);
+ using (TimedScope startedTimedScope = new TimedScopeDefinition("TestStartedTimedScope").Create(TimedScopeResult.SystemError))
+ {
+ AssertResult(ActivityResultStrings.SystemError);
+ }
- TimedScope notStartedTimedScope = new TimedScopeDefinition("TestNotStartedTimedScope").Create(TimedScopeResult.ExpectedError, false);
- Assert.IsFalse(notStartedTimedScope.IsStarted);
- Assert.AreEqual(TimedScopeResult.ExpectedError, notStartedTimedScope.Result);
+ using (TimedScope notStartedTimedScope = new TimedScopeDefinition("TestNotStartedTimedScope").Create(TimedScopeResult.ExpectedError, false))
+ {
+ notStartedTimedScope.Start();
+ AssertResult(ActivityResultStrings.ExpectedError);
+ }
+ }
+
+
+ private static void AssertResult(string expectedResult)
+ {
+ string value = Activity.Current.Tags.FirstOrDefault(p => string.Equals(p.Key, ActivityTagKeys.Result, StringComparison.Ordinal)).Value;
+ Assert.AreEqual(expectedResult, value);
}
}
}
diff --git a/tests/Extensions/Hosting.Services.UnitTests/HostBuilderExtensionsTests.cs b/tests/Extensions/Hosting.Services.UnitTests/HostBuilderExtensionsTests.cs
index 10ddd897..24de04fd 100644
--- a/tests/Extensions/Hosting.Services.UnitTests/HostBuilderExtensionsTests.cs
+++ b/tests/Extensions/Hosting.Services.UnitTests/HostBuilderExtensionsTests.cs
@@ -11,10 +11,10 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.Omex.Extensions.Abstractions.EventSources;
using Microsoft.Omex.Extensions.Hosting.Services;
using Microsoft.Omex.Extensions.Logging;
-using Microsoft.Omex.Extensions.TimedScopes;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
diff --git a/tests/Extensions/Hosting.Services.UnitTests/OmexHostedServiceTests.cs b/tests/Extensions/Hosting.Services.UnitTests/OmexHostedServiceTests.cs
index 587c1185..d602d271 100644
--- a/tests/Extensions/Hosting.Services.UnitTests/OmexHostedServiceTests.cs
+++ b/tests/Extensions/Hosting.Services.UnitTests/OmexHostedServiceTests.cs
@@ -4,7 +4,6 @@
using System;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Omex.Extensions.Hosting.Services;
@@ -19,23 +18,19 @@ public class OmexHostedServiceTests
public async Task StartAsync_ProperlyCanceled()
{
MockRunner runnerMock = new MockRunner(t => Task.Delay(int.MaxValue, t));
- MockLifetime lifetimeMock = new MockLifetime();
ILogger loggerMock = new NullLogger();
- OmexHostedService hostedService = new OmexHostedService(runnerMock, lifetimeMock, loggerMock);
+ OmexHostedService hostedService = new OmexHostedService(runnerMock, loggerMock);
Assert.IsFalse(runnerMock.IsStarted, "RunServiceAsync should not be called after constructor");
- await hostedService.StartAsync(CancellationToken.None);
- Assert.IsFalse(runnerMock.IsStarted, "RunServiceAsync should not be called after StartAsync");
-
- lifetimeMock.ApplicationStartedSource.Cancel();
- Assert.IsTrue(runnerMock.IsStarted, "RunServiceAsync should not be called after StartAsync");
+ await hostedService.StartAsync(CancellationToken.None).ConfigureAwait(false);
+ Assert.IsTrue(runnerMock.IsStarted, "RunServiceAsync should be called after StartAsync");
Task task = runnerMock.Task!;
Assert.IsFalse(task.IsCanceled, "Task should not be canceled");
Assert.IsFalse(runnerMock.Token.IsCancellationRequested, "CancelationToken should not be canceled");
- lifetimeMock.ApplicationStoppingSource.Cancel();
+ await hostedService.StopAsync(CancellationToken.None).ConfigureAwait(false);
Assert.IsTrue(runnerMock.Token.IsCancellationRequested, "Task should be canceled");
Assert.IsTrue(task.IsCanceled, "CancelationToken should be canceled");
}
@@ -44,24 +39,22 @@ public async Task StartAsync_ProperlyCanceled()
[TestMethod]
public async Task StartAsync_HandlesExceptions()
{
- MockRunner runnerMock = new MockRunner(t => Task.Run(() => throw new Exception("Totaly valid exeption")));
- MockLifetime lifetimeMock = new MockLifetime();
+ MockRunner runnerMock = new MockRunner(t => Task.Run(async () =>
+ {
+ await Task.Delay(5).ConfigureAwait(false);
+ throw new ArithmeticException("Totaly valid exeption");
+ }));
ILogger loggerMock = new NullLogger();
- OmexHostedService hostedService = new OmexHostedService(runnerMock, lifetimeMock, loggerMock);
+ OmexHostedService hostedService = new OmexHostedService(runnerMock, loggerMock);
Assert.IsFalse(runnerMock.IsStarted, "RunServiceAsync should not be called after constructor");
- await hostedService.StartAsync(CancellationToken.None);
- Assert.IsFalse(runnerMock.IsStarted, "RunServiceAsync should not be called after StartAsync");
-
- lifetimeMock.ApplicationStartedSource.Cancel();
+ await hostedService.StartAsync(CancellationToken.None).ConfigureAwait(false);
Assert.IsTrue(runnerMock.IsStarted, "RunServiceAsync should be called after StartAsync");
Assert.IsFalse(runnerMock.Token.IsCancellationRequested, "CancelationToken should not be canceled");
- await lifetimeMock.CompletionTask;
+ await hostedService.StopAsync(CancellationToken.None).ConfigureAwait(false);
Assert.IsTrue(runnerMock.Task!.IsFaulted, "Task should be faulted");
-
- lifetimeMock.ApplicationStoppingSource.Cancel();
Assert.IsTrue(runnerMock.Token.IsCancellationRequested, "Task should be canceled");
}
@@ -90,44 +83,5 @@ public Task RunServiceAsync(CancellationToken cancellationToken)
private readonly Func m_function;
}
-
-
- private class MockLifetime : IHostApplicationLifetime
- {
- public MockLifetime()
- {
- ApplicationStartedSource = new CancellationTokenSource();
- ApplicationStoppingSource = new CancellationTokenSource();
- ApplicationStoppedSource = new CancellationTokenSource();
- m_completionSource = new TaskCompletionSource();
- }
-
-
- public CancellationTokenSource ApplicationStartedSource { get; }
-
-
- public CancellationTokenSource ApplicationStoppingSource { get; }
-
-
- public CancellationTokenSource ApplicationStoppedSource { get; }
-
-
- public Task CompletionTask => m_completionSource.Task;
-
-
- public CancellationToken ApplicationStarted => ApplicationStartedSource.Token;
-
-
- public CancellationToken ApplicationStopping => ApplicationStoppingSource.Token;
-
-
- public CancellationToken ApplicationStopped => ApplicationStoppedSource.Token;
-
-
- public void StopApplication() => m_completionSource.SetResult(true);
-
-
- private readonly TaskCompletionSource m_completionSource;
- }
}
}
diff --git a/tests/Extensions/Hosting.Services.Web.UnitTests/ListenerValidator.cs b/tests/Extensions/Hosting.Services.Web.UnitTests/ListenerValidator.cs
index 04f421b0..fdd3f593 100644
--- a/tests/Extensions/Hosting.Services.Web.UnitTests/ListenerValidator.cs
+++ b/tests/Extensions/Hosting.Services.Web.UnitTests/ListenerValidator.cs
@@ -7,6 +7,7 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.Omex.Extensions.Hosting.Services;
using Microsoft.Omex.Extensions.Hosting.Services.Web;
using Microsoft.Omex.Extensions.Logging;
diff --git a/tests/Extensions/Hosting.UnitTests/HostBuilderExtensionsTests.cs b/tests/Extensions/Hosting.UnitTests/HostBuilderExtensionsTests.cs
index 231ecf94..20e0a3da 100644
--- a/tests/Extensions/Hosting.UnitTests/HostBuilderExtensionsTests.cs
+++ b/tests/Extensions/Hosting.UnitTests/HostBuilderExtensionsTests.cs
@@ -6,7 +6,7 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Hosting.Internal;
using Microsoft.Extensions.Logging;
-using Microsoft.Omex.Extensions.TimedScopes;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.Omex.Extensions.Hosting.UnitTests
diff --git a/tests/Extensions/Logging.UnitTests/ActivityEnhancementObserverTests.cs b/tests/Extensions/Logging.UnitTests/ActivityEnhancementObserverTests.cs
new file mode 100644
index 00000000..4cfbc393
--- /dev/null
+++ b/tests/Extensions/Logging.UnitTests/ActivityEnhancementObserverTests.cs
@@ -0,0 +1,44 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System;
+using System.Diagnostics;
+using Microsoft.Extensions.Options;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Logging;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Hosting.Services.UnitTests
+{
+ [TestClass]
+ public class ActivityEnhancementObserverTests
+ {
+ [TestMethod]
+ [Obsolete]
+ public void OnStart_WhenSettingEnabled_ObsolterCorrelationIdSet()
+ {
+ Guid? correlation = StartAndGetCorrelation(true);
+ Assert.IsNotNull(correlation);
+ Assert.AreNotEqual(Guid.Empty, correlation);
+ }
+
+ [TestMethod]
+ [Obsolete]
+ public void OnStart_WhenSettingDisabled_ObsolterCorrelationIdNotSet()
+ {
+ Guid? correlation = StartAndGetCorrelation(false);
+ Assert.IsNull(correlation);
+ }
+
+ [Obsolete]
+ private Guid? StartAndGetCorrelation(bool addCorrelation)
+ {
+ IOptions options = Options.Create(new OmexLoggingOptions { AddObsoleteCorrelationToActivity = addCorrelation });
+ ActivityEnhancementObserver observer = new ActivityEnhancementObserver(options);
+ string name = FormattableString.Invariant($"{nameof(StartAndGetCorrelation)}|{nameof(addCorrelation)}:{addCorrelation}");
+ Activity activity = new Activity(name);
+ observer.OnStart(activity, null);
+ return activity.GetObsoleteCorrelationId();
+ }
+ }
+}
diff --git a/tests/Extensions/Logging.UnitTests/OmexLogEventSenderTests.cs b/tests/Extensions/Logging.UnitTests/OmexLogEventSenderTests.cs
index ffba04a5..13581bad 100644
--- a/tests/Extensions/Logging.UnitTests/OmexLogEventSenderTests.cs
+++ b/tests/Extensions/Logging.UnitTests/OmexLogEventSenderTests.cs
@@ -7,6 +7,7 @@
using System.Diagnostics.Tracing;
using System.Linq;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
using Microsoft.Omex.Extensions.Abstractions.EventSources;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -36,7 +37,8 @@ public void LogMessage_CreatesProperEvents(EventLevel eventLevel, LogLevel logLe
OmexLogEventSender logsSender = new OmexLogEventSender(
OmexLogEventSource.Instance,
new BasicMachineInformation(),
- new EmptyServiceContext());
+ new EmptyServiceContext(),
+ Options.Create(new OmexLoggingOptions()));
logsSender.LogMessage(activity, category, logLevel, tagId, 0, message);
@@ -44,7 +46,7 @@ public void LogMessage_CreatesProperEvents(EventLevel eventLevel, LogLevel logLe
AssertPayload(eventInfo, "message", message);
AssertPayload(eventInfo, "category", category);
- AssertPayload(eventInfo, "correlationId", activity.Id);
+ AssertPayload(eventInfo, "activityId", activity.Id);
AssertPayload(eventInfo, "tagId", "fff9");
}
diff --git a/tests/Extensions/Logging.UnitTests/ReplayableActivityProviderTests.cs b/tests/Extensions/Logging.UnitTests/ReplayableActivityProviderTests.cs
index af3e1261..411e19f3 100644
--- a/tests/Extensions/Logging.UnitTests/ReplayableActivityProviderTests.cs
+++ b/tests/Extensions/Logging.UnitTests/ReplayableActivityProviderTests.cs
@@ -3,7 +3,7 @@
using System.Diagnostics;
using Microsoft.Extensions.Options;
-using Microsoft.Omex.Extensions.Abstractions;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.Omex.Extensions.Logging.Replayable;
using Microsoft.VisualStudio.TestTools.UnitTesting;
diff --git a/tests/Extensions/Logging.UnitTests/ReplayableActivityStopObserverTests.cs b/tests/Extensions/Logging.UnitTests/ReplayableActivityStopObserverTests.cs
new file mode 100644
index 00000000..3a1ca4a2
--- /dev/null
+++ b/tests/Extensions/Logging.UnitTests/ReplayableActivityStopObserverTests.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.Diagnostics;
+using Microsoft.Extensions.Options;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Logging;
+using Microsoft.Omex.Extensions.Logging.Replayable;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Hosting.Services.UnitTests
+{
+ [TestClass]
+ public class ReplayableActivityStopObserverTests
+ {
+ [DataTestMethod]
+ [DataRow(TimedScopeResult.SystemError, true, true)]
+ [DataRow(TimedScopeResult.SystemError, false, false)]
+ [DataRow(TimedScopeResult.ExpectedError, true, false)]
+ public void OnStop_UsingReplaySettingsAndResult_CallesLogReplayIfNeeded(TimedScopeResult result, bool replayLog, bool shouldBeCalled)
+ {
+ Activity activity = new Activity(nameof(OnStop_UsingReplaySettingsAndResult_CallesLogReplayIfNeeded));
+ TimedScope timedScope = new TimedScope(activity, result);
+ IOptions options = Options.Create(new OmexLoggingOptions { ReplayLogsInCaseOfError = replayLog });
+ LogEventReplayerMock replayerMock = new LogEventReplayerMock();
+ ReplayableActivityStopObserver observer = new ReplayableActivityStopObserver(replayerMock, options);
+ observer.OnStop(activity, null);
+
+ if (shouldBeCalled)
+ {
+ Assert.AreEqual(activity, replayerMock.Activity);
+ }
+ else
+ {
+ Assert.IsNull(replayerMock.Activity);
+ }
+ }
+
+ private class LogEventReplayerMock : ILogEventReplayer
+ {
+ public Activity? Activity { get; private set; }
+
+ public void ReplayLogs(Activity activity) => Activity = activity;
+ }
+ }
+}
diff --git a/tests/Extensions/TimedScopes.UnitTests/ActivityObserversIntializerTests.cs b/tests/Extensions/TimedScopes.UnitTests/ActivityObserversIntializerTests.cs
new file mode 100644
index 00000000..c2f7b7f1
--- /dev/null
+++ b/tests/Extensions/TimedScopes.UnitTests/ActivityObserversIntializerTests.cs
@@ -0,0 +1,57 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
+using Microsoft.Omex.Extensions.TimedScopes;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+
+namespace Hosting.Services.UnitTests
+{
+ [TestClass]
+ public class ActivityObserversIntializerTests
+ {
+ [TestMethod]
+ public async Task ActivityObserversInvokedProperly()
+ {
+ string name = nameof(ActivityObserversInvokedProperly);
+ Mock startObserver = new Mock();
+ Mock stopObserver = new Mock();
+ ActivityObserversIntializer initializer = new ActivityObserversIntializer(
+ new [] { startObserver.Object },
+ new [] { stopObserver.Object });
+
+ try
+ {
+ await initializer.StartAsync(CancellationToken.None).ConfigureAwait(false);
+
+ using DiagnosticListener listener = new DiagnosticListener(name);
+
+ Assert.IsTrue(listener.IsEnabled(MakeStartName(name)), "Should be enabled for Activity.Start");
+ Assert.IsFalse(listener.IsEnabled(name, "Should be disabled for other events"));
+ Assert.IsTrue(listener.IsEnabled(MakeStopName(name)), "Should be enabled for Activity.Stop");
+
+ Activity activity = new Activity(name);
+ object obj = new object();
+
+ listener.StartActivity(activity, obj);
+ startObserver.Verify(obs => obs.OnStart(activity, obj), Times.Once);
+
+ listener.StopActivity(activity, obj);
+ stopObserver.Verify(obs => obs.OnStop(activity, obj), Times.Once);
+ }
+ catch
+ {
+ await initializer.StopAsync(CancellationToken.None).ConfigureAwait(false);
+ throw;
+ }
+ }
+
+ private string MakeStartName(string name) => name + ".Start";
+
+ private string MakeStopName(string name) => name + ".Stop";
+ }
+}
diff --git a/tests/Extensions/TimedScopes.UnitTests/ActivityStopObserverTests.cs b/tests/Extensions/TimedScopes.UnitTests/ActivityStopObserverTests.cs
new file mode 100644
index 00000000..93706214
--- /dev/null
+++ b/tests/Extensions/TimedScopes.UnitTests/ActivityStopObserverTests.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.Diagnostics;
+using Microsoft.Omex.Extensions.TimedScopes;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+
+namespace Hosting.Services.UnitTests
+{
+ [TestClass]
+ public class ActivityStopObserverTests
+ {
+ [TestMethod]
+ public void OnStop_CallsLogActivityStop()
+ {
+ Activity activity = new Activity(nameof(OnStop_CallsLogActivityStop));
+ Mock senderMock = new Mock();
+ ActivityStopObserver observer = new ActivityStopObserver(senderMock.Object);
+ observer.OnStop(activity, null);
+ senderMock.Verify(s => s.LogActivityStop(activity), Times.Once);
+ }
+ }
+}
diff --git a/tests/Extensions/TimedScopes.UnitTests/ServiceCollectionTests.cs b/tests/Extensions/TimedScopes.UnitTests/ServiceCollectionTests.cs
index 7c5e97ff..72e5e51e 100644
--- a/tests/Extensions/TimedScopes.UnitTests/ServiceCollectionTests.cs
+++ b/tests/Extensions/TimedScopes.UnitTests/ServiceCollectionTests.cs
@@ -3,6 +3,7 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.Omex.Extensions.TimedScopes.UnitTests
diff --git a/tests/Extensions/TimedScopes.UnitTests/SimpleActivityProviderTests.cs b/tests/Extensions/TimedScopes.UnitTests/SimpleActivityProviderTests.cs
index d058f0e5..aead7f27 100644
--- a/tests/Extensions/TimedScopes.UnitTests/SimpleActivityProviderTests.cs
+++ b/tests/Extensions/TimedScopes.UnitTests/SimpleActivityProviderTests.cs
@@ -2,7 +2,7 @@
// Licensed under the MIT license.
using System.Diagnostics;
-using Microsoft.Omex.Extensions.Abstractions;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.Omex.Extensions.TimedScopes.UnitTests
diff --git a/tests/Extensions/TimedScopes.UnitTests/TimedScopeEventSourceTests.cs b/tests/Extensions/TimedScopes.UnitTests/TimedScopeEventSourceTests.cs
index 439d96c2..aaba61c4 100644
--- a/tests/Extensions/TimedScopes.UnitTests/TimedScopeEventSourceTests.cs
+++ b/tests/Extensions/TimedScopes.UnitTests/TimedScopeEventSourceTests.cs
@@ -7,6 +7,7 @@
using System.Linq;
using Microsoft.Extensions.Hosting.Internal;
using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
using Microsoft.Omex.Extensions.Abstractions.EventSources;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -27,11 +28,16 @@ public void LogTimedScopeEndEvent_CreatesEvent(EventSourcesEventIds eventId, boo
string subType = "TestSubType";
string metaData = "TestmetaData";
+ TimedScopeEventSender logEventSource = new TimedScopeEventSender(
+ TimedScopeEventSource.Instance,
+ new HostingEnvironment { ApplicationName = "TestApp" },
+ new NullLogger());
+
Activity activity = new Activity(name);
- using (TimedScope scope = new TimedScope(s_logEventSource, activity, TimedScopeResult.Success, null).Start())
+ using (TimedScope scope = new TimedScope(activity, TimedScopeResult.Success).Start())
{
- scope.SubType = subType;
- scope.Metadata = metaData;
+ scope.SetSubType(subType);
+ scope.SetMetadata(metaData);
activity.SetUserHash("TestUserHash");
if (isTransaction)
{
@@ -39,6 +45,8 @@ public void LogTimedScopeEndEvent_CreatesEvent(EventSourcesEventIds eventId, boo
}
}
+ logEventSource.LogActivityStop(activity);
+
EventWrittenEventArgs eventInfo = listener.EventsInformation.Single(e => e.EventId == (int)eventId);
AssertPayload(eventInfo, "name", name);
@@ -47,13 +55,6 @@ public void LogTimedScopeEndEvent_CreatesEvent(EventSourcesEventIds eventId, boo
}
- private static readonly TimedScopeEventSender s_logEventSource =
- new TimedScopeEventSender(
- TimedScopeEventSource.Instance,
- new HostingEnvironment { ApplicationName = "TestApp" },
- new NullLogger());
-
-
private class CustomEventListener : EventListener
{
public List EventsInformation { get; } = new List();
diff --git a/tests/Extensions/TimedScopes.UnitTests/TimedScopeProviderTests.cs b/tests/Extensions/TimedScopes.UnitTests/TimedScopeProviderTests.cs
index 62e359a1..f2c909e6 100644
--- a/tests/Extensions/TimedScopes.UnitTests/TimedScopeProviderTests.cs
+++ b/tests/Extensions/TimedScopes.UnitTests/TimedScopeProviderTests.cs
@@ -3,8 +3,8 @@
using System;
using System.Diagnostics;
-using Microsoft.Omex.Extensions.Abstractions;
-using Microsoft.Omex.Extensions.Abstractions.ReplayableLogs;
+using Microsoft.Omex.Extensions.Abstractions.Activities;
+using Microsoft.Omex.Extensions.Abstractions.Activities.Processing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
@@ -14,39 +14,27 @@ namespace Microsoft.Omex.Extensions.TimedScopes.UnitTests
public class TimedScopeProviderTests
{
[TestMethod]
- public void CreateAndStart_ActivityCreatedWithReplay()
+ public void CreateAndStart_ActivityCreated()
{
- CreateAndValidateActivity("testNameWithReplay", new Mock().Object);
+ CreateAndValidateActivity("testName");
}
- [TestMethod]
- public void CreateAndStart_ActivityCreatedWithoutReplay()
- {
- CreateAndValidateActivity("testNameWithoutReplay", null);
- }
-
-
- private void CreateAndValidateActivity(string activityName, ILogEventReplayer? replayer)
+ private void CreateAndValidateActivity(string activityName)
{
TimedScopeResult result = TimedScopeResult.ExpectedError;
- Mock eventSourceMock = new Mock();
Mock activityProviderMock = new Mock();
Mock activityMock = new Mock(activityName);
TimedScopeDefinition definition = new TimedScopeDefinition(activityName);
activityProviderMock.Setup(p => p.Create(definition)).Returns(activityMock.Object);
- TimedScopeProvider provider = new TimedScopeProvider(
- eventSourceMock.Object,
- activityProviderMock.Object,
- replayer);
+ TimedScopeProvider provider = new TimedScopeProvider(activityProviderMock.Object);
TimedScope scope = provider.CreateAndStart(definition, result);
- Assert.AreEqual(result, scope.Result);
- Assert.ReferenceEquals(activityMock.Object, scope.Activity);
+ Assert.IsNotNull(scope);
}
}
}
diff --git a/tests/Extensions/TimedScopes.UnitTests/TimedScopeTests.cs b/tests/Extensions/TimedScopes.UnitTests/TimedScopeTests.cs
deleted file mode 100644
index a32c77ac..00000000
--- a/tests/Extensions/TimedScopes.UnitTests/TimedScopeTests.cs
+++ /dev/null
@@ -1,156 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using Microsoft.Omex.Extensions.Abstractions.ReplayableLogs;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-
-namespace Microsoft.Omex.Extensions.TimedScopes.UnitTests
-{
- [TestClass]
- public class TimedScopeTests
- {
- [TestMethod]
- public void ConstructorWithoutReplayer_WorksProperly()
- {
- CreateTimedScope(null);
- }
-
-
- [TestMethod]
- public void ConstructorWithReplayer_WorksProperly()
- {
- CreateTimedScope(new Mock().Object);
- }
-
-
- [TestMethod]
- public void Start_StartsActivity()
- {
- (TimedScope scope, _) = CreateTimedScope(null);
-
- Assert.IsNull(scope.Activity.Id);
-
- scope.Start();
-
- Assert.IsNotNull(scope.Activity.Id);
- }
-
-
- [TestMethod]
- public void Stop_MultipleCallsIgnored()
- {
- (TimedScope scope, _) = CreateTimedScope(null);
- scope.Start();
- scope.Stop();
-
- Assert.IsTrue(scope.IsFinished);
-
- scope.Stop();
- }
-
-
- [TestMethod]
- public void Dispose_MultipleCallsIgnored()
- {
- (TimedScope scope, _) = CreateTimedScope(null);
- scope.Start();
-
- IDisposable disposable = scope;
- disposable.Dispose();
-
- Assert.IsTrue(scope.IsFinished);
-
- disposable.Dispose();
- }
-
-
- [TestMethod]
- public void Stop_CallsEventSource()
- {
- (TimedScope scope, Mock source) = CreateTimedScope(null);
-
- scope.Start();
-
- scope.Stop();
- source.Verify(s => s.LogTimedScopeEndEvent(scope), Times.Once);
- source.Invocations.Clear();
-
- scope.Stop();
- source.Verify(s => s.LogTimedScopeEndEvent(It.IsAny()), Times.Never);
- }
-
-
- [DataTestMethod]
- [DynamicData(nameof(AllResults), DynamicDataSourceType.Method)]
- public void Stop_NotCallsLogReplayerIfItNotExist(TimedScopeResult result)
- {
- Mock replayer = new Mock();
- (TimedScope scope, Mock source) = CreateTimedScope(null);
- scope.Result = result;
-
- scope.Start();
-
- scope.Stop();
- }
-
-
- public static IEnumerable