Kohei Nozaki's blog 

Entries tagged [wildfly]

Logging with log4j appenders


Posted on Thursday Feb 13, 2014 at 10:59AM in Technology


  • We can use WildFly's logging mechanism with log4j appenders.

Environment

  • WildFly 8.0.0.Final
  • Oracle JDK7u51
  • OS X 10.9.2

Precondition

  • Ensure we already have a logger named “hoge.logger1”.
  • I will use this servlet to logging test.
package logger;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/")
public class LogServlet extends HttpServlet {
    private static final org.slf4j.Logger SLF4J_LOGGER1 = org.slf4j.LoggerFactory.getLogger("hoge.logger1");

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        StringBuilder sb = new StringBuilder(1200);
        for(int i=0; i<1200; i++){
            sb.append(i%10);
        }

        SLF4J_LOGGER1.info("0-1199: {}", sb);
        SLF4J_LOGGER1.info("exception logging test", new AssertionError("test"));
    }
}
  • Log4j is shipped with out-of-box WildFly8 so we don't need any preparation about log4j.

Defining with org.apache.log4j.FileAppender

Create an custom-handler named “LOG4J_FILE”

/subsystem=logging/custom-handler=LOG4J_FILE:add( \
 class="org.apache.log4j.FileAppender", \
 module="org.apache.log4j", \
 named-formatter=PATTERN, \
 level=INFO, \
 properties={ \
  File="/tmp/log4jtest.log", \
  Append=true})

Assign the handler to a logger

/subsystem=logging/logger=hoge.logger1:assign-handler(name=LOG4J_FILE)

Output

2014-03-07 14:57:46,538 INFO  [hoge.logger1] (default task-10) 0-1199: 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
2014-03-07 14:57:46,538 INFO  [hoge.logger1] (default task-10) exception logging test: java.lang.AssertionError: test
        at logger.LogServlet.doGet(LogServlet.java:22) [classes:]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:687) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar:1.0.0.Final]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:113) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java:52) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.server.Connectors.executeRootHandler(Connectors.java:168) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:687) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_51]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_51]
        at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_51]

Defining with org.apache.log4j.net.SyslogAppender

Create an custom-handler named “LOG4J_SYSLOG”

/subsystem=logging/custom-handler=LOG4J_SYSLOG:add( \
 class="org.apache.log4j.net.SyslogAppender", \
 module="org.apache.log4j", \
 formatter="%-5p [%c] (%t) %s%E%n", \
 level=INFO, \
 properties={ \
  Header=true, \
  syslogHost="localhost:514", \
  facility="local1", \
  facilityPrinting=false})

Assign the handler to a logger

/subsystem=logging/logger=hoge.logger1:assign-handler(name=LOG4J_SYSLOG)

Output

Mar  7 15:02:33 kyle-no-MacBook.local INFO  [hoge.logger1] (default task-1) 0-119]: 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456...
Mar  7 15:02:33 kyle-no-MacBook.local Unknown: ...78901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
Mar  7 15:02:33 kyle-no-MacBook.local INFO  [hoge.logger1] (default task-1) exception logging tes]: java.lang.AssertionError: test
                at logger.LogServlet.doGet(LogServlet.java:22) [classes:]
                at javax.servlet.http.HttpServlet.service(HttpServlet.java:687) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar:1.0.0.Final]
                at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
Mar  7 15:02:33 kyle-no-MacBook.local ...est(SecurityContextAssociationHandler.java: 78)
                at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:113) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java:52) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
Mar  7 15:02:33 kyle-no-MacBook.local ...Handler.handleRequest(CachedAuthenticatedSessionHandler.java: 70) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
                at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
                at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
Mar  7 15:02:33 kyle-no-MacBook.local ...ertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java: 227) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.server.Connectors.executeRootHandler(Connectors.java:168) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
                at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:687) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_51]
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_51]
                at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_51]

Conclusion

  • Anyway, we can use log4j appenders with custom-handler surely.
  • But something goes wrong with exception logging with SyslogAppender.
    • Some parts of stacktraces were lost.
    • The last digit of message strings are replaced by ']'.

References

  1. [AS7-4925] Log4j appenders should also be allowed for custom handlers - JBoss Issue Tracker
  2. Log4jAppenderHandler usage | Community
  3. #8059525 - Pastie
  4. Use Log4j appender as custom-handler in AS 7.1…. | Community
  5. Magnus K Karlsson: How to setup log4j Syslog Appender in JBoss EAP 6
  6. Programming fun at startup: log4j TCP SyslogAppender


別プロセスからリモートEJBを呼び出してみる


Posted on Sunday Feb 09, 2014 at 03:18PM in Technology


WildFly8にデプロイしてあるEJB(WARファイル内に存在)を、別のJavaプロセスからリモート呼び出ししてみる

環境

  • Eclipse Kepler SR1
  • WildFly8.0.0.CR1
  • Oracle JDK7u51

前提条件

WildFly8.0.0CR1でサーブレットを動かしてみる あたりでEclipseに加えた設定が終わっているものとする

準備

プロジェクトを作る

以下の3つを作ります

  1. リモートEJBインタフェースを含むプロジェクト(remoteejbif)
  2. リモートEJBの実装を含むプロジェクト(remoteejbwar)
  3. クライアント側プロジェクト(remoteejbclient)

リモートEJBインタフェースを含むプロジェクト(remoteejbif)

  1. 「remoteejbif」という名称のJavaプロジェクトを作る
  2. ソースを追加
package foo;


public interface HogeBean {

    String hoge();
}

リモートEJBの実装を含むプロジェクト(remoteejbwar)

  1. 「remoteejbwar」という名称のMavenプロジェクトをarchetype「javaee7-essentials」から作る
  2. プロジェクトの設定を開く
  3. Project Referencesでremoteejbifにチェックを入れる
  4. Java Build PathのProjectsタブでAddを押してremoteejbifを追加する
  5. Deployment Assembly→Add→Projectでremoteejbifを追加する。追加した後、再度設定内容を確認すると、追加されていなかったりするので注意(もう一度追加するとOKっぽい。なんだこれ)
  6. ソースを追加
  7. ソースを追加したらJava EE Perspective→Servers→WildFly→右クリック→Add and Removeからデプロイ
