2008-11-21 55 views
13

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

的情况是:

我在远程机器上运行的过程,从控制Java进程。 这个远程进程记录东西到事件日志,我想在控制过程中看到。

在此先感谢。

回答

9

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

在Windows端,功能你就是OpenEventLog后。这应该允许您访问远程事件日志。另见Querying for Event Information

如果没有健全的权利,我也发现了这个直接解析日志文件(没有办法,我建议,但有趣的仍然):

1

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

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

后来!

17

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

Microsoft通过Windows Management Instrumentation(WMI)公开了大量的系统信息。 WMI可以通过DCOM远程访问,并且微软网站上还有相关的主题文档。碰巧,您可以通过这个可远程访问的界面访问Windows Event Logs

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

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

以下示例使用其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(); 
       } 
      } 
     } 
    } 

} 

6

阅读this article

JNA 3.2.8具有从Windows事件日志读取和写入的两种方法。

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

这里读的例子:

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