如何跟踪尝试为侦听器设置 Azure 接收器时的异常源

How can I track the source of exception on trying to set Azure sink for a listener

我正在尝试使用 Semantic Logging Application Block 将日志存储到 Azure Table Storage。设置:

ObservableEventListener listener1 = new ObservableEventListener();
var conString =
    $"DefaultEndpointsProtocol={CloudStorageAccount.DevelopmentStorageAccount.TableEndpoint.Scheme};" +
    $"AccountName={CloudStorageAccount.DevelopmentStorageAccount.Credentials.AccountName};" +
    $"AccountKey={Convert.ToBase64String(CloudStorageAccount.DevelopmentStorageAccount.Credentials.ExportKey())}";
    
listener1.LogToWindowsAzureTable( // <---- EXCEPTION HERE
        instanceName: "instName",
        connectionString: conString);

我遇到了一个奇怪的异常:

Exception thrown: 'System.MissingMethodException' in Microsoft.Practices.EnterpriseLibrary.SemanticLogging.WindowsAzure.dll

Additional information: Method not found: 'Void Microsoft.WindowsAzure.Storage.Table.CloudTableClient.set_RetryPolicy(Microsoft.WindowsAzure.Storage.RetryPolicies.IRetryPolicy)'.

我的真实账户也有同样的问题。包版本(全部来自 NuGet):

如何跟踪异常的来源? Google 没有说明找不到的方法。要在您的机器上测试的项目是 here.

您收到此错误的原因是 SLAB 依赖于存储客户端库 3.0.2.0 (source) and setting Retry Policies on client (CloudTableClient for example) was deprecated in version 4.0.0.0 (source),并在某些更高版本中被删除(不确定是哪个版本)。

因为您使用的是存储客户端库版本 7.x,所以在 CloudTableClient 上设置 RetryPolicy 的方法不存在,因此您会收到此错误。

正如 Guarav 所说,SLAB 是针对 Microsoft.WindowsAzure.Storage 的一个非常旧的版本构建的。问题是 this line, using client.RetryPolicy instead of client.DefaultRequestOptions.RetryPolicy. I tried updating the NuGet packages and change it but it seemed to break some tests and it didn't seem trivial to fix them. Also it looks like 4.6 support is not there: https://github.com/mspnp/semantic-logging/issues/64.

这里有一个缺陷:https://github.com/mspnp/semantic-logging/issues/81, but I doubt anything is going to happen with it any time soon (if ever). I'll probably end up writing some simple sink that redirects the logs to a Trace Listener for Azure to take care of (including Table Storage upload)。

编辑这里的代码(尚未测试):

public class SystemDiagnosticsTraceSink : IObserver<EventEntry>
{
    public void OnNext(EventEntry entry)
    {
        if (entry == null) return;
        using (var writer = new StringWriter())
        {
            new EventTextFormatter().WriteEvent(entry, writer);
            var eventText = writer.ToString();
            switch (entry.Schema.Level)
            {
                case EventLevel.LogAlways:
                case EventLevel.Critical:
                case EventLevel.Error:
                    Trace.TraceError(eventText);
                    return;
                case EventLevel.Warning:
                    Trace.TraceWarning(eventText);
                    return;
                case EventLevel.Informational:
                case EventLevel.Verbose:
                    Trace.TraceInformation(eventText);
                    return;
                default:
                    Trace.TraceError("Unknown event level: " + entry.Schema.Level);
                    Trace.TraceInformation(eventText);
                    return;
            }
        }
    }
    public void OnError(Exception error)
    {} //you might want to do something here
    public void OnCompleted()
    {} //nothing to do
}

和扩展名 class:

public static class SystemDiagnosticsTraceSinkExtensions
{
    public static SinkSubscription<SystemDiagnosticsTraceSink> LogToSystemDiagnosticsTrace
      (this IObservable<EventEntry> eventStream)
    {
        if (eventStream == null) throw new ArgumentNullException(nameof(eventStream));

        var sink = new SystemDiagnosticsTraceSink();
        return new SinkSubscription<SystemDiagnosticsTraceSink>(
                       eventStream.Subscribe(sink), sink);
    }
}