Kohei Nozaki's blog 

Arquillianチュートリアルを埋め込みWeldでテスト走らせるところまでやってみる


Posted on Friday Jan 24, 2014 at 05:02PM in Technology


JavaEEで結合テストを楽にするツール/フレームワークのArquillianを使ってみます。基本的にはオフィシャルのチュートリアル[2][4]をなぞるだけです。ここでは埋め込みWeld使ったテストが緑色になるところまでやります。

環境

  • Eclipse Kepler SR1
  • Apache Maven 2.2.1 (r801777; 2009-08-07 04:16:01+0900)
  • Apple JDK6u65
  • OS X 10.9.1

準備

プロジェクトを作る

kyle-no-MacBook:arquillian kyle$ mvn archetype:generate -DarchetypeGroupId=net.avh4.mvn.archetype -DarchetypeArtifactId=java-1.6-archetype
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO]    task-segment: [archetype:generate] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] Preparing archetype:generate
[INFO] No goals needed for project - skipping
[INFO] [archetype:generate {execution: default-cli}]
[INFO] Generating project in Interactive mode
[INFO] Archetype [net.avh4.mvn.archetype:java-1.6-archetype:0.0.3] found in catalog remote
Define value for property 'groupId': : org.arquillian.example
Define value for property 'artifactId': : arquillian-tutorial
Define value for property 'version': 1.0-SNAPSHOT: 
Define value for property 'package': org.arquillian.example: 
Confirm properties configuration:
groupId: org.arquillian.example
artifactId: arquillian-tutorial
version: 1.0-SNAPSHOT
package: org.arquillian.example
Y: 
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: java-1.6-archetype:0.0.3
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: org.arquillian.example
[INFO] Parameter: artifactId, Value: arquillian-tutorial
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: org.arquillian.example
[INFO] Parameter: packageInPathFormat, Value: org/arquillian/example
[INFO] Parameter: package, Value: org.arquillian.example
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: groupId, Value: org.arquillian.example
[INFO] Parameter: artifactId, Value: arquillian-tutorial
[INFO] project created from Archetype in dir: /Users/kyle/tmp/arquillian/arquillian-tutorial
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 25 seconds
[INFO] Finished at: Fri Jan 24 20:48:27 JST 2014
[INFO] Final Memory: 23M/310M
[INFO] ------------------------------------------------------------------------
kyle-no-MacBook:arquillian kyle$ 

プロジェクトが出来ました

kyle-no-MacBook:arquillian kyle$ ls -l
total 0
drwxr-xr-x+ 8 kyle  staff  272  1 24 20:48 arquillian-tutorial
kyle-no-MacBook:arquillian kyle$ 

pom.xmlを書き換える

JavaEE6用の依存性を追加します。結果以下のように。本当はJavaEE7でやりたいのですが何かとらぶるのもいやなのでとりあえずチュートリアル通りに。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.arquillian.example</groupId>
  <artifactId>arquillian-tutorial</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>arquillian-tutorial</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-all</artifactId>
      <version>1.8.5</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest-integration</artifactId>
      <version>1.2.1</version>
    </dependency>
    <dependency>
      <groupId>net.avh4.util</groupId>
      <artifactId>imagecomparison</artifactId>
      <version>0.0.2</version>
      <scope>test</scope>
    </dependency>
    <!-- clip -->
    <dependency>
        <groupId>org.jboss.spec</groupId>
        <artifactId>jboss-javaee-6.0</artifactId>
        <version>1.0.0.Final</version>
        <type>pom</type>
        <scope>provided</scope>
    </dependency>
    <!-- clip -->
  </dependencies>
</project>

Eclipseで開く

  1. FileからImportを開く

  2. Existing Maven Projectsを選択

  3. 作ったプロジェクトのディレクトリを選択してFinish

  4. 特にエラーもなくプロジェクトができました Java6が探し出されてしまったのがアレですがとりあえず我慢

pom.xmlを編集する

Maven Surefire Pluginはオプションだけど入れとくのをお勧めするとか書いてあるので、とりあえずこれも追加。動かすコンテナはとりあえずWeld EE Embeddedになっている。最終的にはスタンドアロンで動いてるWildFlyにしたいんだけどまあとりあえず。結果こうなる。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.arquillian.example</groupId>
  <artifactId>arquillian-tutorial</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>arquillian-tutorial</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.jboss.arquillian</groupId>
                <artifactId>arquillian-bom</artifactId>
                <version>1.1.2.Final</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.12</version>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-all</artifactId>
      <version>1.8.5</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest-integration</artifactId>
      <version>1.2.1</version>
    </dependency>
    <dependency>
      <groupId>net.avh4.util</groupId>
      <artifactId>imagecomparison</artifactId>
      <version>0.0.2</version>
      <scope>test</scope>
    </dependency>
    <!-- clip -->
    <dependency>
        <groupId>org.jboss.spec</groupId>
        <artifactId>jboss-javaee-6.0</artifactId>
        <version>1.0.0.Final</version>
        <type>pom</type>
        <scope>provided</scope>
    </dependency>
    <!-- clip -->
    <dependency>
        <groupId>org.jboss.arquillian.junit</groupId>
        <artifactId>arquillian-junit-container</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- for weld ee embedded start -->
    <dependency>
        <groupId>org.jboss.arquillian.container</groupId>
        <artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
        <version>1.0.0.CR3</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.jboss.weld</groupId>
        <artifactId>weld-core</artifactId>
        <version>1.1.5.Final</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.6.4</version>
        <scope>test</scope>
    </dependency>
    <!-- for weld ee embedded end -->   
  </dependencies>
