我看到Microsoft.Windows.EventTracing.Interop.Metadata.NativeTraceLogfileHeader包含BootTime的值。在某些情况下这可能很有用。通过ITraceMetaData接口暴露的任何机会还是可以通过其他方式访问?
// Microsoft.Windows.EventTracing.Metadata.ITraceMetadata
using Microsoft.Windows.EventTracing;
public interface ITraceMetadata
{
Version OSVersion
bool Is32Bit
FrequencyValue ProcessorSpeed
TraceClockType ClockType
FrequencyValue PerformanceCounterFrequency
TraceTimestampValue? ReferenceTimestampValue
FrequencyValue ProcessorUsageTimerFrequency
TraceTimestamp FirstAnalyzerDisplayedEventTime
TraceTimestamp LastEventTime
TraceDuration AnalyzerDisplayedDuration
long LostBufferCount
long LostEventCount
string TracePath
DateTimeOffset StartTime
DateTimeOffset StopTime
int ProcessorCount
int KernelEventVersion
}
我将让当前的团队成员回答有关可以进行哪些更改。从概念上讲,在发布v1 API之前,我认为将这些数据添加到ITraceMetadata是合理的。
我不记得要将此数据添加到API中的其他任何内容。 (我检查了ISystemMetadata,在那儿没看到它。)我知道的唯一解决方法是使用IEventConsumer / IFilteredEventConsumer解析包含该数据的事件的有效负载(总是跟踪中的第一个事件,我认为,无论该事件具有什么ProviderId / Id,我都不会立即记住)。
如果我没记错的话,有效载荷就是TRACE_LOGFILE_HEADER structure。但是请注意,由于该事件中包含LoggerName / LogFileName指针,因此该事件同时具有32位和64位版本(基于跟踪的位数,而不是处理跟踪的计算机的位数)。
编辑:
这里是一个示例exe文件,它通过跟踪标头事件获取启动时间。 (我正在使用trace.Use(),但IFilteredEventConsumer等效。)
using Microsoft.Windows.EventTracing;
using System;
using System.Runtime.InteropServices;
class Program
{
static int Main(string[] args)
{
if (args.Length != 1)
{
Console.Error.WriteLine("Usage: GetTraceBootTime.exe <trace.etl>");
return 1;
}
string tracePath = args[0];
using (ITraceProcessor trace = TraceProcessor.Create(tracePath))
{
DateTime? bootTime = null;
Guid eventTraceProviderId = new Guid("68fdd900-4a3e-11d1-84f4-0000f80464e3");
trace.Use(new[] { eventTraceProviderId }, e =>
{
if (e.Event.Id != 0 || e.Event.Version != 2)
{
return;
}
var data = e.Event.Data;
long rawBootTime;
if (e.Event.Is32Bit)
{
if (data.Length < Marshal.SizeOf<NativeTraceHeaderEvent32>())
{
throw new InvalidOperationException("Invalid 32-bit trace header event.");
}
IntPtr pointer = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data.ToArray(), 0, pointer, data.Length);
NativeTraceHeaderEvent32 typedData = Marshal.PtrToStructure<NativeTraceHeaderEvent32>(pointer);
Marshal.FreeHGlobal(pointer);
rawBootTime = typedData.BootTime;
}
else
{
if (data.Length < Marshal.SizeOf<NativeTraceHeaderEvent64>())
{
throw new InvalidOperationException("Invalid 64-bit trace header event.");
}
IntPtr pointer = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data.ToArray(), 0, pointer, data.Length);
NativeTraceHeaderEvent64 typedData = Marshal.PtrToStructure<NativeTraceHeaderEvent64>(pointer);
Marshal.FreeHGlobal(pointer);
rawBootTime = typedData.BootTime;
}
// See https://docs.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-trace_logfile_header:
// BootTime is ticks since midnight, January 1, 1601 and is apparently UTC (despite documentation to the
// contrary).
DateTime epoch = new DateTime(1601, 1, 1, 0, 0, 0, DateTimeKind.Utc);
bootTime = epoch.AddTicks(rawBootTime);
e.Cancel();
});
trace.Process();
Console.WriteLine(bootTime);
}
return 0;
}
// https://docs.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-trace_logfile_header
[StructLayout(LayoutKind.Sequential)]
struct NativeTraceHeaderEvent64
{
public uint BufferSize;
public byte MajorVersion;
public byte MinorVersion;
public byte SubVersion;
public byte SubMinorVersion;
public uint ProviderVersion;
public uint NumberOfProcessors;
public long EndTime;
public uint TimerResolution;
public uint MaximumFileSize;
public uint LogFileMode;
public uint BuffersWritten;
public uint StartBuffers;
public uint PointerSize;
public uint EventsLost;
public uint CpuSpeedInMHz;
public ulong LoggerName;
public ulong LogFileName;
public NativeTimeZoneInformation TimeZone;
public long BootTime;
public long PerfFreq;
public long StartTime;
public uint ReservedFlags;
public uint BuffersLost;
}
// https://docs.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-trace_logfile_header
[StructLayout(LayoutKind.Sequential)]
struct NativeTraceHeaderEvent32
{
public uint BufferSize;
public byte MajorVersion;
public byte MinorVersion;
public byte SubVersion;
public byte SubMinorVersion;
public uint ProviderVersion;
public uint NumberOfProcessors;
public long EndTime;
public uint TimerResolution;
public uint MaximumFileSize;
public uint LogFileMode;
public uint BuffersWritten;
public uint StartBuffers;
public uint PointerSize;
public uint EventsLost;
public uint CpuSpeedInMHz;
public uint LoggerName;
public uint LogFileName;
public NativeTimeZoneInformation TimeZone;
public long BootTime;
public long PerfFreq;
public long StartTime;
public uint ReservedFlags;
public uint BuffersLost;
}
// https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time_zone_information
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct NativeTimeZoneInformation
{
public int Bias;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] StandardName;
public NativeSystemTime StandardDate;
public int StandardBias;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] DaylightName;
public NativeSystemTime DaylightDate;
public int DaylightBias;
}
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime
[StructLayout(LayoutKind.Sequential)]
struct NativeSystemTime
{
public short wYear;
public short wMonth;
public short wDayOfWeek;
public short wDay;
public short wHour;
public short wMinute;
public short wSecond;
public short wMilliseconds;
}
}