package foo;

import javax.ejb.Remote;
import javax.ejb.Stateless;

@Stateless
@Remote(HogeBean.class)
public class HogeBeanImpl implements HogeBean{

    @Override
    public String hoge() {
        return "hoge from remote";
    }
}

クライアント側プロジェクト(remoteejbclient)

  1. 「remoteejbclient」という名称のJavaプロジェクトを作る
  2. プロジェクトの設定を開く
  3. Project Referencesでremoteejbifにチェックを入れる
  4. Java Build PathのProjectsタブでAddを押してremoteejbifを追加する
  5. Java Build PathのLibrariesタブでAdd External Jarsを押して$WILDFLY_HOME/bin/client/jboss-client.jarを追加する
  6. ソースを追加
package foo;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;

public class HogeBeanInvoker2 {

    public static void main(String[] args) throws Exception {
        Properties p = new Properties();
        p.put("remote.connections", "default");
        p.put("remote.connection.default.port", "8080");
        p.put("remote.connection.default.host", "localhost");
        p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", false);
        p.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
        p.put("org.jboss.ejb.client.scoped.context", true);

        Context c = null;
        try {
            c = new InitialContext(p);
            HogeBean hogeBean = (HogeBean) c.lookup("ejb:/remoteejbwar//HogeBeanImpl!foo.HogeBean");
            System.out.println(hogeBean.hoge());
        } finally {
            c.close();
        }
    }
}

実行

「remoteejbclient」プロジェクトに作ったHogeBeanInvoker2を普通に実行する(右クリック→Run As→Java Application)。こんな感じの出力が出る。わりと速い

2 10, 2014 5:24:54 午後 org.xnio.Xnio <clinit>
INFO: XNIO version 3.2.0.Beta4
2 10, 2014 5:24:54 午後 org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.2.0.Beta4
2 10, 2014 5:24:54 午後 org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version (unknown)
2 10, 2014 5:24:54 午後 org.jboss.ejb.client.remoting.VersionReceiver handleMessage
INFO: EJBCLIENT000017: Received server version 2 and marshalling strategies [river]
2 10, 2014 5:24:54 午後 org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate
INFO: EJBCLIENT000013: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@1f1ee981, receiver=Remoting connection EJB receiver [connection=org.jboss.ejb.client.remoting.ConnectionPool$PooledConnection@2674241d,channel=jboss.ejb,nodename=kyle-no-macbook]} on channel Channel ID bb6edca7 (outbound) of Remoting connection 3aa7fab1 to localhost/127.0.0.1:8080
2 10, 2014 5:24:54 午後 org.jboss.ejb.client.EJBClient <clinit>
INFO: JBoss EJB Client version 2.0.0.Beta5
hoge from remote

備考

デプロイ時に出力されるJNDI名は別プロセスからのリモート呼び出しには使えない

EJBをデプロイするとWildFlyの出力に以下のようなJNDI名が出力されるが、別プロセスからのリモート呼び出しでは使えなかった。別プロセスからlookupする場合は「ejb:」で始まるJNDI名を使わないといけないっぽい。詳細は参考文献を参照。

java:global/remoteejbwar/HogeBeanImpl!foo.HogeBean
java:app/remoteejbwar/HogeBeanImpl!foo.HogeBean
java:module/HogeBeanImpl!foo.HogeBean
java:jboss/exported/remoteejbwar/HogeBeanImpl!foo.HogeBean
java:global/remoteejbwar/HogeBeanImpl
java:app/remoteejbwar/HogeBeanImpl
java:module/HogeBeanImpl

同じAPサーバにデプロイされたアプリケーション間なら「java:global」で始まるJNDI名でlookup可能。

ユーザの作成は不要

参考文献を見るとユーザの作成が必要な旨の記述が多く見つかるが、どうやらこの環境では特に必要ない模様

standalone.xmlでOK

参考文献を見ると設定ファイルstandalone-full.xmlで起動している例が見つかるが、この記事のような単純なものの場合は特に必要ない模様。JMSとか使う場合に必要になるのかも

その他

レガシーでもはやなるべく使うべきではないと言われることもあるリモートEJB呼び出しだが、局面によっては依然使えると思われる

参考文献

  1. Tanmoy's Blog: WildFly: EJB invocations from a remote client
  2. java - WildFly: EJB invocations from a remote client - Stack Overflow
  3. EJB invocations from a remote client using JNDI - WildFly 8 - Project Documentation Editor
  4. JNDI Lookup Failing | Community
  5. Remote EJB invocations via JNDI - EJB client API or remote-naming project - WildFly 8 - Project Documentation Editor
  6. Java Web: Accessing remote EJB on JBoss AS 7.1 from web application
  7. JBoss EAP 6.2のリモートEJB呼び出し - nekopの日記


@ResourceアノテーションでDataSourceを注入してみる


Posted on Sunday Feb 02, 2014 at 05:23PM in Technology


直接JDBCを使う必要がでてきた時用。

環境

  • WildFly8.0.0.CR1
  • Oracle JDK7u51
  • PostgreSQL 9.2.4

準備

データソースを確認

こんなデータソースを使ってみることにする

[standalone@localhost:9990 /] /subsystem=datasources/data-source=TestDS:read-attribute(name=jndi-name)
{
    "outcome" => "success",
    "result" => "java:jboss/jdbc/TestDS"
}
[standalone@localhost:9990 /] 

HogeServlet.java

このサーブレットにDataSourceを注入します。try-with-resourcesが便利ですね。@Resourceアノテーションのlookup属性には、“java:comp/env/“の後にXMLファイルで定義した論理名を書く

package com.example;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

@WebServlet("/HogeServlet")
public class HogeServlet extends HttpServlet {

    @Resource(lookup = "java:comp/env/jdbc/hoge")
    DataSource dataSource;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try(PrintWriter pw = response.getWriter();
            Connection cn = dataSource.getConnection();
            Statement st = cn.createStatement();
            ResultSet rs = st.executeQuery("select now()")){
            while(rs.next()){
                pw.write(String.valueOf(rs.getTimestamp(1)));
            }
        }catch(SQLException e){
            throw new ServletException(e);
        }
    }
}

web.xml

この環境の場合はなくても動くようだが一応。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <resource-ref>
        <res-ref-name>jdbc/hoge</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
    </resource-ref>
