static const SID sid = { SID_REVISION, 1, 5, { 18 } };
TRACELOGGING_DECLARE_PROVIDER(g_hProvider);
// 3B9CAB28-762A-4740-A82B-B6829CC90ADF
TRACELOGGING_DEFINE_PROVIDER(
g_hProvider,
"My-Test-Provider",
(0x3b9cab28, 0x762a, 0x4740, 0xa8, 0x2b, 0xb6, 0x82, 0x9c, 0xc9, 0xa, 0xdf));
int main() {
TraceLoggingRegister(g_hProvider);
EmitEID1();
for (int i = 0; i < 5; i++) {
EmitEID2();
}
TraceLoggingUnregister(g_hProvider);
}
void EmitEID1() {
TraceLoggingWrite(g_hProvider,
"ProcessCreation",
TraceLoggingUInt8(1, "EventId"),
TraceLoggingUInt32(44, "Pid"),
TraceLoggingUInt32(400, "ParentPid"),
TraceLoggingWideString(L"test-provider.exe", "ParentProcessName"),
TraceLoggingUInt32(600, "CreatorPid"),
TraceLoggingWideString(L"test-provider.exe", "CreatorProcessName"),
TraceLoggingWideString(L"test-provider.exe", "FileName"),
TraceLoggingBoolean(TRUE, "ExactFileName"),
TraceLoggingWideString(L"testing", "CommandLine"),
TraceLoggingSid(&sid, "Sid"),
TraceLoggingBoolean(FALSE, "SubsystemProcess")
);
}
void EmitEID2() {
TraceLoggingWrite(g_hProvider,
"ThreadCreation",
TraceLoggingUInt8(2, "EventId"),
TraceLoggingUInt32(6000, "CreatorPid"),
TraceLoggingWideString(L"test-provider.exe", "CreatorProcessName"),
TraceLoggingUInt32(444, "TargetPid"),
TraceLoggingWideString(L"test-provider.exe", "TargetProcessName"),
TraceLoggingUInt32(6464, "TargetThreadId"),
TraceLoggingSid(&sid, "Sid")
);
}
I've written a basic consumer application that parses the events into a struct.
use ferristetw::*;
fn main() {
let test_provider = provider::Provider
::by_guid("3B9CAB28-762A-4740-A82B-B6829CC90ADF")
.add_callback(test_callback)
.build();
let test_trace = UserTrace::new()
.enable(test_provider)
.start_and_process()
.unwrap();
std::thread::sleep(std::time::Duration::new(60, 0));
test_trace.stop().unwrap();
}
fn test_callback(record: &EventRecord, schema_locator: &SchemaLocator) {
match schema_locator.event_schema(record) {
Err(err) => println!("Unable to get the ETW schema for event: {:?}", err),
Ok(schema) => parse_event(&schema, record)
}
}
fn parse_event(schema: &schema::Schema, record: &EventRecord) {
let parser = parser::Parser::create(record, schema);
match parser.try_parse::<u8>("EventId").unwrap_or(0) {
2 => {
let event = ThreadCreatedEvent {
id: 2,
description: String::from("Thread created"),
creator_pid: parser.try_parse::<u32>("CreatorPid").unwrap_or(0),
creator_process_name: parser.try_parse::<String>("CreatorProcessName").unwrap_or_else(|_| String::from("")),
target_pid: parser.try_parse::<u32>("TargetPid").unwrap_or(0),
target_process_name: parser.try_parse::<String>("TargetProcessName").unwrap_or_else(|_| String::from("")),
target_thread_id: parser.try_parse::<u32>("TargetThreadId").unwrap_or(0),
sid: parser.try_parse::<String>("Sid").unwrap_or_else(|_| String::from(""))
};
println!("{:?}", event);
}
_ => {}
}
}