ElasticSearchのJavaクライアントでhttpログをlogbackで出力する方法
ElasticSearchに直接HTTPでAPIを投入し動作確認をした後、Javaクライアント側で動かない場合に原因究明が難しいため、HTTPログを出力するやり方です。
elasticsearch-javaの8.2.0をmavenで取り込むと、httpclient-4.5.10.jarを使っているようなので、httpclient-4.5.10.jarでHTTPログを出せばいいことがわかりました。
pom
<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>elasticsearch_sample3</groupId>
<artifactId>elasticsearch_sample3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven.compiler.source>${java.version}</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>8.2.0</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
<!--
https://www.baeldung.com/apache-httpclient-enable-logging
httpclient-4.5.10.jarでログ出力を行う
-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
</dependencies>
</project>
https://www.baeldung.com/apache-httpclient-enable-logging
にHTTPログを出す方法が書いてあるのですが、おそらくjul-to-slf4jは間違いで、jcl-over-slf4jを使うべきだったようです。
これが分かるまでにかなり時間がかかりました。
jcl-over-slf4jでcommons-logging側の処理を行うので、commons-loggingはexclusionしています。
logback.xml
<configuration debug="false">
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%level] %logger - %msg %n</pattern>
</encoder>
</appender>
<!-- 以下の設定でHTTPログを出力させる -->
<logger name="org.apache.http.wire" level="debug"/>
<root level="INFO">
<appender-ref ref="stdout"/>
</root>
</configuration>
テストコード
package elasticsearch_sample3;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
import co.elastic.clients.elasticsearch._types.Time;
import co.elastic.clients.elasticsearch._types.mapping.DateProperty;
import co.elastic.clients.elasticsearch._types.mapping.IndexOptions;
import co.elastic.clients.elasticsearch._types.mapping.KeywordProperty;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.IndexSettings;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
public class TestElasticsearchClient {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public static void main(String args[]) {
new TestElasticsearchClient().exe();
}
public void exe() {
logger.info("接続開始");
// Create the low-level client
RestClient restClient = RestClient.builder(new HttpHost("100.64.1.25", 9200)).build();
// Create the transport with a Jackson mapper
ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
// And create the API client
ElasticsearchClient client = new ElasticsearchClient(transport);
logger.info("接続完了");
//**************************************
//**************************************
//**************************************
Map<String, Property> map = new HashMap<>();
//.index(true).store(true)
//のようにstore(true)とすると、
//GET /mytestindes/_search
//{
// "stored_fields": [ "xxx" ]
//}
//のような検索をするときにstore指定した部分を指定すると検索できる。
//store(false)のデフォルト設定だと、上記をやってもHITしない
//べつにこれはデフォルトのfalseのままでよく、どのような時につかうのか不明
// map.put("xxx", new Property(new KeywordProperty.Builder().index(false).store(false).norms(false).docValues(false).indexOptions(IndexOptions.Freqs).build()));
map.put("xxx", new Property(new KeywordProperty.Builder().index(false).store(false).norms(false).indexOptions(IndexOptions.Freqs).build()));
map.put("datetime", new Property(new DateProperty.Builder().index(false).build()));
TypeMapping typeMapping = new TypeMapping.Builder().properties(map).build();
IndexSettings indexSettings = new IndexSettings.Builder()
.numberOfShards(String.valueOf(1))
.numberOfReplicas(String.valueOf(0))
.refreshInterval( new Time.Builder().time("60s").build() )
.build();
co.elastic.clients.elasticsearch.indices.CreateIndexRequest.Builder cirb = new co.elastic.clients.elasticsearch.indices.CreateIndexRequest.Builder();
co.elastic.clients.elasticsearch.indices.CreateIndexRequest cir =
cirb.index("mytestindes")
.mappings(typeMapping)
.settings(indexSettings)
.build();
try {
CreateIndexResponse response = client.indices().create(cir);
logger.info("response.acknowledged():" + response.acknowledged());
} catch (ElasticsearchException e) {
logger.error("Elasticsearchで問題発生1!", e);
} catch (IOException e) {
logger.error("Elasticsearchで問題発生2!", e);
}
try {
//transport側で読んでいるのはrestClient.close();なので
//どちらでもよいのかもしれない。
// restClient.close();
transport.close();
} catch (IOException e) {
logger.error("Elasticsearchへのコネクション切断処理でERROR発生!", e);
}
}
}
上記の処理の流れとしては、
1)ElasticsearchClientでElasticsearchとの接続を開始
2)ElasticsearchClientのindices().create()でインデックス作成
3)Elasticsearchとの接続を切断。
です。
ログ
23:40:19,096 [INFO] elasticsearch_sample3.TestElasticsearchClient - 接続開始
23:40:20,751 [INFO] elasticsearch_sample3.TestElasticsearchClient - 接続完了
23:40:20,997 [DEBUG] org.apache.http.wire - http-outgoing-0 >> "PUT /mytestindes HTTP/1.1[\r][\n]"
23:40:20,997 [DEBUG] org.apache.http.wire - http-outgoing-0 >> "User-Agent: elastic-java/8.2.0 (Java/11.0.2)[\r][\n]"
23:40:20,997 [DEBUG] org.apache.http.wire - http-outgoing-0 >> "X-Elastic-Client-Meta: es=8.2.0,jv=11,hl=2,t=8.2.0,hc=4.1.4[\r][\n]"
23:40:20,997 [DEBUG] org.apache.http.wire - http-outgoing-0 >> "Accept: application/vnd.elasticsearch+json; compatible-with=8[\r][\n]"
23:40:20,997 [DEBUG] org.apache.http.wire - http-outgoing-0 >> "Content-Length: 247[\r][\n]"
23:40:20,997 [DEBUG] org.apache.http.wire - http-outgoing-0 >> "Content-Type: application/vnd.elasticsearch+json; compatible-with=8[\r][\n]"
23:40:20,997 [DEBUG] org.apache.http.wire - http-outgoing-0 >> "Host: 100.64.1.25:9200[\r][\n]"
23:40:20,997 [DEBUG] org.apache.http.wire - http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
23:40:20,997 [DEBUG] org.apache.http.wire - http-outgoing-0 >> "[\r][\n]"
23:40:20,997 [DEBUG] org.apache.http.wire - http-outgoing-0 >> "{"mappings":{"properties":{"datetime":{"type":"date","index":false},"xxx":{"type":"keyword","store":false,"index":false,"index_options":"freqs","norms":false}}},"settings":{"number_of_shards":"1","number_of_replicas":"0","refresh_interval":"60s"}}"
23:40:21,216 [DEBUG] org.apache.http.wire - http-outgoing-0 << "HTTP/1.1 200 OK[\r][\n]"
23:40:21,216 [DEBUG] org.apache.http.wire - http-outgoing-0 << "X-elastic-product: Elasticsearch[\r][\n]"
23:40:21,216 [DEBUG] org.apache.http.wire - http-outgoing-0 << "content-type: application/vnd.elasticsearch+json;compatible-with=8[\r][\n]"
23:40:21,216 [DEBUG] org.apache.http.wire - http-outgoing-0 << "content-length: 70[\r][\n]"
23:40:21,216 [DEBUG] org.apache.http.wire - http-outgoing-0 << "[\r][\n]"
23:40:21,216 [DEBUG] org.apache.http.wire - http-outgoing-0 << "{"acknowledged":true,"shards_acknowledged":true,"index":"mytestindes"}"
23:40:21,309 [INFO] elasticsearch_sample3.TestElasticsearchClient - response.acknowledged():true
HTTPログが出力されており、以下のjsonをElasticsearchへ送信していることが確認できます。
{
"mappings": {
"properties": {
"datetime": {
"type": "date",
"index": false
},
"xxx": {
"type": "keyword",
"store": false,
"index": false,
"index_options": "freqs",
"norms": false
}
}
},
"settings": {
"number_of_shards": "1",
"number_of_replicas": "0",
"refresh_interval": "60s"
}
}
logbackを使わない方法もある。
以下のパラメータをJAVAの引数に指定することでHTTPログを出力することが出来る。
-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog -Dorg.apache.commons.logging.simplelog.showdatetime=true -Dorg.apache.commons.logging.simplelog.log.org.apache.http=DEBUG