</web-app>

jboss-web.xml

WEB-INFの下に置く。ここでデータソースのJNDI名とResourceアノテーションのlookup属性で指定した名前のひも付けを行う。

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
    <resource-ref>
        <res-ref-name>jdbc/hoge</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <jndi-name>java:jboss/jdbc/TestDS</jndi-name>
    </resource-ref>
</jboss-web>

動かしてみる

テストの際はどうするか

jboss-web.xmlを別のものに差し替えればOK。HogeServletには手を入れずに参照するDBを切り替えることができる。

備考

JPAのpersistence.xmlからはweb.xmlとjboss-web.xmlで定義した論理名を参照できない

persistence.xmlからもweb.xmlとjboss-web.xmlで定義した論理名 “jdbc/hoge” を使う事が出来れば、jboss-web.xmlを差し替えるだけでJPAから参照するデータソースも切り替えられるので楽だなと思ったのだが、どうやらそれは出来ないらしい[2]。“java:comp/env/jdbc/hoge” とかも試してみたが駄目だった。persistence.xmlにはAPサーバに定義してあるJNDI名を直接指定してやる必要があるみたい。残念。WebSphereだとできたりするみたいだけど一般的には駄目っぽい[5]。

今回の例だとこう書いてやる必要がある。

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="datasource">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:jboss/jdbc/TestDS</jta-data-source>
    </persistence-unit>
</persistence>

ただアプリケーションローカルでweb.xmlかアノテーションで定義したデータソースを使う場合は共用が可能らしい[3]。アプリの資源に接続情報べた書きになるので避けたい気もするが用途によっては良いのかもしれない。

@Resourceで直接JNDI名を参照する

特に論理名を通じて利用する必要がないなら、HogeServlet.javaで以下のようにすれば直接JNDI名からデータソースを拾って来れる。jboss-web.xmlもweb.xmlも不要になる。

ただし複数箇所でJNDI名の直書きが発生するのはあまりよろしくないので、CDIのProducerを使うか、前述の手段で論理名を通して参照した方が良いような気はする。

package com.example;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

@WebServlet("/HogeServlet")
public class HogeServlet extends HttpServlet {

    @Resource(lookup="java:jboss/jdbc/TestDS")
    DataSource dataSource;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try(PrintWriter pw = response.getWriter();
            Connection cn = dataSource.getConnection();
            Statement st = cn.createStatement();
            ResultSet rs = st.executeQuery("select now()")){
            while(rs.next()){
                pw.write(String.valueOf(rs.getTimestamp(1)));
            }
        }catch(SQLException e){
            throw new ServletException(e);
        }
    }
}

参考文献

  1. JBoss でのデータソースの定義のしかた (DB2/400)
  2. Beware of soapy frogs: Java EE 6 - Traps, pitfalls and warts list
  3. DataSource Resource Definition in Java EE 6 (Enterprise Tech Tips)
  4. Java EE 7 Deployment Descriptors | Antonio's Blog
  5. WebSphere Application Server Version 8 Information Center


jboss-cliからいろいろ設定したりしてみる


Posted on Saturday Jan 25, 2014 at 08:01PM in Technology


jboss-cliを使っていろいろ設定する方法のメモです

環境

  • WildFly 8.0.0.CR1

ロガー

ここに書きました: ロガーを設定してみる

データソース

ここに書きました: CLIでデータソースを定義する

データソースの一覧を見る

ls /subsystem=datasources/data-source

JNDI

ここにも書きました: ProjectStageをJNDIで設定する

一覧表示

ls /subsystem=naming/binding

java:/env/jsf/ProjectStage=Developmentを設定する

/subsystem=naming/binding=java\:\/env\/jsf\/ProjectStage/:add(binding-type=simple,value=Development,class=java.lang.String)

java:/env/jsf/ProjectStageの設定内容を確認する

ls /subsystem=naming/binding=java\:\/env\/jsf\/ProjectStage

java:/env/jsf/ProjectStageの値をUnitTestに変更する

/subsystem=naming/binding=java\:\/env\/jsf\/ProjectStage/:write-attribute(name=value,value=UnitTest)

システムプロパティ

一覧表示

ls /system-property

file.encoding=UTF-8を設定する

/system-property=file.encoding:add(value=UTF-8)

file.encodingの設定内容を確認する

/system-property=file.encoding:read-resource

file.encodingを削除する

/system-property=file.encoding:remove

参考文献

  1. CLI Recipes - JBoss AS 7.1 - Project Documentation Editor


ロガーを設定してみる


Posted on Thursday Jan 23, 2014 at 04:32PM in Technology


環境

  • WildFly8.0.0CR1

jboss-cliからやる方法

CLIの管理コマンドjboss-cliを起動しconnectした後に打つコマンドです

コンソールのログレベルをTRACEレベルにする

/subsystem=logging/console-handler=CONSOLE:change-log-level(level=TRACE)

org.hibernate.SQLのロガーをTRACEレベルで作る

/subsystem=logging/logger=org.hibernate.SQL:add(level=TRACE) 

この2つをやると取り急ぎHibernateのSQLが出るようになります。

コマンドを打つとすぐに設定が反映されてログが出るようになります。再起動はいりません。便利だ。

コンソールのログレベルを確認

/subsystem=logging/console-handler=CONSOLE:read-resource

追加したロガーを確認

/subsystem=logging/logger=org.hibernate.SQL:read-resource 

ロガーを削除

/subsystem=logging/logger=org.hibernate.SQL:remove

ロガーを一覧表示

ls /subsystem=logging/logger

ロガーのログレベルを変更

org.hibernate.SQLのログレベルをTRACEに変更

/subsystem=logging/logger=org.hibernate.SQL:change-log-level(level=TRACE)

ファイルハンドラの設定

  • ここからはWildFly8.0.0Finalで実験。多分CR1でも同じだと思うけど

ログ出力用サーブレット

  • こんな感じのログ出力サーブレットをデプロイして実験してみる
