首页 > 解决方案 > JNA 从 Windows 事件日志记录中解析描述字符串

问题描述

我正在使用 JNA 读取我的应用程序提供的一些事件日志。我最感兴趣的是描述字符串数据。

我正在使用下面的代码:

private static void readLog() {
        Advapi32Util.EventLogIterator iter = new Advapi32Util.EventLogIterator("Application");
        while (iter.hasNext()) {
            Advapi32Util.EventLogRecord record = iter.next();

            System.out.println("------------------------------------------------------------");
            System.out.println(record.getRecordNumber()
                    + ": Event ID: " + record.getInstanceId()
                    + ", Event Type: " + record.getType()
                    + ", Event Strings: " + Arrays.toString(record.getStrings())
                    + ", Data: " + record.getRecord().toString());
            System.out.println();
        }
    }

我的应用程序产生的示例事件:

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
    <System>
        <Provider Name="Microsoft-Windows-MyApp" Guid="{4d5ae6a1-c7c8-4e6d-b840-4d8080b42e1b}" />
        <EventID>201</EventID>
        <Version>0</Version>
        <Level>2</Level>
        <Task>2</Task>
        <Opcode>30</Opcode>
        <Keywords>0x4010000001000000</Keywords>
        <TimeCreated SystemTime="2021-02-19T15:16:03.675690900Z" />
        <EventRecordID>3622</EventRecordID>
        <Correlation ActivityID="{e6ee2b3b-9b9a-4c9d-b39b-6c2bf2550000}" />
        <Execution ProcessID="2108" ThreadID="8908" />
        <Channel>Microsoft-Windows-MyApp/Operational</Channel>
        <Computer>computer</Computer>
        <Security UserID="S-1-5-20" />
    </System>
    <UserData>
        <EventInfo xmlns="aag">
            <Username>username</Username>
            <IpAddress>127.0.0.1</IpAddress>
            <AuthType>NTLM</AuthType>
            <Resource />
            <ConnectionProtocol>HTTP</ConnectionProtocol>
            <ErrorCode>23003</ErrorCode>
        </EventInfo>
    </UserData>
</Event>

其他事件用户数据:

<UserData>
    <EventInfo xmlns="aag">
        <Username>otherUserName</Username>
        <IpAddress>10.235.163.52:50427</IpAddress>
    </EventInfo>
</UserData>

EVENTLOGRECORDJNA 在仅包含获取描述字符串值的方法的类中提供事件日志记录。如果我能获得 XML 格式的记录,我的问题就会消失。UserData 中的数据并不总是相同的,它包含不同的值,具体取决于事件类型。我想将 UserData 部分中的数据解析为 POJO(它可以只是一个包含所有可用字段的 POJO)。我不想使用字段顺序,因为某些事件的字段与其他事件不同(如示例所示)。

有没有办法使用 xml 标签名称来做到这一点?我什至会考虑切换到其他语言。

标签: javajnaevent-log

解决方案


As I pointed out in my comment you need to render the event to get to the XML. Matthias Bläsing also pointed out that some sample code is available in the WevtapiTest test class in JNA.

Using that test class, I created the below program which reads the XML from the latest 50 events from the System log. Filtering events to what you want is left as an exercise for the reader.

    public static void main(String[] args) {
        EVT_HANDLE queryHandle = null;
        // Requires elevation or shared access to the log.
        String path = "C:\\Windows\\System32\\Winevt\\Logs\\System.evtx";

        try {
            queryHandle = Wevtapi.INSTANCE.EvtQuery(null, path, null, Winevt.EVT_QUERY_FLAGS.EvtQueryFilePath);

            // Read 10 events at a time
            int eventArraySize = 10;
            int evtNextTimeout = 1000;
            int arrayIndex = 0;
            EVT_HANDLE[] eventArray = new EVT_HANDLE[eventArraySize];
            IntByReference returned = new IntByReference();

            while (Wevtapi.INSTANCE.EvtNext(queryHandle, eventArraySize, eventArray, evtNextTimeout, 0, returned)) {

                Memory buff;
                // This just needs to be 0. Kept same name from test sample
                IntByReference propertyCount = new IntByReference();
                Winevt.EVT_VARIANT evtVariant = new Winevt.EVT_VARIANT();
                for (int i = 0; i < returned.getValue(); i++) {
                    buff = WevtapiUtil.EvtRender(null, eventArray[i], Winevt.EVT_RENDER_FLAGS.EvtRenderEventXml,
                            propertyCount);
                    // Output the XML!
                    System.out.println(buff.getWideString(0));
                }
                arrayIndex++;
                // Quit after 5 x 10 events
                if (arrayIndex >= 5) {
                    break;
                }
            }
            if (Kernel32.INSTANCE.GetLastError() != WinError.ERROR_SUCCESS
                    && Kernel32.INSTANCE.GetLastError() != WinError.ERROR_NO_MORE_ITEMS) {
                throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
            }
        } finally {
            if (queryHandle != null) {
                Wevtapi.INSTANCE.EvtClose(queryHandle);
            }
        }
    }

推荐阅读