</project>

クラスを作る

package org.arquillian.example;

import java.io.PrintStream;

/**
 * A component for creating personal greetings.
 */
public class Greeter {
    public void greet(PrintStream to, String name) {
        to.println(createGreeting(name));
    }

    public String createGreeting(String name) {
        return "Hello, " + name + "!";
    }
}

テストクラスを作る

package org.arquillian.example;

import javax.inject.Inject;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.Test;
import org.junit.Assert;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class GreeterTest {

    @Deployment
    public static JavaArchive createDeployment() {
        return ShrinkWrap.create(JavaArchive.class)
            .addClass(Greeter.class)
            .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @Inject
    Greeter greeter;

    @Test
    public void should_create_greeting() {
        Assert.assertEquals("Hello, Earthling!",
            greeter.createGreeting("Earthling"));
        greeter.greet(System.out, "Earthling");
    }
}

クラスとテストクラスの配置

Maven Dependenciesの下にあるjarファイルを数えてみると72個あります。

テスト実行

テストクラスのウインドウで右クリック、Run As→JUnit Test

コンソールへの出力

JUnit窓への出力

やっと@Inject使ったコードが動くとこまできました。準備は大変だったけど、埋め込みコンテナだけにテストの実行速度は普通のJavaクラスの単体テスト並の早さ。長くなったので続きは別の項で。

続き

Arquillianチュートリアルの埋め込みGlassFish3でテストを走らせるところをやってみる

参考文献

  1. Arquillianを使った本物のJava EEテスト - nekopの日記
  2. Getting Started · Arquillian Guides
  3. Arquillianでインテグレーションテスト最初の第一歩 - 裏紙
  4. Getting Started · Arquillian Guides (日本語)


jQuery File Uploadとサーブレットでファイルアップロード画面を作ってみる


Posted on Friday Jan 24, 2014 at 09:13AM in Technology


jQuery File UploadとJava Servletを使ってドラッグアンドドロップで複数ファイルのアップロードが可能な画面を作ってみます。

ここでは[1]を使います。[3]が参考になりそうです。サーバ側での受け取りはサーブレットを使います。Servlet3のAPIを使って作ります。

環境

  • jQuery-File-Upload-9.5.3
  • WildFly 8.0.0CR1
  • Oracle JDK7u51
  • OS X 10.9.1

準備

  • [1]からzipファイルをダウンロードしてきます。私は9.5.3.zipというファイルを取ってきました
  • この要領でEclipseでJavaEE7プロジェクトを作ります

作る

画面側でHTMLファイル以外に必要なもの

  • jQuery本体
  • js/jquery.fileupload.js
  • js/jquery.iframe-transport.js
  • js/vendor/jquery.ui.widget.js

jQuery本体はCDNから取ってきます。下3つはjQuery-File-Uploadのzipファイルに含まれていますので適当な場所にコピーします。この例ではjsディレクトリを作ってそこにまとめて置きました。

プロジェクトの構造

こんな感じ

画面側

index.html

  • 基本はファイル選択ボタンを押してファイルダイアログ出して選択
  • 直接ブラウザの画面へドラッグアンドドロップも可
  • 複数ファイルOK
  • 簡単なプログレスバー的なものあり
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>jQuery File Upload Example</title>
<style>
.bar {
    height: 18px;
    background: green;
}
</style>
</head>
<body>
<input id="fileupload" type="file" name="files[]" data-url="upload" multiple>
<div id="progress">
    <div class="bar" style="width: 0%;"></div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="js/jquery.ui.widget.js"></script>
<script src="js/jquery.iframe-transport.js"></script>
<script src="js/jquery.fileupload.js"></script>
<script>
$('#fileupload').fileupload({
    progressall: function (e, data) {
        var progress = parseInt(data.loaded / data.total * 100, 10);
        $('#progress .bar').css(
            'width',
            progress + '%'
        );
    }
});
</script>
</body> 
</html>

バックエンド側

UploadReceiveServlet

package jqueryfileul;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

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

@WebServlet("/upload")
@MultipartConfig(fileSizeThreshold = 1024 * 1024, maxFileSize = 1024 * 1024 * 5, maxRequestSize = 1024 * 1024 * 5 * 5)
public class UploadReceiveServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {

        for (Part part : request.getParts()) {
            System.out.println(part.getName());
            System.out.println(part.getContentType());
            System.out.println(part.getSubmittedFileName());
            System.out.println(part.getSize());
            if ("text/plain".equals(part.getContentType())) {
                try (InputStream is = part.getInputStream();
                        InputStreamReader r = new InputStreamReader(is);
                        BufferedReader br = new BufferedReader(r)) {
                    System.out.println(br.readLine());
                }
            }
        }
    }
}

