/// <summary> /// Starts the correlation context. /// </summary> /// <param name="correlationId">The correlation id to create the context for.</param> /// <returns>The created correlation context (also accessible via <see cref="ICorrelationContextAccessor"/>), or null if diagnostics and logging is disabled.</returns> public CorrelationContext Start(string correlationId) { if (correlationId == null) { throw new ArgumentNullException(nameof(correlationId)); } bool isDiagnosticsEnabled = _diagnosticListener?.IsEnabled() ?? false; bool isLoggingEnabled = _logger.IsEnabled(LogLevel.Critical); if (isDiagnosticsEnabled || isLoggingEnabled) { CorrelationContext context = _correlationContextFactory.Create(correlationId); if (isDiagnosticsEnabled) { // TODO: add Activity support //var activity = new Activity("Correlated-Request"); //activity.SetParentId(correlationId); //_diagnosticListener.StartActivity(activity, new {}) } if (isLoggingEnabled) { _logScope = _logger.BeginCorrelatedScope(correlationId); } _activity?.Start(context); return(context); } return(null); }
public void When_starting_correlationContext_when_another_context_is_active_should_start_new() { const string parentContextId = nameof(parentContextId); const string innerContextId = nameof(innerContextId); _sut.Correlate(parentContextId, () => { CorrelationContext parentContext = _correlationContextAccessor.CorrelationContext; parentContext.Should().NotBeNull(); parentContext.CorrelationId.Should().Be(parentContextId); _sut.Correlate(innerContextId, () => { CorrelationContext innerContext = _correlationContextAccessor.CorrelationContext; innerContext.Should().NotBeNull(); innerContext.Should().NotBe(parentContext); innerContext.CorrelationId.Should().Be(innerContextId); }); _correlationContextAccessor.CorrelationContext.Should().NotBeNull(); _correlationContextAccessor.CorrelationContext .CorrelationId .Should() .Be(parentContextId); }); }
private static bool HandlesException <T>(OnException onException, CorrelationContext correlationContext, Exception ex, out T result) { if (correlationContext != null && !ex.Data.Contains(CorrelateConstants.CorrelationIdKey)) { // Because we're about to lose context scope, enrich exception with correlation id for reference by calling code. ex.Data.Add(CorrelateConstants.CorrelationIdKey, correlationContext.CorrelationId); } if (onException != null) { bool hasResultValue = typeof(T) != typeof(Void); // Allow caller to handle exception inline before losing context scope. ExceptionContext exceptionContext = hasResultValue ? new ExceptionContext <T>() : new ExceptionContext(); exceptionContext.Exception = ex; exceptionContext.CorrelationContext = correlationContext; onException(exceptionContext); if (exceptionContext.IsExceptionHandled) { result = hasResultValue ? ((ExceptionContext <T>)exceptionContext).Result : default(T); return(true); } } result = default(T); return(false); }
public Task When_starting_correlationContext_with_legacy_ctor_when_another_context_is_active_should_not_throw() { const string parentContextId = nameof(parentContextId); #pragma warning disable 618 // justification, covering legacy implementation (pre v3.0) var sut = new CorrelationManager( new CorrelationContextFactory(_correlationContextAccessor), _correlationIdFactoryMock.Object, new NullLogger <CorrelationManager>() ); #pragma warning restore 618 return(sut.CorrelateAsync(parentContextId, async() => { CorrelationContext parentContext = _correlationContextAccessor.CorrelationContext; parentContext.Should().NotBeNull(); parentContext.CorrelationId.Should().Be(parentContextId); await sut.CorrelateAsync(() => { CorrelationContext innerContext = _correlationContextAccessor.CorrelationContext; innerContext.Should().NotBeNull().And.NotBe(parentContext); innerContext.CorrelationId.Should().NotBe(parentContextId); return Task.CompletedTask; }); })); }
public Task When_starting_correlationContext_when_another_context_is_active_should_start_new() { const string parentContextId = nameof(parentContextId); const string innerContextId = nameof(innerContextId); return(_sut.CorrelateAsync(parentContextId, async() => { CorrelationContext parentContext = _correlationContextAccessor.CorrelationContext; parentContext.Should().NotBeNull(); parentContext.CorrelationId.Should().Be(parentContextId); await _sut.CorrelateAsync(innerContextId, () => { CorrelationContext innerContext = _correlationContextAccessor.CorrelationContext; innerContext.Should().NotBeNull(); innerContext.Should().NotBe(parentContext); innerContext.CorrelationId.Should().Be(innerContextId); return Task.CompletedTask; }); _correlationContextAccessor.CorrelationContext.Should().NotBeNull(); _correlationContextAccessor.CorrelationContext .CorrelationId .Should() .Be(parentContextId); })); }
private async Task CorrelateAsync(string correlationId, RootActivity activity, Func <Task> correlatedTask, OnException onException) { CorrelationContext correlationContext = activity.Start(correlationId ?? _correlationIdFactory.Create()); try { await correlatedTask().ConfigureAwait(false); } catch (Exception ex) { if (correlationContext != null && !ex.Data.Contains(CorrelateConstants.CorrelationIdKey)) { // Because we're about to lose context scope, enrich exception with correlation id for reference by calling code. ex.Data.Add(CorrelateConstants.CorrelationIdKey, correlationContext.CorrelationId); } if (onException == null) { throw; } // Allow caller to handle exception inline before losing context scope. bool isHandled = onException(correlationContext, ex); if (!isHandled) { throw; } } finally { activity.Stop(); } }
public async Task When_running_multiple_tasks_in_nested_context_should_inherit_from_ambient_parent() { const string rootName = "root-context"; var expectedNestedCorrelationIds = new List <string> { $"{rootName} > 1:0 | 1:0 > 1:1 | 1:1 > 1:2 | 1:2 > 1:3 | ", $"{rootName} > 2:0 | 2:0 > 2:1 | 2:1 > 2:2 | 2:2 > 2:3 | ", $"{rootName} > 3:0 | 3:0 > 3:1 | 3:1 > 3:2 | 3:2 > 3:3 | " }; var rootContext = new CorrelationContext { CorrelationId = rootName }; _sut.CorrelationContext = rootContext; // Act IEnumerable <Task <string> > tasks = Enumerable.Range(1, 3) .Select(i => RunChildTask(i.ToString())); string[] actual = await Task.WhenAll(tasks); _sut.CorrelationContext = null; // Assert actual.Should().BeEquivalentTo(expectedNestedCorrelationIds, "each task that creates new context should inherit from parent, and all inner tasks from their respective parent"); _sut.CorrelationContext.Should().BeNull(); }
/// <inheritdoc /> CorrelationContext ICorrelationContextFactory.Create(string correlationId) { CorrelationContext correlationContext = Create(correlationId); if (_correlationContextAccessor != null) { _correlationContextAccessor.CorrelationContext = correlationContext; } return(correlationContext); }
public void When_starting_correlationContext_inside_running_context_without_specifying_should_reuse() { _sut.Correlate(() => { CorrelationContext parentContext = _correlationContextAccessor.CorrelationContext; _sut.Correlate(() => { CorrelationContext innerContext = _correlationContextAccessor.CorrelationContext; innerContext.Should() .NotBe(parentContext) .And.BeEquivalentTo(parentContext); }); }); }
public Task When_starting_correlationContext_inside_running_context_without_specifying_should_reuse() { return(_sut.CorrelateAsync(async() => { CorrelationContext parentContext = _correlationContextAccessor.CorrelationContext; await _sut.CorrelateAsync(() => { CorrelationContext innerContext = _correlationContextAccessor.CorrelationContext; innerContext.Should() .NotBe(parentContext) .And.BeEquivalentTo(parentContext); return Task.CompletedTask; }); })); }
private T Execute <T>(string correlationId, Func <T> correlatedFunc, OnException onException) { IActivity activity = CreateActivity(); CorrelationContext correlationContext = StartActivity(correlationId, activity); try { return(correlatedFunc()); } catch (Exception ex) when(HandlesException(onException, correlationContext, ex, out T exceptionResult)) { return(exceptionResult); } finally { activity.Stop(); } }
private async Task <T> ExecuteAsync <T>(string correlationId, Func <Task <T> > correlatedTask, OnException onException) { IActivity activity = CreateActivity(); CorrelationContext correlationContext = StartActivity(correlationId, activity); try { return(await correlatedTask().ConfigureAwait(false)); } catch (Exception ex) when(HandlesException(onException, correlationContext, ex, out T exceptionResult)) { return(exceptionResult); } finally { activity.Stop(); } }
internal ExceptionContext(CorrelationContext correlationContext, Exception exception) { CorrelationContext = correlationContext; Exception = exception; }
void IActivity.Start(CorrelationContext correlationContext) { throw new NotImplementedException(); }