package logger;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/")
public class LogServlet extends HttpServlet {
    private static final java.util.logging.Logger JUL_LOGGER1 = java.util.logging.Logger.getLogger("hoge.logger1");
    private static final org.slf4j.Logger SLF4J_LOGGER1 = org.slf4j.LoggerFactory.getLogger("hoge.logger1");
    private static final java.util.logging.Logger JUL_LOGGER2 = java.util.logging.Logger.getLogger("hoge.logger2");
    private static final org.slf4j.Logger SLF4J_LOGGER2 = org.slf4j.LoggerFactory.getLogger("hoge.logger2");

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        JUL_LOGGER1.info("JUL_LOGGER1.info()");
        SLF4J_LOGGER1.info("SLF4J_LOGGER1.info()");
        JUL_LOGGER2.info("JUL_LOGGER2.info()");
        SLF4J_LOGGER2.info("SLF4J_LOGGER2.info()");
    }
}

設定

  • jboss-cliを使う

ファイルハンドラ作成

/subsystem=logging/file-handler=HOGE_LOGGER1:add(level=INFO, file={"relative-to"=>"jboss.server.log.dir", "path"=>"HOGE_LOGGER1.log"}, append=true, autoflush=true)

ロガーをファイルハンドラを指定して作成

/subsystem=logging/logger=hoge.logger1:add(use-parent-handlers=false,handlers=["HOGE_LOGGER1"])

この状態でサーブレットにアクセスすると

kyle-no-MacBook:log kyle$ pwd
/Users/kyle/apps/wildfly-8.0.0.Final/standalone/log
kyle-no-MacBook:log kyle$ cat HOGE_LOGGER1.log 
08:30:31,672 INFO  [hoge.logger1] (default task-11) JUL_LOGGER1.info()
08:30:31,672 INFO  [hoge.logger1] (default task-11) SLF4J_LOGGER1.info()
kyle-no-MacBook:log kyle$ 
  • この例だとEclipseのコンソールやserver.logには出なくなる。hoge.logger2の出力だけ残る:
08:30:31,672 INFO  [hoge.logger2] (default task-11) JUL_LOGGER2.info()
08:30:31,673 INFO  [hoge.logger2] (default task-11) SLF4J_LOGGER2.info()
  • ハンドラには、他にも日時でローテートできるファイルハンドラや、サイズでローテートできるファイルハンドラ、syslogに転送するハンドラなどがある[3]
  • logbackほど豊富ではないが、ほとんどの局面で問題なさそうな品揃えな気はする

server.logには出したくないけどコンソールには出したい

  • こうするとコンソールに出るようになる
/subsystem=logging/logger=hoge.logger1:assign-handler(name=CONSOLE)
  • コンソールの出力
08:40:33,090 INFO  [hoge.logger1] (default task-14) JUL_LOGGER1.info()
08:40:33,090 INFO  [hoge.logger1] (default task-14) SLF4J_LOGGER1.info()
08:40:33,090 INFO  [hoge.logger2] (default task-14) JUL_LOGGER2.info()
08:40:33,091 INFO  [hoge.logger2] (default task-14) SLF4J_LOGGER2.info()
  • HOGE_LOGGER1.log
08:40:33,090 INFO  [hoge.logger1] (default task-14) JUL_LOGGER1.info()
08:40:33,090 INFO  [hoge.logger1] (default task-14) SLF4J_LOGGER1.info()
  • server.log
2014-03-06 08:40:33,090 INFO  [hoge.logger2] (default task-14) JUL_LOGGER2.info()
2014-03-06 08:40:33,091 INFO  [hoge.logger2] (default task-14) SLF4J_LOGGER2.info()

日時でローテートさせたい

  • periodic-rotating-file-handlerを使うとできる
  • server.log用にデフォルトで作られているハンドラの設定はこんな感じになっている
[standalone@localhost:9990 /] /subsystem=logging/periodic-rotating-file-handler=FILE:read-resource
{
    "outcome" => "success",
    "result" => {
        "append" => true,
        "autoflush" => true,
        "enabled" => true,
        "encoding" => undefined,
        "file" => {
            "relative-to" => "jboss.server.log.dir",
            "path" => "server.log"
        },
        "filter" => undefined,
        "filter-spec" => undefined,
        "formatter" => "%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n",
        "level" => "ALL",
        "name" => "FILE",
        "named-formatter" => "PATTERN",
        "suffix" => ".yyyy-MM-dd"
    }
}
  • 上を参考に分単位でローテートするファイルハンドラを作ってみる
/subsystem=logging/periodic-rotating-file-handler=HOGE_LOGGER2:add( \
 append=true, \
 autoflush=true, \
 enabled=true, \
 file= {"relative-to"=>"jboss.server.log.dir", "path"=>"HOGE_LOGGER2.log"}, \ 
 formatter= "%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n", \
 level=INFO, \
 named-formatter=PATTERN, \
 suffix=".yyyy-MM-dd_HHmm")
  • hoge.logger2ロガーを作る
    • HOGE_LOGGER2とCONSOLEをハンドラにする
/subsystem=logging/logger=hoge.logger2:add(use-parent-handlers=false,handlers=["HOGE_LOGGER2", "CONSOLE"])
  • こんな感じになる
kyle-no-MacBook:log kyle$ ls -l HOGE_LOGGER2*
-rw-r--r--+ 1 kyle  staff  164  3  6 09:01 HOGE_LOGGER2.log
-rw-r--r--+ 1 kyle  staff    0  3  6 08:54 HOGE_LOGGER2.log.2014-03-06_0854
-rw-r--r--+ 1 kyle  staff  822  3  6 08:58 HOGE_LOGGER2.log.2014-03-06_0858
-rw-r--r--+ 1 kyle  staff  328  3  6 08:59 HOGE_LOGGER2.log.2014-03-06_0859
kyle-no-MacBook:log kyle$ cat HOGE_LOGGER2.log.2014-03-06_0858
2014-03-06 08:58:15,099 INFO  [hoge.logger2] (default task-15) JUL_LOGGER2.info()
2014-03-06 08:58:15,101 INFO  [hoge.logger2] (default task-15) SLF4J_LOGGER2.info()
2014-03-06 08:58:18,526 INFO  [hoge.logger2] (default task-1) JUL_LOGGER2.info()
2014-03-06 08:58:18,526 INFO  [hoge.logger2] (default task-1) SLF4J_LOGGER2.info()
2014-03-06 08:58:19,645 INFO  [hoge.logger2] (default task-2) JUL_LOGGER2.info()
2014-03-06 08:58:19,645 INFO  [hoge.logger2] (default task-2) SLF4J_LOGGER2.info()
2014-03-06 08:58:20,461 INFO  [hoge.logger2] (default task-3) JUL_LOGGER2.info()
2014-03-06 08:58:20,461 INFO  [hoge.logger2] (default task-3) SLF4J_LOGGER2.info()
2014-03-06 08:58:22,126 INFO  [hoge.logger2] (default task-4) JUL_LOGGER2.info()
2014-03-06 08:58:22,127 INFO  [hoge.logger2] (default task-4) SLF4J_LOGGER2.info()
kyle-no-MacBook:log kyle$ cat HOGE_LOGGER2.log.2014-03-06_0859
2014-03-06 08:59:03,932 INFO  [hoge.logger2] (default task-5) JUL_LOGGER2.info()
2014-03-06 08:59:03,933 INFO  [hoge.logger2] (default task-5) SLF4J_LOGGER2.info()
2014-03-06 08:59:04,258 INFO  [hoge.logger2] (default task-6) JUL_LOGGER2.info()
2014-03-06 08:59:04,258 INFO  [hoge.logger2] (default task-6) SLF4J_LOGGER2.info()
kyle-no-MacBook:log kyle$ cat HOGE_LOGGER2.log
2014-03-06 09:01:39,835 INFO  [hoge.logger2] (default task-7) JUL_LOGGER2.info()
2014-03-06 09:01:39,836 INFO  [hoge.logger2] (default task-7) SLF4J_LOGGER2.info()
kyle-no-MacBook:log kyle$ 

ファイルサイズでローテートさせたい

  • size-rotating-file-handlerを使えば可能
  • 保持する古いログの上限を設定すると、上限を超えた古いログを自動で削除してくれる
  • ハンドラの作成はこんな感じ。サイズ2Kでローテート、5つを超えたら削除
/subsystem=logging/size-rotating-file-handler=SRFH1:add( \
 append=true, \
 autoflush=true, \
 enabled=true, \
 file= {"relative-to"=>"jboss.server.log.dir", "path"=>"SRFH1.log"}, \ 
 formatter= "%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n", \
 level=INFO, \
 named-formatter=PATTERN, \
 rotate-size="2k", \
 max-backup-index="5" )
  • hoge.logger1にアサインする
/subsystem=logging/logger=hoge.logger1:assign-handler(name=SRFH1)
  • さっきのサーブレットのリロードをしばし連打するとこんな感じになる
kyle-no-MacBook:log kyle$ pwd
/Users/kyle/apps/wildfly-8.0.0.Final/standalone/log
kyle-no-MacBook:log kyle$ ls -l SRFH*
-rw-r--r--+ 1 kyle  staff   746  3  6 10:44 SRFH1.log
-rw-r--r--+ 1 kyle  staff  2056  3  6 10:44 SRFH1.log.1
kyle-no-MacBook:log kyle$ cat SRFH1.log.1
2014-03-06 10:44:18,330 INFO  [hoge.logger1] (default task-15) JUL_LOGGER1.info()
2014-03-06 10:44:18,330 INFO  [hoge.logger1] (default task-15) SLF4J_LOGGER1.info()
2014-03-06 10:44:22,966 INFO  [hoge.logger1] (default task-1) JUL_LOGGER1.info()
2014-03-06 10:44:22,967 INFO  [hoge.logger1] (default task-1) SLF4J_LOGGER1.info()
2014-03-06 10:44:23,132 INFO  [hoge.logger1] (default task-2) JUL_LOGGER1.info()
2014-03-06 10:44:23,133 INFO  [hoge.logger1] (default task-2) SLF4J_LOGGER1.info()
2014-03-06 10:44:23,268 INFO  [hoge.logger1] (default task-3) JUL_LOGGER1.info()
2014-03-06 10:44:23,268 INFO  [hoge.logger1] (default task-3) SLF4J_LOGGER1.info()
2014-03-06 10:44:23,391 INFO  [hoge.logger1] (default task-4) JUL_LOGGER1.info()
2014-03-06 10:44:23,392 INFO  [hoge.logger1] (default task-4) SLF4J_LOGGER1.info()
2014-03-06 10:44:25,137 INFO  [hoge.logger1] (default task-5) JUL_LOGGER1.info()
2014-03-06 10:44:25,138 INFO  [hoge.logger1] (default task-5) SLF4J_LOGGER1.info()
2014-03-06 10:44:25,315 INFO  [hoge.logger1] (default task-6) JUL_LOGGER1.info()
2014-03-06 10:44:25,316 INFO  [hoge.logger1] (default task-6) SLF4J_LOGGER1.info()
2014-03-06 10:44:25,451 INFO  [hoge.logger1] (default task-7) JUL_LOGGER1.info()
2014-03-06 10:44:25,451 INFO  [hoge.logger1] (default task-7) SLF4J_LOGGER1.info()
2014-03-06 10:44:25,574 INFO  [hoge.logger1] (default task-8) JUL_LOGGER1.info()
2014-03-06 10:44:25,574 INFO  [hoge.logger1] (default task-8) SLF4J_LOGGER1.info()
2014-03-06 10:44:26,623 INFO  [hoge.logger1] (default task-9) JUL_LOGGER1.info()
2014-03-06 10:44:26,623 INFO  [hoge.logger1] (default task-9) SLF4J_LOGGER1.info()
2014-03-06 10:44:26,767 INFO  [hoge.logger1] (default task-10) JUL_LOGGER1.info()
2014-03-06 10:44:26,767 INFO  [hoge.logger1] (default task-10) SLF4J_LOGGER1.info()
2014-03-06 10:44:26,901 INFO  [hoge.logger1] (default task-11) JUL_LOGGER1.info()
2014-03-06 10:44:26,902 INFO  [hoge.logger1] (default task-11) SLF4J_LOGGER1.info()
2014-03-06 10:44:27,048 INFO  [hoge.logger1] (default task-12) JUL_LOGGER1.info()
kyle-no-MacBook:log kyle$ cat SRFH1.log
2014-03-06 10:44:27,048 INFO  [hoge.logger1] (default task-12) SLF4J_LOGGER1.info()
2014-03-06 10:44:27,184 INFO  [hoge.logger1] (default task-13) JUL_LOGGER1.info()
2014-03-06 10:44:27,185 INFO  [hoge.logger1] (default task-13) SLF4J_LOGGER1.info()
2014-03-06 10:44:27,306 INFO  [hoge.logger1] (default task-14) JUL_LOGGER1.info()
2014-03-06 10:44:27,307 INFO  [hoge.logger1] (default task-14) SLF4J_LOGGER1.info()
2014-03-06 10:44:27,452 INFO  [hoge.logger1] (default task-15) JUL_LOGGER1.info()
2014-03-06 10:44:27,453 INFO  [hoge.logger1] (default task-15) SLF4J_LOGGER1.info()
2014-03-06 10:44:27,599 INFO  [hoge.logger1] (default task-1) JUL_LOGGER1.info()
2014-03-06 10:44:27,599 INFO  [hoge.logger1] (default task-1) SLF4J_LOGGER1.info()
kyle-no-MacBook:log kyle$ 
  • さらに連打するとこうなる
