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

时间:2021-11-20 22:03:31

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.

提前谢谢。

5 个解决方案

#1


9  

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):

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

#2


17  

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主机上从运行在非Windows客户机上运行的Java代码访问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 Logs via this remotely accessible interface.

微软通过Windows管理工具(WMI)公开了过多的系统信息。通过DCOM可以远程访问WMI,并且在微软的站点上有大量关于这个主题的文档。碰巧,您可以通过这个远程访问接口访问Windows事件日志。

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

通过使用j-interop,您可以创建WbemScripting的一个实例。SWbemLocator WMI对象远程,然后连接到远程Windows主机上的Windows管理工具(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();
                }
            }
        }
    }

}

~

~

#3


6  

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()); 
} 

#4


1  

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协议规范的库。不幸的是,我还没有在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!

后来!

#5


1  

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。根据/ 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

#1


9  

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):

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

#2


17  

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主机上从运行在非Windows客户机上运行的Java代码访问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 Logs via this remotely accessible interface.

微软通过Windows管理工具(WMI)公开了过多的系统信息。通过DCOM可以远程访问WMI,并且在微软的站点上有大量关于这个主题的文档。碰巧,您可以通过这个远程访问接口访问Windows事件日志。

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

通过使用j-interop,您可以创建WbemScripting的一个实例。SWbemLocator WMI对象远程,然后连接到远程Windows主机上的Windows管理工具(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();
                }
            }
        }
    }

}

~

~

#3


6  

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()); 
} 

#4


1  

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协议规范的库。不幸的是,我还没有在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!

后来!

#5


1  

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。根据/ 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