動かしてみる

画面はこんな感じ

ドラッグアンドドロップ

わかりにくいけどFinderからファイル2個ドラッグしてるところです。

プログレスバーが緑色に

サーバ側でも取れてますね

その他

日本語ファイル名が化ける

私の環境だと何故か日本語ファイル名でアップロードすると文字化けが起こります。この設定しとけば大丈夫だろうと思っていたのだけど。またそのうち調べる。クライアント側でファイル名をURIエンコードしないといけないのかな。

PrimeFacesのファイルアップロードコンポーネントお勧め

JSFの動くWebコンテナがあるならPrimeFacesの同機能[7]を使うのがお勧めです。何故わざわざこんな風に書いているかというと[6]の問題にはまったらしく、advancedモードで動かす事が出来なかったからです。

ちなみにPrimeFacesの同コンポーネントはかつてCommons FileUploadとCommons IOに依存していて、なおかつフィルタの設定も必要だったのですが、JSF2.2上で動かすなら両者とも不要になったようです。WildFlyでは動かなかったけど。GlassFish4なら動くのかな。

参考文献

  1. jQuery File Upload Demo
  2. 7 Javascript Ajax File Upload Plugins
  3. Java Servlet – jQuery File Upload (multiple, drag&drop, progress…) | HMKCode
  4. Basic plugin · blueimp/jQuery-File-Upload Wiki
  5. JSF 2.2 で待ちに待ったFileUploadを試す - DENのシステムエンジニアの思うこと
  6. [WFLY-2329] File upload doesn't work - JBoss Issue Tracker
  7. PrimeFaces - ShowCase


ロガーを設定してみる


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


WildFly8.0.0CR1でPOSTパラメータの文字化けを回避する


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


環境

  • WildFly8.0.0CR1
  • Oracle JRE7u51

設定内容

/WEB-INF/jboss-web.xmlに以下のような内容を書くだけです

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web version="8.0" xmlns="http://www.jboss.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.jboss.org/j2ee/schema/jboss-web_8_0.xsd">
    <default-encoding>UTF-8</default-encoding>
</jboss-web>

WildFly8は最近HTTPサーバの実装が切り替わったか何かで若干情報が見つかり辛かった。あとアプリ別じゃなくてアプリケーションサーバ全体に同じ設定を適用する手段も参考資料にありました。試してないけど。

あと何故かこの設定を入れなくてもajaxの通信は化けなかった

参考文献


markdown4jで遊ぶ


Posted on Wednesday Jan 22, 2014 at 01:28PM in Technology


環境

  • markdown4j 2.2
  • WildFly 8.0.0CR1
  • Oracle JDK7u51

何をするの?

markdown4jで遊びます。とりあえずサンプルとかありがちなのを動かしてみてどんな感じのhtmlが生成されるか見てみます。

実験用画面も置いておきます

準備

pom.xml

mavenで取ってこれるのでここにあるdependencyを追加します

実験用画面

JSFで画面を作ります

CDI管理Bean

import java.io.IOException;
import java.io.Serializable;

import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

import org.markdown4j.Markdown4jProcessor;

@Named
@SessionScoped
public class MarkdownBean implements Serializable {

	String body;
	String md;

	public String getMd() {
		return md;
	}

	public void setMd(String md) {
		this.md = md;
	}

	public String getBody() {
		return body;
	}

	public void setBody(String body) {
		this.body = body;
	}

	public void process() throws IOException {
		md = new Markdown4jProcessor().process(body);
	}
}

Faceletsページ

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets">

<h:head></h:head>
<body>
	<h:form>
		<h:inputTextarea value="#{markdownBean.body}" cols="80" rows="5"
			id="input" />
		<br />
		<h:commandButton action="#{markdownBean.process()}" value="process">
			<f:ajax execute="input" render="md md2" />
		</h:commandButton>
		<div>
			<h:outputText value="#{markdownBean.md}" id="md" />
		</div>
		<hr />
		<div>
			<h:outputText value="#{markdownBean.md}" id="md2" escape="false" />
		</div>
	</h:form>
</body>
</html>

動かしてみる

遊ぶ

markdown4jのページにあるサンプル






最後の方は外部サービス連携みたいですが便利ですね

さらに遊ぶ

# 見出し1
## 見出し2

段落1ああああああああああああああああああああああああああああああああああああああああああああああああああ

段落2

[リンク](http://www.google.com/)

![画像](/jboss_community.png)

``` java
class hoge{
  private int hoge;
  private int hoge2;
}
```

参考文献