kyle-no-MacBook:log kyle$ ls -l SRFH*
-rw-r--r--+ 1 kyle  staff  1652  3  6 10:46 SRFH1.log
-rw-r--r--+ 1 kyle  staff  2058  3  6 10:46 SRFH1.log.1
-rw-r--r--+ 1 kyle  staff  2056  3  6 10:46 SRFH1.log.2
-rw-r--r--+ 1 kyle  staff  2061  3  6 10:46 SRFH1.log.3
-rw-r--r--+ 1 kyle  staff  2061  3  6 10:46 SRFH1.log.4
-rw-r--r--+ 1 kyle  staff  2063  3  6 10:46 SRFH1.log.5
kyle-no-MacBook:log kyle$ head SRFH1.log.5
2014-03-06 10:46:17,340 INFO  [hoge.logger1] (default task-7) SLF4J_LOGGER1.info()
2014-03-06 10:46:17,516 INFO  [hoge.logger1] (default task-8) JUL_LOGGER1.info()
2014-03-06 10:46:17,517 INFO  [hoge.logger1] (default task-8) SLF4J_LOGGER1.info()
2014-03-06 10:46:17,653 INFO  [hoge.logger1] (default task-9) JUL_LOGGER1.info()
2014-03-06 10:46:17,653 INFO  [hoge.logger1] (default task-9) SLF4J_LOGGER1.info()
2014-03-06 10:46:17,789 INFO  [hoge.logger1] (default task-10) JUL_LOGGER1.info()
2014-03-06 10:46:17,789 INFO  [hoge.logger1] (default task-10) SLF4J_LOGGER1.info()
2014-03-06 10:46:17,952 INFO  [hoge.logger1] (default task-11) JUL_LOGGER1.info()
2014-03-06 10:46:17,952 INFO  [hoge.logger1] (default task-11) SLF4J_LOGGER1.info()
2014-03-06 10:46:18,085 INFO  [hoge.logger1] (default task-12) JUL_LOGGER1.info()
kyle-no-MacBook:log kyle$ 
  • java.util.loggingちっくな感じ。ちゃんと古いのは消えている
  • 書いてから気づいたけどnamed-formatterとformatterはどっちかだけでいいかも

syslogにログを飛ばしてみる

  • OS Xは10.9.2
  • TCPにも出来るかもしれないけどとりあえずUDPでやってみる

OS Xのsyslogdの設定

  • ソケット経由でログの送信を受け付けるようにする
  • syslogdのplistの編集
kyle-no-MacBook:LaunchDaemons kyle$ sudo /usr/libexec/PlistBuddy /System/Library/LaunchDaemons/com.apple.syslogd.plist
Command: add :Sockets:NetworkListener dict
Command: add :Sockets:NetworkListener:SockServiceName string syslog
Command: add :Sockets:NetworkListener:SockType string dgram
Command: save
Saving...
Command: quit
  • syslog.confに適当なテスト用facilityを追加
local1.*                                                /var/log/hoge1.log
  • syslogdの再起動
kyle-no-MacBook:LaunchDaemons kyle$ sudo launchctl unload com.apple.syslogd.plist
kyle-no-MacBook:LaunchDaemons kyle$ sudo launchctl load com.apple.syslogd.plist
kyle-no-MacBook:LaunchDaemons kyle$ sudo lsof -i:514
COMMAND   PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
launchd     1 root   39u  IPv4 0xf0749ee857f40f93      0t0  UDP *:syslog
launchd     1 root  147u  IPv6 0xf0749ee836545ceb      0t0  UDP *:syslog
syslogd 56930 root    4u  IPv4 0xf0749ee857f40f93      0t0  UDP *:syslog
syslogd 56930 root    5u  IPv6 0xf0749ee836545ceb      0t0  UDP *:syslog
kyle-no-MacBook:LaunchDaemons kyle$ 
  • loggerからログを出してみる。ソケット経由で送る方法はわからんかった
kyle-no-MacBook:etc kyle$ logger -p local1.notice hogehoge
kyle-no-MacBook:etc kyle$ cat /var/log/hoge1.log 
Mar  6 11:19:24 kyle-no-MacBook.local kyle[57062]: hogehoge
kyle-no-MacBook:etc kyle$ 

WildFly側の設定

  • まずハンドラを作る
  • [6]に若干説明がある
  • facilityはsyslog.confの書き方と若干異なる。一覧は[6]にある
  • hostnameってのはログの送信元ホスト名らしい
  • server-addressが送信先ホスト名
/subsystem=logging/syslog-handler=SYSLOG1:add( \
 app-name="hogeapp", \
 facility="local-use-1", \
 hostname="kyle-wildfly", \
 level=INFO, \
 server-address="localhost")
  • hoge.logger1にアサイン
/subsystem=logging/logger=hoge.logger1:assign-handler(name=SYSLOG1)
  • サーブレットをリロードすると
