简体   繁体   English

文件事件中 Windows (ETW) 文件名的事件跟踪丢失

[英]Event Trace for Windows (ETW) FileName in File events missing

I am trying to do some work with ETW in C#.我正在尝试在 C# 中使用 ETW 做一些工作。 Some raw events require a sort of 'aggregation' performed on them to obtain the full data in each event.一些原始事件需要对它们执行某种“聚合”以获得每个事件中的完整数据。 This action takes information from some events and fills it in others.此操作从某些事件中获取信息并将其填充到其他事件中。

This action can be performed on the output file of the ETW framework however I need to perform it dynamically in the real time of event apperance.此操作可以在 ETW 框架的 output 文件上执行,但是我需要在事件出现的实时动态执行它。 I managed to perform this for the registry events and their missing "KeyName" values thanks to the answers in this thread.由于线程中的答案,我设法为注册表事件及其丢失的“KeyName”值执行此操作。

I could not however find any information that would allow me to interpret the ETW file events to figure out the "FileName" attribute in each event.但是,我找不到任何信息可以让我解释 ETW 文件事件以找出每个事件中的“文件名”属性。

Does anyone know how the FileIO events should be interpreted to obtain missing "FileNames" in each event?有谁知道应该如何解释 FileIO 事件以在每个事件中获取缺少的“FileNames”? Are there any resources on this topic that I might have missed?有没有我可能错过的关于这个主题的资源?

Ps.附言。 I am sorry if this question is unclear.如果这个问题不清楚,我很抱歉。

You might be missing FileRundown events.您可能缺少 FileRundown 事件。 Normally, KernelTraceEventParserState keeps a dictionary which maps FileObject/FileKey to FileName.通常, KernelTraceEventParserState保留一个字典,将 FileObject/FileKey 映射到 FileName。 KernelTraceEventParser configures various hooks to fill this dictionary. KernelTraceEventParser配置各种钩子来填充这个字典。 The first problems are cleanup and delete events that remove file names from the dictionary before your hook is called.第一个问题是清理和删除事件,在调用钩子之前从字典中删除文件名。 For other events, the problem is that you miss FileKey mappings for processes that were running before your trace started.对于其他事件,问题是您错过了跟踪开始之前正在运行的进程的 FileKey 映射。 And I haven't found a way to force the rundown events to run at the begging of the session.而且我还没有找到一种方法来强制破败事件在 session 的请求下运行。 The only workaround I can propose is to run a short trace session with DiskIO | DiskFileIO我可以建议的唯一解决方法是使用 DiskIO 运行短跟踪DiskIO | DiskFileIO DiskIO | DiskFileIO keywords enabled and prepare your file key map.启用DiskIO | DiskFileIO关键字并准备文件密钥 map。 Later, in the main session, update it when you receive the FileIO/Create event.稍后,在主 session 中,在收到FileIO/Create事件时对其进行更新。 You may check a post on my blog to learn more details.您可以查看我博客上的帖子以了解更多详细信息。

Below, I paste the F# code I used to test FileIO events.下面,我粘贴了我用来测试 FileIO 事件的 F# 代码。 I hope it will help you with your scenario.我希望它会帮助你解决你的场景。

open System
open System.Threading
open Microsoft.Diagnostics.Tracing
open Microsoft.Diagnostics.Tracing.Parsers
open Microsoft.Diagnostics.Tracing.Session
open System.Collections.Generic
open Microsoft.Diagnostics.Tracing.Parsers.Kernel

type NtKeywords = KernelTraceEventParser.Keywords
type ClrKeywords = ClrTraceEventParser.Keywords

let rundownFileKeyMap sessionName =
    use session = new TraceEventSession(sessionName)

    let traceFlags = NtKeywords.DiskFileIO ||| NtKeywords.DiskIO
    session.EnableKernelProvider(traceFlags, NtKeywords.None) |> ignore

    let fileKeyMap = Dictionary<uint64, string>()
    session.Source.Kernel.add_FileIOFileRundown(fun ev -> fileKeyMap.[ev.FileKey] <- ev.FileName)

    use cts = new CancellationTokenSource(TimeSpan.FromSeconds(2.0))
    use _r = cts.Token.Register(fun _ -> session.Stop() |> ignore)

    session.Source.Process() |> ignore

    fileKeyMap

let processEvent (fileObjectAndKeyMap : Dictionary<uint64, string>) (ev : TraceEvent) =
    let opcode = int32(ev.Opcode)

    let fileKey =
        let i = ev.PayloadIndex("FileKey")
        if i >= 0 then ev.PayloadValue(i) :?> uint64 else 0UL
    let fileObject =
        let i = ev.PayloadIndex("FileObject")
        if i >= 0 then ev.PayloadValue(i) :?> uint64 else 0UL

    let path = 
        if opcode = 64 (* create *) then
            let ev = ev :?> FileIOCreateTraceData
            let fileName = ev.FileName
            fileObjectAndKeyMap.[fileObject] <- fileName
            fileName
        else
            let chooser k =
                match fileObjectAndKeyMap.TryGetValue(k) with
                | (true, s) -> Some s
                | (false, _) -> None
            seq { fileKey; fileObject } 
            |> Seq.tryPick chooser 
            |> Option.defaultValue "n/a"

    printfn "%d %s (%d) (%s) [%d.%d] (%s) key: 0x%X object: 0x%X '%s'" 
        (uint32(ev.EventIndex)) ev.EventName opcode (ev.GetType().Name) 
        ev.ProcessID ev.ThreadID ev.ProcessName fileKey fileObject path

[<EntryPoint>]
let main _ =
    let sessionName = sprintf "mytrace-%d" DateTime.UtcNow.Ticks

    use session = new TraceEventSession(sessionName)

    let traceFlags = NtKeywords.FileIOInit
    let stackFlags = NtKeywords.None
    session.EnableKernelProvider(traceFlags, stackFlags) |> ignore

    printf "Collecting rundown events..."
    let fileObjectAndKeyMap = rundownFileKeyMap (sprintf "%s_rundown" sessionName)
    printfn "done"
    printfn "Key map size: %d" fileObjectAndKeyMap.Count

    use _sub = session.Source.Kernel.Observe(fun s -> s.StartsWith("FileIO", StringComparison.Ordinal))
               |> Observable.subscribe (processEvent fileObjectAndKeyMap)

    Console.CancelKeyPress.Add(fun ev -> ev.Cancel <- true; session.Stop() |> ignore)

    session.Source.Process() |> ignore

    printfn "Key map size: %d" fileObjectAndKeyMap.Count
    0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM