LoggingSession.SaveToFileAsync 有时会创建以 .etl.tmp 结尾的文件

LoggingSession.SaveToFileAsync sometimes creates files ending with .etl.tmp

我有一个通用的 Windows/WindowsPhone 8.1 应用程序,我在其中使用 LoggingSession 在我的应用程序运行时记录消息。

当发生未处理的异常时,我会记录异常,然后等待对 LoggingSession.SaveToFileAsync 的调用以将日志转储到文件中。下次启动我的应用程序时,我会上传日志文件并在我这边接收它。

我看到的问题是,有时我的日志文件以 .etl.tmp 结尾(通常文件大小为 50 - 100 Kb),当我尝试打开它们时(使用 tracerpt 或 Windows 事件查看器)我没有看到任何日志。其他时候,我打开 .etl.tmp 文件,这些文件的大小通常约为 200Kb,我会看到一些日志条目。还有一些时候,日志文件(通常小于 20Kb)正确地以 .etl 扩展名结尾(没有 .tmp)并且所有记录的消息都在那里。

1) 为什么 LoggingSession.SaveToFileAsync 有时会生成扩展名为 .etl.tmp 的文件?

2) 关于如何解决这个问题有什么建议吗?在将它们保存到文件之前,我需要捕获所有日志(甚至是未处理的异常),这就是为什么我在我的应用程序的未处理异常事件处理程序中调用 LoggingSession.SaveToFileAsync 的原因。我还需要我的日志记录解决方案是高性能的,而不是太慢我的应用程序。

谢谢


这是精简的示例代码:

public sealed partial class App : Application
{
    .
    .
    .

    public static ETWLogger Logger;
    public App()
    {
        InitializeComponent();

        Logger = new ETWLogger();

        Suspending += OnSuspending;
        UnhandledException += OnUnhandledExceptionAsync;
    }

    private async void OnUnhandledExceptionAsync(object sender, UnhandledExceptionEventArgs args)
    {
        await Logger.SaveToFileAsync();
    }

    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        // Check to see if there are files in the Log folder. If so
        // then upload them and then delete all files in the Log folder.
    }

    .
    .
    .
}

public class ETWLogger
{
    private LoggingSession _session;
    private LoggingChannel _channel;
    private StorageFolder _logFolder;
    .
    .
    .

    public ETWLogger()
    {
        .
        .
        .
        _session = new LoggingSession("DefaultSession");
        _channel = new LoggingChannel("DefaultChannel");
        _session.AddLoggingChannel(_channel);

        _logFolder = StorageHelper.CreateSubFolder(ApplicationData.Current.LocalFolder, "LogFiles", CreationCollisionOption.OpenIfExists);
        .
        .
        .
    }

    public async Task SaveToFileAsync()
    {
        if (_session == null) return;

        var fileName = DateTime.Now.ToString("yyyyMMdd-HHmmssTzz", CultureInfo.InvariantCulture) + ".etl";
        await _session.SaveToFileAsync(_logUploadFolder, fileName);
    }

    .
    .
    .
}

我很清楚这里发生了什么。您描述了 Microsoft 使用的一种常用技术,它可以防止文件损坏和数据丢失。它不是创建您要求的 foo.etl 文件,而是 first 创建具有不同名称的文件。像 foo.etl.tmp。只有当文件写入成功,或者换句话说,async 方法真正完成后,它才会将文件从 foo.etl.tmp 重命名为 foo.etl.

您现在可以很好地保证您始终获得完整的 "good" 文件。没有腐败。如果您以前有一个同名文件,那么它不会被损坏的半写文件替换。没有数据丢失。

When an unhandled exception occurs, I log the exception and then I await a call

"unhandled exception" 就是问题所在。仅当异常不足以阻止 async/await 管道继续工作时,您的日志文件才能被完整写入。或者换句话说,您现在只能获得 "mild" 异常信息。坏的产生写了一半的 foo.etl.tmp 文件,应用程序在完成之前就倒塌了。

如果您想了解 "bad" 个,您不能在这里使用 await。 SaveToFileAsync() 调用必须同步完成。