kyle-no-MacBook:log kyle$ tail -f /var/log/hoge1.log 
Mar  6 11:19:24 kyle-no-MacBook.local kyle[57062]: hogehoge
Mar  6 11:29:15 1 2014-03-06T11: 29:15.653+09:00 kyle-wildfly hogeapp 5435 hoge.logger1 - JUL_LOGGER1.info()
Mar  6 11:29:15 1 2014-03-06T11: 29:15.670+09:00 kyle-wildfly hogeapp 5435 hoge.logger1 - SLF4J_LOGGER1.info()
Mar  6 11:30:03 1 2014-03-06T11: 30:03.549+09:00 kyle-wildfly hogeapp 5435 hoge.logger1 - JUL_LOGGER1.info()
Mar  6 11:30:03 1 2014-03-06T11: 30:03.549+09:00 kyle-wildfly hogeapp 5435 hoge.logger1 - SLF4J_LOGGER1.info()
Mar  6 11:30:05 1 2014-03-06T11: 30:05.327+09:00 kyle-wildfly hogeapp 5435 hoge.logger1 - JUL_LOGGER1.info()
Mar  6 11:30:05 1 2014-03-06T11: 30:05.327+09:00 kyle-wildfly hogeapp 5435 hoge.logger1 - SLF4J_LOGGER1.info()
Mar  6 11:30:05 1 2014-03-06T11: 30:05.765+09:00 kyle-wildfly hogeapp 5435 hoge.logger1 - JUL_LOGGER1.info()
Mar  6 11:30:05 1 2014-03-06T11: 30:05.766+09:00 kyle-wildfly hogeapp 5435 hoge.logger1 - SLF4J_LOGGER1.info()
  • 出力フォーマットはもう一種類あるみたいなので変えてみる
/subsystem=logging/syslog-handler=SYSLOG1:write-attribute(name="syslog-format", value="RFC3164")
  • 出力日時が一個だけになる
Mar  6 11:33:41 kyle-wildfly hogeapp[5435]: JUL_LOGGER1.info()
Mar  6 11:33:41 kyle-wildfly hogeapp[5435]: SLF4J_LOGGER1.info()
  • 5435って何の数字だろう。WildFlyのPIDかと思ったけど違うし
  • シビリティとかロガー名が欠落しているのが残念な気はする

org.jboss.logmanager.handlers.SyslogHandlerを試してみる

  • [3]によるとsyslog-handlerよりこっちの方が機能が多いらしい
  • そのうちsyslog-handlerにマージされるらしい
  • ハンドラを作る。設定はpropertiesに書くんだけど資料っぽいものがないので[7]のソースを見てsetterの名前から類推した
/subsystem=logging/custom-handler=SYSLOG2:add( \
 class="org.jboss.logmanager.handlers.SyslogHandler", \
 module="org.jboss.logmanager", \
 named-formatter=PATTERN, \
 level=INFO, \
 properties={ \
  appName="hogeapp", \
  hostname="kyle-wildfly", \
  serverHostname="localhost", \
  facility="LOCAL_USE_1", \
  syslogType="RFC3164" })
  • SYSLOG1のアサインを解除してSYSLOG2をアサイン
/subsystem=logging/logger=hoge.logger1:unassign-handler(name=SYSLOG1)
/subsystem=logging/logger=hoge.logger1:assign-handler(name=SYSLOG2)
  • こんな感じ。ロガー名とシビリティが出た。#012って何だろう
Mar  6 12:15:24 kyle-wildfly hogeapp[5435]: 2014-03-06 12:15:24,646 INFO  [hoge.logger1] (default task-11) JUL_LOGGER1.info()#012
Mar  6 12:15:24 kyle-wildfly hogeapp[5435]: 2014-03-06 12:15:24,648 INFO  [hoge.logger1] (default task-11) SLF4J_LOGGER1.info()#012
Mar  6 12:15:25 kyle-wildfly hogeapp[5435]: 2014-03-06 12:15:25,144 INFO  [hoge.logger1] (default task-12) JUL_LOGGER1.info()#012
Mar  6 12:15:25 kyle-wildfly hogeapp[5435]: 2014-03-06 12:15:25,145 INFO  [hoge.logger1] (default task-12) SLF4J_LOGGER1.info()#012
  • #012を消すべくフォーマットをいじってみる
  • いったんSYSLOG2を消す
/subsystem=logging/logger=hoge.logger1:unassign-handler(name=SYSLOG2)
/subsystem=logging/custom-handler=SYSLOG2:remove
  • フォーマットいじって作り直し
/subsystem=logging/custom-handler=SYSLOG2:add( \
 class="org.jboss.logmanager.handlers.SyslogHandler", \
 module="org.jboss.logmanager", \
 formatter="%-5p [%c] (%t) %s", \
 level=INFO, \
 properties={ \
  appName="hogeapp", \
  hostname="kyle-wildfly", \
  serverHostname="localhost", \
  facility="LOCAL_USE_1", \
  syslogType="RFC3164" })
/subsystem=logging/logger=hoge.logger1:assign-handler(name=SYSLOG2)
  • こうなる。シビリティとロガー名も出てるしこれでいいかな。
Mar  6 13:00:20 kyle-wildfly hogeapp[5435]: INFO  [hoge.logger1] (default task-10) JUL_LOGGER1.info()
Mar  6 13:00:20 kyle-wildfly hogeapp[5435]: INFO  [hoge.logger1] (default task-10) SLF4J_LOGGER1.info()
  • ちなみにformatterの書き方はlog4jと同じらしい[8]
  • 例外とか最大長も考慮するとRFC3164形式ならこんな感じがいいかも
/subsystem=logging/custom-handler=SYSLOG6:add( \
 class="org.jboss.logmanager.handlers.SyslogHandler", \
 module="org.jboss.logmanager", \
 formatter="%-5p [%c] (%t) %s%e", \
 level=INFO, \
 properties={ \
  appName="hogeapp", \
  hostname="kyle-wildfly", \
  serverHostname="localhost", \
  facility="LOCAL_USE_1", \
  truncate=false, \
  maxLength=1024, \
  syslogType="RFC3164" })
/subsystem=logging/logger=hoge.logger1:assign-handler(name=SYSLOG6)
  • ログはこんな感じ
