This page is being prepared for a substantial reworking. Some content may be temporarily missing. Temporarily may turn into indefinitely. New content may be more than usually defective. The page is now published only as a revision in progress. Use with caution.

TRACE_LOGFILE_HEADER

The TRACE_LOGFILE_HEADER is one of many types of fixed-size header that begin the event-specific data for an event as held in a trace buffer or flushed to an Event Trace Log (ETL) file.

The type of event for which the TRACE_LOGFILE_HEADER can be the event-specific data is the system event WMI_LOG_TYPE_HEADER (0x0000).

Usage

The WMI_LOG_TYPE_HEADER event is the very first in every ETL file, beginning immediately after the first WMI_BUFFER_HEADER. It records which logger recorded the file, and under what conditions. Interpretation of all the events in the rest of the file can depend on what’s recorded in the WMI_LOG_TYPE_HEADER event.

Documentation Status

The TRACE_LOGFILE_HEADER is documented. Of course, this is not so that it can be inspected in an ETL file. What is documented is the translation that is presented to callers of the documented OpenTrace function as output in the LogfileHeader member of the EVENT_TRACE_LOGFILE structure whose address is passed to the function as its one argument.

This article is concerned only with the raw TRACE_LOGFILE_HEADER as it appears in trace buffers or ETL files, as prepared by the kernel, and only then to note where this differs from what is documented.

Layout

Data for the WMI_LOG_TYPE_HEADER event comprises:

Trace Header

In the Marker that begins the SYSTEM_TRACE_HEADER, the Flags are 0xC0, the HeaderType is 0x01 or 0x02 for a 32-bit or 64-bit trace session, respectively, and the Version is nowadays 0x02 but is 0x01 in traces written by Windows versions before 6.0. The Size is the total in bytes of all the components, both the fixed-size headers and the variable-size strings. The HookId is WMI_LOG_TYPE_HEADER.

Note that the HeaderType matters since the TRACE_LOGFILE_HEADER has different 32-bit and 64-bit forms (named TRACE_LOGFILE_HEADER32 and TRACE_LOGFILE_HEADER64). A 32-bit trace session on 64-bit Windows writes the 32-bit form. Whether an ETL file was made by a 32-bit or 64-bit trace session, it may be interpreted on either 32-bit or 64-bit Windows.

Event-Specific Data

The TRACE_LOGFILE_HEADER is 0x0110 or 0x0118 bytes in its 32-bit and 64-bit forms, respectively, in all known versions that have it.

Offset (x86) Offset (x64) Definition Versions
0x00 0x00
ULONG BufferSize;
5.0 and higher
0x04 0x04
union {
    ULONG Version;
    struct {
        UCHAR MajorVersion;
        UCHAR MinorVersion;
        UCHAR SubVersion;
        UCHAR SubMinorVersion;
    } VersionDetail;
};
5.0 and higher
0x08 0x08
ULONG ProviderVersion;
5.0 and higher
0x0C 0x0C
ULONG NumberOfProcessors;
5.0 and higher
0x10 0x10
LARGE_INTEGER EndTime;
5.0 and higher
0x18 0x18
ULONG TimerResolution;
5.0 and higher
0x1C 0x1C
ULONG MaximumFileSize;
5.0 and higher
0x20 0x20
ULONG LogFileMode;
5.0 and higher
0x24 0x24
ULONG BuffersWritten;
5.0 and higher
0x28 0x28
union {
    GUID LogInstanceGuid;
    struct {
        ULONG StartBuffers;
        ULONG PointerSize;
        ULONG EventsLost;
        ULONG Reserved32;
    };
};
5.0 only
union {
    GUID LogInstanceGuid;
    struct {
        ULONG StartBuffers;
        ULONG PointerSize;
        ULONG EventsLost;
        ULONG CpuSpeedInMHz;
    };
};
5.1 and higher
0x38 0x38
PWSTR LoggerName;
5.0 and higher
0x3C 0x40
PWSTR LogFileName;
5.0 and higher
0x40 0x48
RTL_TIME_ZONE_INFORMATION TimeZone;
5.0 to 5.2
TIME_ZONE_INFORMATION TimeZone;
6.0 and higher
0xF0 0xF8
LARGE_INTEGER BootTime;
5.0 and higher
0xF8 0x0100
LARGE_INTEGER PerfFreq;
5.0 and higher
0x0100 0x0108
LARGE_INTEGER StartTime;
5.0 and higher
0x0108 0x0110
ULONG ReservedFlags;
5.0 and higher
0x010C 0x0114
ULONG BuffersLost;
5.0 and higher

