如何从 Java 访问 Windows 事件查看器日志数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/310355/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 13:00:29  来源:igfitidea点击:

How do I access Windows Event Viewer log data from Java

javawindowslogging

提问by Matthew Farwell

Is there any way to access the Windows Event Log from a java class. Has anyone written any APIs for this, and would there be any way to access the data from a remote machine?

有什么方法可以从 java 类访问 Windows 事件日志。有没有人为此编写过任何 API,有没有办法从远程机器访问数据?

The scenario is:

场景是:

I run a process on a remote machine, from a controlling Java process. This remote process logs stuff to the Event Log, which I want to be able to see in the controlling process.

我在远程机器上从控制 Java 进程运行一个进程。这个远程进程将内容记录到事件日志中,我希望能够在控制进程中看到它。

Thanks in advance.

提前致谢。

采纳答案by Corbin March

On the Java side, you'll need a library that allows you to make native calls. Sun offers JNI, but it sounds like sort of a pain. Also consider:

在 Java 方面,您需要一个允许您进行本机调用的库。Sun 提供JNI,但这听起来有点痛苦。还要考虑:

On the Windows side, the function you're after is OpenEventLog. This should allow you to access a remote event log. See also Querying for Event Information.

在 Windows 方面,您所追求的功能是OpenEventLog。这应该允许您访问远程事件日志。另请参阅查询事件信息

If that doesn't sound right, I also found this for parsing the log files directly (not an approach I'd recommend but interesting nonetheless):

如果这听起来不对,我还发现它可以直接解析日志文件(不是我推荐的方法,但仍然很有趣):

回答by Adam Paynter

