Oracle® Fusion Middleware Oracle WebLogic Server ログ ファイルのコンフィグレーションとログ メッセージのフィルタ処理 11g リリース 1 (10.3.1) B55548-01 |
|
![]() 戻る |
WebLogic Server メッセージ カタログおよび NonCatalogLogger
でメッセージが生成されるとき、それらのメッセージは java.util.logging.Logger
オブジェクトに配信されます。Logger
オブジェクトは、メッセージを説明する WLLogRecord
オブジェクトを割り当て、Logger
をサブスクライブしているすべてのメッセージ ハンドラにその WLLogRecord
をパブリッシュします。
以下の節では、メッセージ ハンドラの作成とサブスクライブについて説明します。
WebLogic Server のロガーとハンドラの詳細については、「ロガーとハンドラの役割」を参照してください。
WebLogic Server は、ログ メッセージを受信して出力するメッセージ ハンドラをインスタンス化し、サブスクライブさせます。独自のメッセージ ハンドラを作成して、WebLogic Server の Logger
オブジェクトをサブスクライブするようにもできます (図 5-1 を参照)。
たとえば、アプリケーションがクライアント JVM で動作しており、そのアプリケーションがアプリケーションの生成するメッセージをリスンするようにする場合は、ハンドラを作成し、そのハンドラをクライアント JVM の Logger
オブジェクトにサブスクライブすることができます。アプリケーションが特定サブシステムの障害を知らせるログ メッセージを受信した場合、そのアプリケーションは以下のようなアクションを実行できます。
WebLogic Server の管理者にログ メッセージを電子メールで送信する。
自身またはそのサブシステムを終了または再起動する。
注意 : ユーザ独自のメッセージ ハンドラを作成する場合は、サーバの初期化が完了して実行状態になる前に、WebLogic Server プロセスで実行されるカスタム コードを実行しないように注意します。場合によっては、初期化中のサーバ サービスにカスタム コードが干渉する場合があります。たとえば、IIOP サーバ サービスの初期化の前にPortableRemoteObject を使用する発信 RMI 呼び出しを行うカスタム ログ ハンドラは、サーバの起動が失敗する原因になる場合があります。 |
作成し、Logger
オブジェクトをサブスクライブさせたハンドラでは、その Logger の重大度とフィルタ基準を満たすすべてのメッセージが受信されます。ハンドラでは、Logger がパブリッシュする特定のメッセージだけに応答するように重大度とフィルタ基準を追加で指定することもできます。
ハンドラを作成してサブスクライブさせるには、次の手順に従います。
以下の最小限のインポート文が含まれるハンドラ クラスを作成します。
import java.util.logging.Handler; import java.util.logging.LogRecord; import java.util.logging.ErrorManager; import weblogic.logging.WLLogRecord; import weblogic.logging.WLLevel; import weblogic.logging.WLErrorManager; import weblogic.logging.LoggingHelper;
ハンドラ クラスで、java.util.logging.Handler
を拡張します。
ハンドラ クラスで、Handler.publish(LogRecord record)
メソッドを実装します。
このメソッドは次のように機能します。
受信した LogRecord
オブジェクトを WLLogRecord
オブジェクトとしてキャストします。
ハンドラで設定されているフィルタを適用します。
WLLogRecord
オブジェクトがフィルタの基準を満たしている場合は、WLLogRecord
のメソッドを使用してメッセージからデータを取得します。
必要に応じて、メッセージのデータを 1 つまたは複数のリソースに書き込みます。
ハンドラ クラスで、Handler.flush
メソッドと Handler.close
メソッドを実装します。
リソースと連係して機能するハンドラはすべて、flush
メソッド (バッファされた出力をフラッシュするため) および close
メソッド (開いているリソースを閉じるため) を実装する必要があります。
親 Logger
オブジェクトが閉じると、すべてのハンドラで Handler.close
メソッドが呼び出されます。close メソッドは、flush
メソッドを呼び出してからそれ独自のロジックを実行します。
Handler
オブジェクトが受信するメッセージのタイプを指定するフィルタ クラスを作成します。「ロガーとハンドラのフィルタの設定」を参照してください。
次のいずれかの LoggingHelper
メソッドを呼び出すクラスを作成します。
getClientLogger
(現在のコンテキストがクライアント JVM である場合)。
getServerLogger
(現在のコンテキストがサーバ JVM であり、サーバの Logger
オブジェクトにハンドラをアタッチする必要がある場合)。
getDomainLogger
(現在のコンテキストが管理サーバであり、ドメインの Logger
オブジェクトにハンドラをアタッチする必要がある場合)。
LoggingHelper.getDomainLogger()
は、ドメイン ログを管理する Logger
オブジェクトを取得します。カスタム ハンドラにこのロガーをサブスクライブさせて、単一の場所にある全サーバからのログ メッセージを処理できます。
このクラスで、Logger.addHandler(Handler myHandler)
メソッドを呼び出します。
省略可能。Logger.setFilter(Filter myFilter)
メソッドを呼び出してフィルタを設定します。
この例では、JDBC データ ソースに接続し、メッセージをデータベース テーブルに挿入する SQL 文を発行するハンドラを作成します。この例では、以下のクラスを実装します。
Handler
クラス。「例 : ハンドラ クラスの実装」を参照してください。
Filter
クラス。「ロガーとハンドラのフィルタの設定」を参照してください。
ハンドラとフィルタにサーバの Logger
クラスをサブスクライブさせるクラス。「例 : ロガー クラスのサブスクライブ」を参照してください。
コード リスト 5-1 の Handler
クラスの例では、次のようにしてデータベースにメッセージを書き込みます。
java.util.logging.Handler
を拡張します。
javax.naming.InitialContext
オブジェクトを作成し、Context.lookup
メソッドを呼び出して myPoolDataSource
というデータ ソースをルックアップします。
javax.sql.DataSource.getConnection
メソッドを呼び出して、データ ソースとの接続を確立します。
setErrorManager
メソッドを実装します。このメソッドは、このハンドラの java.util.logging.ErrorManager
オブジェクトを作成します。
このハンドラでエラーが生じると、エラー マネージャの error
メソッドが呼び出されます。この例の error
メソッドは次のように機能します。
エラー メッセージを標準エラーに出力します。
LoggingHelper.getServerLogger().removeHandler(MyJDBCHandler.this)
を呼び出してハンドラを無効にします。
注意 : 独立したクラス ファイルでErrorManager クラスを定義する代わりに、この例では ErrorManager が無名内部クラスとして内包されています。 |
エラー メッセージの詳細については、Sun API のドキュメントの java.util.logging.ErrorManager
の項 (http://java.sun.com/javase/6/docs/api/index.html
) を参照してください。
Handler.publish(LogRecord record)
メソッドを実装します。このメソッドは、次のことを実行します。
受信した各 LogRecord
オブジェクトを WLLogRecord
オブジェクトとしてキャストします。
isLoggable
メソッドを呼び出して、ハンドラに設定されているフィルタを適用します。isLoggable
メソッドは、このハンドラ クラスの最後に定義されています。
WLLogRecord
のメソッドを使用して、メッセージからデータを取得します。
WLLogRecord
メソッドの詳細については、『Oracle Fusion Middleware Oracle WebLogic Server API Reference』の weblogic.logging.WLLogRecord
クラスに関する説明を参照してください。
メッセージのデータを SQL prepareStatement
としてフォーマットし、データベースの更新を実行します。
この例で使用されるテーブルのスキーマは次のとおりです。
表 5-1 サンプル Handler のデータベース テーブルのスキーマ
名前 | Null 可/不可 | 型 |
---|---|---|
MSGID |
なし |
CHAR(25) |
LOGLEVEL |
なし |
CHAR(25) |
SUBSYSTEM |
なし |
CHAR(50) |
MESSAGE |
なし |
CHAR(1024) |
flush
メソッドを呼び出して、接続をフラッシュします。
Handler.close
メソッドを実装して、データ ソースとの接続を閉じます。
親 Logger
オブジェクトが閉じると、Handler.close
メソッドが呼び出されます。このメソッドは、Handler.flush
メソッドを呼び出してからそれ独自のロジックを実行します。
コード リスト 5-1 に、この節で説明した手順を示します。
コード リスト 5-1 例 : ハンドラ クラスの実装
import java.util.logging.Handler; import java.util.logging.LogRecord; import java.util.logging.Filter; import java.util.logging.ErrorManager; import weblogic.logging.WLLogRecord; import weblogic.logging.WLLevel; import weblogic.logging.WLErrorManager; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.sql.PreparedStatement; import weblogic.logging.LoggingHelper; public class MyJDBCHandler extends Handler { private Connection con = null; private PreparedStatement stmt = null; public MyJDBCHandler() throws NamingException, SQLException { InitialContext ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup("myPoolDataSource"); con = ds.getConnection(); PreparedStatement stmt = con.prepareStatement setErrorManager(new ErrorManager() { public void error(String msg, Exception ex, int code) { System.err.println("Error reported by MyJDBCHandler " + msg + ex.getMessage()); //このハンドラのインスタンスをすべて削除 LoggingHelper.getServerLogger().removeHandler( MyJDBCHandler.this); } }); } public void publish(LogRecord record) { WLLogRecord rec = (WLLogRecord)record; if (!isLoggable(rec)) return; try { ("INSERT INTO myserverLog VALUES (?, ?, ? ,?)"); stmt.setEscapeProcessing(true); stmt.setString(1, rec.getId()); stmt.setString(2, rec.getLevel().getLocalizedName()); stmt.setString(3, rec.getLoggerName()); stmt.setString(4, rec.getMessage()); stmt.executeUpdate(); flush(); } catch(SQLException sqex) { reportError("Error publihsing to SQL", sqex, ErrorManager.WRITE_FAILURE); } } public void flush() { try { con.commit(); } catch(SQLException sqex) { reportError("Error flushing connection of MyJDBCHandler", sqex, ErrorManager.FLUSH_FAILURE); } } public boolean isLoggable(LogRecord record) { Filter filter = getFilter(); if (filter != null) { return filter.isLoggable(record); } else { return true; } } public void close() { try { con.close(); } catch(SQLException sqex) { reportError("Error closing connection of MyJDBCHandler", sqex, ErrorManager.CLOSE_FAILURE); } } }
コード リスト 5-2 の Logger
クラスの例では、以下のことを行います。
LoggingHelper.getServerLogger
メソッドを呼び出して、Logger
オブジェクトを取得します。
Logger.addHandler(Handler myHandler)
メソッドを呼び出します。
Logger.getHandlers
メソッドを呼び出して、Logger
オブジェクトのすべてのハンドラを取得します。
myHandler
が見つかるまで配列を検索します。
Handler.setFilter(Filter myFilter)
メソッドを呼び出します。
サーバが起動するたびにハンドラとフィルタがサーバの Logger
オブジェクトをサブスクライブするようにする場合は、このクラスを WebLogic Server 起動クラスとしてデプロイします。起動クラスの詳細については、Oracle Fusion Middleware Oracle WebLogic Server の Administration Console オンライン ヘルプの「カスタム クラスを使用したサーバのコンフィグレーション」を参照してください。
コード リスト 5-2 例 : ロガー クラスのサブスクライブ
import java.util.logging.Logger; import java.util.logging.Handler; import java.util.logging.Filter; import java.util.logging.LogRecord; import weblogic.logging.LoggingHelper; import weblogic.logging.FileStreamHandler; import weblogic.logging.WLLogRecord; import weblogic.logging.WLLevel; import java.rmi.RemoteException; import weblogic.jndi.Environment; import javax.naming.Context; public class LogConfigImpl { public void configureLogger() throws RemoteException { Logger logger = LoggingHelper.getServerLogger(); try { Handler h = null; h = new MyJDBCHandler(); logger.addHandler(h); h.setFilter(new MyFilter()); } catch(Exception nmex) { System.err.println("Error adding MyJDBCHandler to logger " + nmex.getMessage()); logger.removeHandler(h); } } public static void main(String[] argv) throws Exception { LogConfigImpl impl = new LogConfigImpl(); impl.configureLogger(); } }
コード リスト 5-3 の Appender
クラスの例では、JDBC データ ソースに接続し、メッセージをデータベース テーブルに挿入する SQL 文を発行します。
AppenderSkelton
を拡張します。
javax.naming.InitialContext
オブジェクトを作成し、Context.lookup
メソッドを呼び出して MyDataSource
というデータ ソースをルックアップします。
javax.sql.DataSource.getConnection
メソッドを呼び出して、データ ソースとの接続を確立します。
append(LoggingEvent event)
メソッドを実装します。このメソッドは、次のことを実行します。
受信した各 LoggingEvent
オブジェクトを WLLog4jLogEvent
としてキャストします。
WLLog4jLogEvent
のメソッドを使用して、メッセージからデータを取得します。
WLLog4jLogEvent
メソッドの詳細については、『Oracle Fusion Middleware Oracle WebLogic Server API Reference』の weblogic.logging.log4j.WLLog4jLogEvent
クラスに関する説明を参照してください。
SQL prepareStatement
を作成し、ロギング イベントを受け取るたびにデータベースを更新します。
この例で使用されるテーブルのスキーマは次のとおりです。
表 5-2 サンプル Log4j アペンダのデータベース テーブルのスキーマ
名前 | Null 可/不可 | 型 |
---|---|---|
SERVERNAME |
なし |
CHAR(30) |
MSGID |
なし |
CHAR(20) |
SEVERITYLEVEL |
なし |
CHAR(20) |
LOGGERNAME |
なし |
CHAR(100) |
MESSAGE |
なし |
VARCHAR(2048) |
TIMESTAMP |
なし |
LONG |
close
メソッドを実装して、データ ソースとの接続を閉じます。
コード リスト 5-3 に、この節で説明した手順を示します。
コード リスト 5-3 例 : サンプル Log4j アペンダの起動
package weblogic.logging.examples; import java.util.Enumeration; import org.apache.log4j.AppenderSkeleton; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.Logger; import org.apache.log4j.spi.Filter; import org.apache.log4j.spi.LoggingEvent; import weblogic.logging.LoggerNotAvailableException; import weblogic.logging.NonCatalogLogger; import weblogic.logging.Severities; import weblogic.logging.log4j.AppenderNames; import weblogic.logging.log4j.Log4jLoggingHelper; import weblogic.logging.log4j.WLLog4jLevel; import weblogic.logging.log4j.WLLog4jLogEvent; import org.apache.log4j.jdbc.JDBCAppender; import java.sql.Connection; import java.sql.SQLException; import javax.naming.InitialContext; import weblogic.logging.log4j.WLLog4jLogEvent; import weblogic.logging.Severities; /** * このクラスにより、JDBC アペンダがログ イベントに対するサーバ ロガーの * リスナとしてコンフィグレーションされる */ public class Log4jAppenderExampleStartup { public static void main(String[] args) { try { System.out.println("Invoked the appender example startup class"); Logger serverLogger = Log4jLoggingHelper.getLog4jServerLogger(); // JDBC アペンダをコンフィグレーションする MyJDBCAppender jdbcAppender = new MyJDBCAppender(); // ここで JDBC アペンダをサーバ ロガーに追加する serverLogger.addAppender(jdbcAppender); // ここでフィルタをテストする NonCatalogLogger nc = new NonCatalogLogger("MyAppenderTest"); nc.info("Test INFO message"); nc.warning("Test WARNING message"); } catch(Exception ex) { System.err.println("Init failure " + ex.getMessage()); ex.printStackTrace(); } } private static class MyJDBCAppender extends AppenderSkeleton { private Connection connection; private java.sql.PreparedStatement stmt; public MyJDBCAppender() throws javax.naming.NamingException, SQLException { InitialContext ctx = new InitialContext(); javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup ("MyDataSource"); connection = ds.getConnection(); // テーブル スキーマ作成 SQL コマンド // Create table SERVER_LOG (server_name char(30),msg_id char(20), // severity_level char(20),logger_name char(100),message varchar(2048), // timestamp long); stmt = connection.prepareStatement("INSERT INTO SERVER_LOG VALUES (?, ?, ?, ?, ?, ?)"); stmt.setEscapeProcessing(true); connection.setAutoCommit(true); } // 実行メソッドをオーバーライドする public void append(LoggingEvent event) { WLLog4jLogEvent wlsEvent = (WLLog4jLogEvent) event; try { stmt.setString(1, wlsEvent.getServerName()); stmt.setString(2, wlsEvent.getId()); stmt.setString(3, Severities.severityNumToString(wlsEvent.getSeverity())); stmt.setString(4, wlsEvent.getSubsystem()); stmt.setString(5, wlsEvent.getMessage().toString()); stmt.setLong(6, wlsEvent.getTimestamp()); stmt.executeUpdate(); } catch (SQLException e) { System.err.println(e.toString()); } } public boolean requiresLayout() { return false; } public void close() { try { stmt.close(); connection.close(); } catch(SQLException sqlex) { System.err.println("Error closing JDBC appender"); sqlex.printStackTrace(); } } } }
WebLogic Server 8.1 より前のリリースで、WebLogic ロギング サービスからメッセージを受信するには、Java Management Extensions (JMX) リスナを作成して、それを LogBroadcasterRuntimeMBean
に登録する方法しかありませんでした。WebLogic Server 8.1 では、Java ロギング ハンドラを使用してログ メッセージを受信 (サブスクライブ) することもできます。
Java ロギング ハンドラでも JMX リスナでも同様の結果が得られますが、Java ロギング API には Formatter
クラスがあり、Handler
オブジェクトはこのクラスを使用して受信したメッセージをフォーマットできます。JMX では、メッセージをフォーマットするこのような API は提供されません。フォーマッタの詳細については、Sun API のドキュメントの Formatter
の項 (http://java.sun.com/javase/6/docs/api/java/util/logging/Formatter.html
) を参照してください。
さらに、Java ロギング Handler
API は JMX API よりも使いやすく、過程が直接的です。たとえば、次のコードは Java ロギング Logger
オブジェクトを取得し、ハンドラにそのオブジェクトをサブスクライブさせます。
Logger logger = LoggingHelper.getServerLogger(); Handler h = null; h = new MyJDBCHandler(); logger.addHandler(h)
JMX リスナを登録して同様の結果を得るには、コード リスト 5-4 のようなコードを使用する必要があります。コードで MBeanHome
インタフェース、RemoteMBeanServer
インタフェース、および LogBroadcasterRuntimeMBean
をルックアップし、それからリスナを登録します。
ローカル マシンのログ メッセージのサブスクライブには Java ロギング ハンドラ、リモート マシンからのログ メッセージの受信には JMX リスナが適しています。すでにモニタに JMX を使用しており、ログ メッセージのフォーマットを変更したりログ メッセージを別の出力に転送したりせずに単純にリスンする場合は、JMX リスナを使用します。それ以外の場合は、Java ロギング ハンドラを使用します。
コード リスト 5-4 JMX リスナの登録
MBeanHome home = null; RemoteMBeanServer rmbs = null; //ドメイン変数 String url = "t3://localhost:7001"; String serverName = "Server1"; String username = "weblogic"; String password = "weblogic"; //MBeanHome を使用して MBeanServer を取得try { Environment env = new Environment(); env.setProviderUrl(url); env.setSecurityPrincipal(username); env.setSecurityCredentials(password); Context ctx = env.getInitialContext(); //管理 MBeanHome インタフェースを取得 home = (MBeanHome) ctx.lookup(MBeanHome.ADMIN_JNDI_NAME); System.out.println("Got the Admin MBeanHome: " + home ); rmbs = home.getMBeanServer(); } catch (Exception e) { System.out.println("Caught exception: " + e); } try { //リスナ クラスをインスタンス化MyListener listener = new MyListener(); MyFilter filter = new MyFilter(); //サーバのログ ブロードキャスタの WebLogicObjectName を //作成 WebLogicObjectName logBCOname = new WebLogicObjectName("TheLogBroadcaster", "LogBroadcasterRuntime", domainName, serverName); //MBean の名前とリスナ クラスを MBeanServer の //addNotificationListener メソッドに渡す rmbs.addNotificationListener(logBCOname, listener, filter, null); } catch(Exception e) { System.out.println("Exception: " + e); } }