2016-08-19 15 views
6

Tôi đang sử dụng NLog 4.3.5 và .Net framework 4.6.1NLog MappedDiagnosticsLogicalContext không làm việc trong async/chờ đợi với ConfigureAwait (false)

Khi tôi bắt đầu một hoạt động phía máy chủ tôi gọi:

NLog.MappedDiagnosticsLogicalContext.Set("OperationId", Guid.NewGuid()); 

Điều này được ánh xạ qua và xuất hiện trong các tệp nhật ký của tôi. Tất cả là tốt .... hay là nó? Khi xem lại các tệp nhật ký của tôi, tôi nhận thấy rằng giá trị id hoạt động này dường như không hoạt động như tôi mong đợi.

Ví dụ:

  1. Trong chủ đề 19 một hoạt động bắt đầu và thiết lập ngữ cảnh.

  2. Nó sử dụng .ConfigureAwait (false) trên tất cả các cuộc gọi đang chờ đợi

  3. Nó thực hiện một

    var tasks = items.Select(item => Task.Run(() => { /* do stuff */} 
    await Task.WhenAll(tasks).ConfigureAwait(false) 
    
  4. Một trong những chủ đề được sử dụng cho những công việc này là chủ đề 31 (giữ ý nghĩ đó cho sau này)
  5. Trong khi đó, trong chuỗi 36, một phương thức máy chủ khác được gọi và bắt đầu một thao tác mới. Một số thông điệp tường trình được viết bằng id hoạt động duy nhất
  6. Thao tác này thực hiện 2 cuộc gọi chờ khác nhau với ConfigureAwait (false)
  7. Câu lệnh nhật ký tiếp theo xảy ra trên chuỗi 31. Từ đó, nó ghi lại id hoạt động đã được tạo cho các hoạt động bắt đầu trên thread 19!

Tôi không mong đợi điều này xảy ra và không chắc chắn về cách nó xảy ra. Nhưng, khi tôi xem qua lịch sử nhật ký của mình, tôi thấy rằng loại điều này đã xảy ra trước đây.

Tôi nghĩ ngữ cảnh cuộc gọi logic được cho là sẽ chuyển sang. Có phải tôi sử dụng ConfigureAwait (sai) đang gây ra hành vi này? Đó là điều duy nhất tôi có thể nghĩ đến ...

Trả lời

1

Bạn có thể làm việc xung quanh này như sau:

public static class LogicalThreadContext 
{ 
    private const string KeyPrefix = "NLog.LogicalThreadContext"; 

    private static string GetCallContextKey(string key) 
    { 
     return string.Format("{0}.{1}", KeyPrefix, key); 
    } 

    private static string GetCallContextValue(string key) 
    { 
     return CallContext.LogicalGetData(GetCallContextKey(key)) as string ?? string.Empty; 
    } 

    private static void SetCallContextValue(string key, string value) 
    { 
     CallContext.LogicalSetData(GetCallContextKey(key), value);   
    } 

    public static string Get(string item) 
    { 
     return GetCallContextValue(item); 
    } 

    public static string Get(string item, IFormatProvider formatProvider) 
    { 
     if ((formatProvider == null) && (LogManager.Configuration != null)) 
     { 
      formatProvider = LogManager.Configuration.DefaultCultureInfo; 
     } 

     return string.Format(formatProvider, "{0}", GetCallContextValue(item)); 
    } 

    public static void Set(string item, string value) 
    { 
     SetCallContextValue(item, value); 
    } 
} 

[LayoutRenderer("mdlc2")] 
public class LogicalThreadContextLayoutRenderer : LayoutRenderer 
{ 
    [DefaultParameter] 
    public bool Name {get;set;} 

    protected override void Append(StringBuilder builder, LogEventInfo logEvent) 
    { 
     builder.Append(LogicalThreadContext.Get(Name, null)); 
    } 
} 

//or application_start for ASP.NET 4 
static void Main(string[] args) 
{ 
    //layout renderer 
    ConfigurationItemFactory.Default.LayoutRenderers 
      .RegisterDefinition("mdlc2", typeof(LogicalThreadContextLayoutRenderer)); 
} 

Cách sử dụng trong tập tin cấu hình:

${mdlc2:OperationId} 
+0

Có, giải pháp đó là trong liên kết tôi đã đăng ở trên. – Keith

+0

Đây là một phần từ liên kết. Tôi đã cập nhật và mở rộng cho các yêu cầu của bạn. – Julian

Các vấn đề liên quan