If you want true event log access from a remote machine, you will have to find a library which implements the EventLog Remoting Protocol Specification. Unfortunately, I have not yet found any such library in Java. However, much of the foundation for implementing this protocol has already been laid by the JCIFS and JARAPAC projects. The protocol itself (if I'm not mistaken) runs on top of the DCE/RPC protocol (implemented by JARAPAC) which itself runs on top of the SMB protocol (implemented by JCIFS).

如果您想从远程机器访问真正的事件日志,则必须找到一个实现EventLog Remoting Protocol Specification的库。不幸的是,我还没有在 Java 中找到任何这样的库。但是,JCIFS 和 JARAPAC 项目已经奠定了实施该协议的大部分基础。协议本身(如果我没记错的话)运行在 DCE/RPC 协议(由 JARAPAC 实现)之上,而后者本身运行在 SMB 协议(由 JCIFS 实现)之上。

I have already been using JCIFS and JARAPAC to implement some of EventLog's cousin protocols, such as remote registry access. I may be blind, but documentation seemed a little scarce regarding JARAPAC. If you are interested in implementing this, I can share with you what I have learned when I get some spare time!

我已经在使用 JCIFS 和 JARAPAC 来实现一些 EventLog 的表亲协议,例如远程注册表访问。我可能是盲人,但关于 JARAPAC 的文档似乎有点稀缺。如果你有兴趣实现这个,我可以在空闲时间与你分享我学到的东西!

Later!

之后!

回答by Dan Fleet

http://www.j-interop.org/is an open-source Java library that implements the DCOM protocol specification without using any native code. (i.e. you can use it to access DCOM objects on a remote Windows host from Java code running on a non-Windows client).

http://www.j-interop.org/是一个开源 Java 库,它在不使用任何本机代码的情况下实现了 DCOM 协议规范。(即,您可以使用它从运行在非 Windows 客户端上的 Java 代码访问远程 Windows 主机上的 DCOM 对象)。

Microsoft exposes a plethora of system information via Windows Management Instrumentation(WMI). WMI is remotely accessible via DCOM, and considerable documentation on the subject exists on Microsoft's site. As it happens, you can access the Windows Event Logsvia this remotely accessible interface.

Microsoft 通过Windows Management Instrumentation(WMI)公开了大量系统信息。WMI 可通过 DCOM 远程访问,Microsoft 站点上有大量关于该主题的文档。碰巧的是,您可以通过这个远程访问界面访问Windows 事件日志

By using j-interop you can create an instance of the WbemScripting.SWbemLocatorWMI object remotely, then connect to Windows Management Instrumentation (WMI) services on the remote Windows host. From there you can submit a querythat will inform you whenever a new event log entry is written.

通过使用 j-interop,您可以远程创建WbemScripting.SWbemLocatorWMI 对象的实例,然后连接到远程 Windows 主机上的 Windows Management Instrumentation (WMI) 服务。从那里您可以提交一个查询,该查询将在写入新事件日志条目时通知您。

Note that this does require that you have DCOM properly enabled and configured on the remote Windows host, and that appropriate exceptions have been set up in any firewalls. Details on this can be searched online, and are also referenced from the j-interop site, above.

请注意,这确实需要您在远程 Windows 主机上正确启用和配置 DCOM,并且在任何防火墙中都设置了适当的例外。这方面的详细信息可以在线搜索,也可以从上面的 j-interop 站点进行引用。

The following example connects to a remote host using its NT domain, hostname, a username and a password, and sits in a loop, dumping every event log entry as they are logged by windows. The user must have been granted appropriate remote DCOM access permissions, but does not have to be an administrator.

以下示例使用其 NT 域、主机名、用户名和密码连接到远程主机,并处于循环中,转储 Windows 记录的每个事件日志条目。用户必须已被授予适当的远程 DCOM 访问权限,但不必是管理员。

import java.io.IOException;
import java.util.logging.Level;

import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.common.JISystem;
import org.jinterop.dcom.core.JIComServer;
import org.jinterop.dcom.core.JIProgId;
import org.jinterop.dcom.core.JISession;
import org.jinterop.dcom.core.JIString;
import org.jinterop.dcom.core.JIVariant;
import org.jinterop.dcom.impls.JIObjectFactory;
import org.jinterop.dcom.impls.automation.IJIDispatch;

public class EventLogListener
{

    private static final String WMI_DEFAULT_NAMESPACE = "ROOT\CIMV2";


    private static JISession configAndConnectDCom( String domain, String user, String pass ) throws Exception
    {
        JISystem.getLogger().setLevel( Level.OFF );

        try
        {
            JISystem.setInBuiltLogHandler( false );
        }
        catch ( IOException ignored )
        {
            ;
        }

        JISystem.setAutoRegisteration( true );

        JISession dcomSession = JISession.createSession( domain, user, pass );
        dcomSession.useSessionSecurity( true );
        return dcomSession;
    }


    private static IJIDispatch getWmiLocator( String host, JISession dcomSession ) throws Exception
    {
        JIComServer wbemLocatorComObj = new JIComServer( JIProgId.valueOf( "WbemScripting.SWbemLocator" ), host, dcomSession );
        return (IJIDispatch) JIObjectFactory.narrowObject( wbemLocatorComObj.createInstance().queryInterface( IJIDispatch.IID ) );
    }


    private static IJIDispatch toIDispatch( JIVariant comObjectAsVariant ) throws JIException
    {
        return (IJIDispatch) JIObjectFactory.narrowObject( comObjectAsVariant.getObjectAsComObject() );
    }


    public static void main( String[] args )
    {

        if ( args.length != 4 )
        {
            System.out.println( "Usage: " + EventLogListener.class.getSimpleName() + " domain host username password" );
            return;
        }

        String domain = args[ 0 ];
        String host = args[ 1 ];
        String user = args[ 2 ];
        String pass = args[ 3 ];

        JISession dcomSession = null;

        try
        {
            // Connect to DCOM on the remote system, and create an instance of the WbemScripting.SWbemLocator object to talk to WMI.
            dcomSession = configAndConnectDCom( domain, user, pass );
            IJIDispatch wbemLocator = getWmiLocator( host, dcomSession );

            // Invoke the "ConnectServer" method on the SWbemLocator object via it's IDispatch COM pointer. We will connect to
            // the default ROOT\CIMV2 namespace. This will result in us having a reference to a "SWbemServices" object.
            JIVariant results[] =
                    wbemLocator.callMethodA( "ConnectServer", new Object[] { new JIString( host ), new JIString( WMI_DEFAULT_NAMESPACE ),
                            JIVariant.OPTIONAL_PARAM(), JIVariant.OPTIONAL_PARAM(), JIVariant.OPTIONAL_PARAM(), JIVariant.OPTIONAL_PARAM(), new Integer( 0 ),
                            JIVariant.OPTIONAL_PARAM() } );

            IJIDispatch wbemServices = toIDispatch( results[ 0 ] );

            // Now that we have a SWbemServices DCOM object reference, we prepare a WMI Query Language (WQL) request to be informed whenever a
            // new instance of the "Win32_NTLogEvent" WMI class is created on the remote host. This is submitted to the remote host via the
            // "ExecNotificationQuery" method on SWbemServices. This gives us all events as they come in. Refer to WQL documentation to
            // learn how to restrict the query if you want a narrower focus.
            final String QUERY_FOR_ALL_LOG_EVENTS = "SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA 'Win32_NTLogEvent'";
            final int RETURN_IMMEDIATE = 16;
            final int FORWARD_ONLY = 32;

            JIVariant[] eventSourceSet =
                    wbemServices.callMethodA( "ExecNotificationQuery", new Object[] { new JIString( QUERY_FOR_ALL_LOG_EVENTS ), new JIString( "WQL" ),
                            new JIVariant( new Integer( RETURN_IMMEDIATE + FORWARD_ONLY ) ) } );
            IJIDispatch wbemEventSource = (IJIDispatch) JIObjectFactory.narrowObject( ( eventSourceSet[ 0 ] ).getObjectAsComObject() );

            // The result of the query is a SWbemEventSource object. This object exposes a method that we can call in a loop to retrieve the
            // next Windows Event Log entry whenever it is created. This "NextEvent" operation will block until we are given an event.
            // Note that you can specify timeouts, see the Microsoft documentation for more details.
            while ( true )
            {
                // this blocks until an event log entry appears.
                JIVariant eventAsVariant = (JIVariant) ( wbemEventSource.callMethodA( "NextEvent", new Object[] { JIVariant.OPTIONAL_PARAM() } ) )[ 0 ];
                IJIDispatch wbemEvent = toIDispatch( eventAsVariant );

                // WMI gives us events as SWbemObject instances (a base class of any WMI object). We know in our case we asked for a specific object
                // type, so we will go ahead and invoke methods supported by that Win32_NTLogEvent class via the wbemEvent IDispatch pointer.
                // In this case, we simply call the "GetObjectText_" method that returns us the entire object as a CIM formatted string. We could,
                // however, ask the object for its property values via wbemEvent.get("PropertyName"). See the j-interop documentation and examples
                // for how to query COM properties.
                JIVariant objTextAsVariant = (JIVariant) ( wbemEvent.callMethodA( "GetObjectText_", new Object[] { new Integer( 1 ) } ) )[ 0 ];
                String asText = objTextAsVariant.getObjectAsString().getString();
                System.out.println( asText );
            }
        }
        catch ( Exception e )
        {
            e.printStackTrace();
        }
        finally
        {
            if ( null != dcomSession )
            {
                try
                {
                    JISession.destroySession( dcomSession );
                }
                catch ( Exception ex )
                {
                    ex.printStackTrace();
                }
            }
        }
    }

}

~

~

回答by JzJ

there are a million (and one) options here ;)

