Как получить доступ к данным журнала Windows Event Viewer из Java
Есть ли способ получить доступ к журналу событий Windows из Java-класса. Кто-нибудь написал какие-либо API для этого, и есть ли способ получить доступ к данным с удаленного компьютера?
Сценарий таков:
Я запускаю процесс на удаленной машине из контролирующего процесса Java. Этот удаленный процесс записывает данные в журнал событий, который я хочу видеть в процессе управления.
Заранее спасибо.
5 ответов
На стороне Java вам понадобится библиотека, которая позволяет вам делать собственные вызовы. Sun предлагает JNI, но это звучит как боль. Также учтите:
На стороне Windows, функция, которую вы ищете, - OpenEventLog. Это должно позволить вам получить доступ к удаленному журналу событий. Смотрите также Запрос информации о событии.
Если это не звучит правильно, я также нашел это для непосредственного разбора файлов журнала (я бы не рекомендовал такой подход, но тем не менее был бы интересен):
http://www.j-interop.org/ - это библиотека Java с открытым исходным кодом, которая реализует спецификацию протокола DCOM без использования какого-либо собственного кода. (т.е. вы можете использовать его для доступа к объектам DCOM на удаленном хосте Windows из кода Java, запущенного на клиенте, отличном от Windows).
Microsoft предоставляет множество системной информации через инструментарий управления Windows (WMI). WMI доступен удаленно через DCOM, и на сайте Microsoft имеется немало документации по этому вопросу. Как это происходит, вы можете получить доступ к журналам событий Windows через этот удаленно доступный интерфейс.
С помощью j-interop можно удаленно создать экземпляр объекта WMI WbemScripting.SWbemLocator, а затем подключиться к службам инструментария управления Windows (WMI) на удаленном хосте Windows. Оттуда вы можете отправить запрос, который будет информировать вас о каждой новой записи в журнале событий.
Обратите внимание, что для этого необходимо, чтобы DCOM был правильно включен и настроен на удаленном хосте Windows, и чтобы в любых брандмауэрах были установлены соответствующие исключения. Подробности об этом можно найти в Интернете, а также ссылки на сайте j-interop выше.
В следующем примере подключается к удаленному хосту, используя его домен NT, имя хоста, имя пользователя и пароль, и зацикливается на каждой записи журнала событий, когда они регистрируются окнами. Пользователю должны быть предоставлены соответствующие разрешения на удаленный доступ к 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();
}
}
}
}
}
~
Прочтите эту статью.
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());
}
Если вы хотите получить истинный доступ к журналу событий с удаленной машины, вам нужно будет найти библиотеку, которая реализует спецификацию протокола удаленного взаимодействия EventLog. К сожалению, я еще не нашел такой библиотеки в Java. Тем не менее, большая часть основы для реализации этого протокола уже была заложена проектами JCIFS и JARAPAC. Сам протокол (если я не ошибаюсь) работает поверх протокола DCE/RPC (реализованного JARAPAC), который сам работает поверх протокола SMB (реализованного JCIFS).
Я уже использовал JCIFS и JARAPAC для реализации некоторых протоколов двоюродного брата EventLog, таких как удаленный доступ к реестру. Я могу быть слепым, но документация казалась немного скудной в отношении JARAPAC. Если вы заинтересованы в реализации этого, я могу поделиться с вами тем, что я узнал, когда у меня будет свободное время!
Потом!
Здесь миллион (и один) вариантов;)
ты можешь посмотреть на сигару
возражаю против лицензирования, хотя....
или вы можете быть быстрыми и грязными и просто периодически выполнять (и перехватывать вывод) D:>cscript.exe c:\WINDOWS\system32\eventquery.vbs /v
затем используйте параметры фильтрации событий для уточнения результатов и т. д... http://technet.microsoft.com/en-us/library/cc772995(WS.10).aspx