It arguably was only ever a curiosity with no practical effect, and now it is only a historical curiosity, but there is significance to Microsoft’s comments in EVNTRACE.H when introducing the C-language definition of the TRACE_LOGFILE_HEADER:

// TRACE_LOGFILE_HEADER32 and TRACE_LOGFILE_HEADER64 structures
// are also provided to simplify cross platform decoding of the
// header event.

Microsoft added this comment for Windows 7. The separate formal definitions were apparently not just newly provided to the world but newly devised even within Microsoft, and not just for interpreting the structure but also for the kernel’s writing of it. Versions 5.2 and 6.0 trust that a set Wow flag in the WMI_LOGGER_INFORMATION that the kernel receives when starting a logger means that 32-bit forms of various structures are wanted instead of 64-bit. For the TRACE_LOGFILE_HEADER this means using a 32-bit form that is eight bytes smaller than the 64-bit form that would be native to the 64-bit kernel. The 32-bit kernels for these versions also have code for preparing a reduced structure—which is then eight bytes smaller than the already smaller 32-bit structure.

The BufferSize is in bytes, not kilobytes, no matter that Microsoft says differently in both the documentation and the EVNTRACE.H comments. That it should be bytes, if only for the TRACE_LOGFILE_HEADER as prepared by the kernel for flushing to an ETL file, was plainly intended from the start. The version 5.0 kernel prepares the structure directly from the WMI_LOGGER_INFORMATION. The latter’s BufferSize is in KB and the kernel explicitly multiplies by 1024 to get the BufferSize for the TRACE_LOGFILE_HEADER.

In the VersionDetail, all versions set the MajorVersion and MinorVersion to those of Windows itself. The following are known for the SubVersion and SubMinorVersion:

See that the SubVersion and SubMinorVersion nowadays tell a little of the logger’s capability. Sufficiently advanced means any of the following:

A header file, named NTWMI.H, which Microsoft is known to have published only with the original and Version 1511 editions of the Windows Driver Kit (WDK) for Windows 10 describes these version numbers in comments:

// The following two are used for defining LogFile layout version.
//
//  1.2 -- Add per-processor event streams.
//  1.3 -- Remove rundown and context/switch streams.
//  1.4 -- Add header stream.
//  1.5 -- Include QPC and Platform clock source in the header.
//
//  2.0 -- Larger Buffers (over 1MB) / 256+ Processors / Compression (Win8).
//

Whether this comment’s start at version 1.2 means that Microsoft regards earlier versions as prehistory, it may be as well to note one case for showing how important these version numbers were and may still be. Not that version 1.1 is known in any released build, it is (still) the cut-off for deciding which format the logger used for events that came through the TraceEventInstance function. If the version is at least 1.1 (but, before Windows 7, as a coding error, if the major and minor version numbers are both at least 1), then these events are interpreted as beginning with the new EVENT_INSTANCE_GUID_HEADER. Otherwise, they have the old, smaller, EVENT_INSTANCE_HEADER.

In version 6.1 and higher, if the logger is configured for the EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING (0x10000000) mode, then the NumberOfProcessors is 1 no matter how many processors are active.

The LogFileMode reported in this structure is not exactly what was ever specified for the logger as a LogFileMode nor even what the logger keeps as its LoggerMode in the WMI_LOGGER_CONTEXT. The following flags are cleared from it:

Though Microsoft’s C-language definition of the TRACE_LOGFILE_HEADER has provided for a CpuSpeedInMHz since Windows XP, it is not until Windows Vista that the kernel sets this member.

The null-terminated Unicode strings that are otherwise suggested for the LoggerName and LogFileName simply follow the structure. Before version 6.1, the LoggerName and LogFileName actually are saved as pointers to these strings. They have since been repurposed and now take values from the HAL_PLATFORM_TIMER_SOURCE enumeration to tell of what hardware produces the clock interrupt and performance counter, respectively.

Microsoft’s C-language definition of the TRACE_LOGFILE_HEADER for kernel-mode programming in all versions provides conditionally that the TimeZone can be an RTL_TIME_ZONE_INFORMATION whose definition Microsoft provides in no other headers. This differs from the documented TIME_ZONE_INFORMATION only in having the kernel-mode TIME_FIELDS instead of the user-mode SYSTEMTIME. Versions before 6.0 do not translate the TimeZone from the undocumented RTL_TIME_ZONE_INFORMATION to a plain old TIME_ZONE_INFORMATION.

Before version 6.0, the ReservedFlags are 1 if the logger uses the performance counter, but are otherwise 0. In modern versions, the ReservedFlags record the logger’s ClockType, which is again 1 if the logger uses the performance counter, but is 2 for the system time and 3 for the CPU cycle counter.