Mar  8 10:17:02 kyle-wildfly hogeapp[91739]: INFO  [hoge.logger1] (default task-1) 0-1199: 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567
Mar  8 10:17:02 kyle-wildfly hogeapp[91739]: 89012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
Mar  8 10:17:02 kyle-wildfly hogeapp[91739]: INFO  [hoge.logger1] (default task-1) exception logging test: java.lang.AssertionError: test#012#011at logger.LogServlet.doGet(LogServlet.java:22)#012#011at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)#012#011at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)#012#011at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)#012#011at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61)#012#011at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)#012#011at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)#012#011at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25)#012#011at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociati
Mar  8 10:17:02 kyle-wildfly hogeapp[91739]: onHandler.java:113)#012#011at io.undertow.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java:52)#012#011at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45)#012#011at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61)#012#011at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70)#012#011at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)#012#011at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25)#012#011at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)#012#011at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25)#012
Mar  8 10:17:02 kyle-wildfly hogeapp[91739]: #011at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25)#012#011at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240)#012#011at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227)#012#011at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73)#012#011at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146)#012#011at io.undertow.server.Connectors.executeRootHandler(Connectors.java:168)#012#011at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:687)#012#011at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)#012#011at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)#012#011at java.lang.Thread.run(Thread.java:744)#012
  • タブや改行がエスケープ(#011と#012)されていたり、長いログが分割されていたりするけどちゃんと抜け漏れなく出てる
  • escapeEnabled=“false” にするとエスケープされなくなる
    • けどこれやるとUDPでログを送信する場合は、複数行のメッセージが欠ける[10]
  • RFC5424形式の方が最大長が長かったりするみたいなので、Linuxとかでまた調べる。ソース見るとSSLやTCPでの送信にも対応しているみたい
  • 何故か日本語とかマルチバイト文字が正しく出ない。encoding=“UTF-8” とか入れてみたけど駄目だった。なぜだろう
    • 少しソースを追っかけてみると、charをbyte[]に分ける処理とかがあってそのあたりで何かがおかしくなってるようだった。
    • 暇があったらプルリクエスト送りたいけど大変そうなのでまたそのうち見てみる
    • issueは[11]に上げてプルリクエストも送ってみた

org.apache.log4j.net.SMTPAppenderを使ってみる

ハンドラの設定

  • GMail経由でSSLで認証付きで送る方法。詳細な設定は[12][13]あたりを参照
  • APサーバに設定したSessionをJNDIで指定できればいいんだけどそういうのはないみたい
/subsystem=logging/custom-handler=LOG4J_SMTP:add( \
 class="org.apache.log4j.net.SMTPAppender", \
 module="org.apache.log4j", \
 formatter="%-5p [%c] (%t) %s%e", \
 level=INFO, \
 properties={ \
  From="jane.doe@gmail.example.com", \
  LocationInfo=true, \
  SMTPDebug=true, \
  SMTPHost="smtp.gmail.com", \
  SMTPPort=465, \
  SMTPProtocol="smtps", \
  SMTPUsername="jane.doe@gmail.example.com",  \
  SMTPPassword="***", \
  Subject="error mail subject", \
  To="jane.doe@icloud.example.com", \
  BufferSize=256 })
  • propertiesにSMTPDebug=trueを追加するとログに通信内容が出るので問題解決にはよいかも

ロガーにハンドラをアサイン

/subsystem=logging/logger=hoge.logger1:assign-handler(name=LOG4J_SMTP)

お試し用サーブレット

  • こんな感じでログ出してみる
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        JUL_LOGGER1.info("JUL_LOGGER1.info()");
        SLF4J_LOGGER1.error("にほんご えらー");
    }

こんなメールがくる

  • 日本語出せない問題は少し前に直ったみたい。

本番環境だとどんな感じが良いか

  • ファイルハンドラ系で素直に吐き出しておいて、fluentdとかのログ収集の仕組みを別に入れるのが、モダンな感じで良いんじゃなかろうかと思う
  • syslog絡めてやるのが良いかなと思うが
    • SyslogHandlerで日本語が出せないのがつらい。一応issueは上げておいたけど[11]。
    • Log4Jのsyslogappenderは、一部の文言が欠けるのがつらい
    • size-rotating-file-handlerとかでローカルに出しつつ(こいつは古いログのパージもやってくれるので)、syslogにも出して、最終的にはどこかのログサーバに集約するとか
    • org.jboss.logmanager.handlers.SyslogHandlerはExceptionをログに出してくれないようだ。 嘘付いてた。formatterに “%e” を設定すると出る。
    • 実はcustom-loggerではLog4JのAppenderも使えるので、log4jのsyslog用Appenderを使うかと思って試してみたら、確かに例外もログに出るんだけど、何故かスタックトレースやメッセージの一部が欠ける謎の現象が現れるので、あんまり良くない
  • あとlog4jのSMTPAppenderのメール通知は状況によっては便利だと思う。WildFlyなら別にjar持ってきたりする必要も無くCLIから設定するだけで使える。

気になる事

  • syslogに出すとpidらしきところに5435と表示されるんだが、そんなプロセスは動いてない
kyle-no-MacBook:etc kyle$ ps -Af | grep java | grep 5435
  501 54356 42731   0  8:01AM ??         0:32.26 /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/bin/java -Dprogram.name=JBossTools: WildFly 8.0.0...
  • WildFlyは54356なんだけど一番下の桁が欠けてるとかあり得るのだろうか
  • 調べたら欠けてた[9]

参考文献

  1. Logging Configuration - WildFly 8 - Project Documentation Editor
  2. How To - WildFly 8 - Project Documentation Editor
  3. Handlers - WildFly 8 - Project Documentation Editor
  4. 11.5.6. Sample XML Configuration for a Size Log Handler
  5. Configuring JBoss AS 7.2 to log to syslog - Server Fault
  6. Logging Configuration - JBoss AS 7.2 - Project Documentation Editor
  7. GC: SyslogHandler - org.jboss.logmanager.handlers.SyslogHandler (.java) - GrepCode Class Source
  8. Customizing  logging format in Jboss 7 AS | Community
  9. [LOGMGR-100] SyslogHandler.findPid() omitted the last digit of pid - JBoss Issue Tracker
  10. [syslog-ng] Extra Lines Truncated
  11. [LOGMGR-104] SyslogHandler doesn't handle multi-byte characters correctly - JBoss Issue Tracker
  12. SMTPAppender (Apache Log4j 1.2.17 API)
  13. Log4J徹底解説~ネットワーク系Appender