这里有一百万(和一个)选项;)

you could look at sigar

你可以看看 sigar

http://cpansearch.perl.org/src/DOUGM/hyperic-sigar-1.6.3-src/docs/javadoc/org/hyperic/sigar/win32/EventLog.html

http://cpansearch.perl.org/src/DOUGM/hyperic-sigar-1.6.3-src/docs/javadoc/org/hyperic/sigar/win32/EventLog.html

mind the licensing though....

不过请注意许可....

or you could be quick and dirty and just periodically execute (and capture the output) D:>cscript.exe c:\WINDOWS\system32\eventquery.vbs /v

或者你可以快速而肮脏,只是定期执行(并捕获输出) D:>cscript.exe c:\WINDOWS\system32\eventquery.vbs /v

then use event filtering params to refine the results etc... http://technet.microsoft.com/en-us/library/cc772995(WS.10).aspx

然后使用事件过滤参数来优化结果等... http://technet.microsoft.com/en-us/library/cc772995(WS.10).aspx

回答by dB.

Read this article.

阅读这篇文章

JNA 3.2.8 has both methods to read and write from the Windows event log.

JNA 3.2.8 有两种方法可以从 Windows 事件日志中读取和写入。

You can see an example of write in log4jna.

您可以在log4jna 中看到写入示例

Here's an example of read:

下面是一个阅读的例子:

EventLogIterator iter = new EventLogIterator("Application");         
while(iter.hasNext()) { 
    EventLogRecord record = iter.next(); 
    System.out.println(record.getRecordNumber() 
            + ": Event ID: " + record.getEventId() 
            + ", Event Type: " + record.getType() 
            + ", Event Source: " + record.getSource()); 
}