Browse Source

Merge pull request #5109 from anuraaga/armeria-updates

Update armeria to latest version, use more idiomatic armeria code, an…
Mike Smith 5 years ago
parent
commit
b843c9ea4f

+ 3 - 3
frameworks/Java/armeria/armeria.dockerfile

@@ -2,9 +2,9 @@ FROM maven:3.6.1-jdk-11-slim as maven
 WORKDIR /armeria
 WORKDIR /armeria
 COPY src src
 COPY src src
 COPY pom.xml pom.xml
 COPY pom.xml pom.xml
-RUN mvn compile assembly:single -q
+RUN mvn package -q
 
 
 FROM openjdk:11.0.3-jdk-slim
 FROM openjdk:11.0.3-jdk-slim
 WORKDIR /armeria
 WORKDIR /armeria
-COPY --from=maven /armeria/target/hello-1.0-SNAPSHOT-jar-with-dependencies.jar app.jar
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-jar", "app.jar"]
+COPY --from=maven /armeria/target/hello-1.0-SNAPSHOT.jar app.jar
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar"]

+ 14 - 17
frameworks/Java/armeria/pom.xml

@@ -16,7 +16,7 @@
     <maven.compiler.target>11</maven.compiler.target>
     <maven.compiler.target>11</maven.compiler.target>
 
 
     <!-- Dependency versions -->
     <!-- Dependency versions -->
-    <armeria.version>0.86.0</armeria.version>
+    <armeria.version>0.93.0</armeria.version>
   </properties>
   </properties>
 
 
   <dependencies>
   <dependencies>
@@ -25,6 +25,11 @@
       <artifactId>armeria</artifactId>
       <artifactId>armeria</artifactId>
       <version>${armeria.version}</version>
       <version>${armeria.version}</version>
     </dependency>
     </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <version>2.12.1</version>
+    </dependency>
     <dependency>
     <dependency>
       <groupId>org.postgresql</groupId>
       <groupId>org.postgresql</groupId>
       <artifactId>postgresql</artifactId>
       <artifactId>postgresql</artifactId>
@@ -55,29 +60,21 @@
       </plugin>
       </plugin>
       <!-- Build an executable JAR with dependencies -->
       <!-- Build an executable JAR with dependencies -->
       <plugin>
       <plugin>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <version>3.1.0</version>
-        <configuration>
-          <archive>
-            <manifest>
-              <mainClass>hello.App</mainClass>
-            </manifest>
-          </archive>
-          <descriptorRefs>
-            <descriptorRef>jar-with-dependencies</descriptorRef>
-          </descriptorRefs>
-        </configuration>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
+        <version>2.1.8.RELEASE</version>
         <executions>
         <executions>
           <execution>
           <execution>
-            <id>make-assembly</id>
-            <phase>package</phase>
             <goals>
             <goals>
-              <goal>single</goal>
+              <goal>repackage</goal>
             </goals>
             </goals>
           </execution>
           </execution>
         </executions>
         </executions>
+        <configuration>
+          <mainClass>hello.App</mainClass>
+          <executable>true</executable>
+        </configuration>
       </plugin>
       </plugin>
-
     </plugins>
     </plugins>
   </build>
   </build>
 
 

+ 18 - 6
frameworks/Java/armeria/src/main/java/hello/App.java

@@ -1,20 +1,32 @@
 package hello;
 package hello;
 
 
-import hello.services.HelloService;
-import hello.services.PostgresDbService;
-import hello.services.PostgresFortunesService;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
 
 
+import com.linecorp.armeria.common.HttpHeaderNames;
 import com.linecorp.armeria.server.Server;
 import com.linecorp.armeria.server.Server;
 import com.linecorp.armeria.server.ServerBuilder;
 import com.linecorp.armeria.server.ServerBuilder;
 
 
+import hello.services.HelloService;
+import hello.services.PostgresDbService;
+import hello.services.PostgresFortunesService;
+
 public final class App {
 public final class App {
   public static void main(String[] args) {
   public static void main(String[] args) {
     ServerBuilder sb = new ServerBuilder();
     ServerBuilder sb = new ServerBuilder();
 
 
     sb.http(8080)
     sb.http(8080)
-      .annotatedService("/", new HelloService())
-      .annotatedService("/", new PostgresDbService())
-      .annotatedService("/", new PostgresFortunesService());
+      .annotatedService(new HelloService())
+      .annotatedService(new PostgresDbService())
+      .annotatedService(new PostgresFortunesService())
+      .decorator((delegate, ctx, req) -> {
+        ctx.addAdditionalResponseHeader(HttpHeaderNames.SERVER, "armeria");
+        ctx.addAdditionalResponseHeader(HttpHeaderNames.DATE,
+                                        DateTimeFormatter.RFC_1123_DATE_TIME.format(
+                                                ZonedDateTime.now(ZoneOffset.UTC)));
+        return delegate.serve(ctx, req);
+      });
 
 
     Server server = sb.build();
     Server server = sb.build();
     server.start().join();
     server.start().join();

+ 0 - 19
frameworks/Java/armeria/src/main/java/hello/helpers/HttpHeadersHelper.java

@@ -1,19 +0,0 @@
-package hello.helpers;
-
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
-
-import com.linecorp.armeria.common.HttpHeaderNames;
-import com.linecorp.armeria.common.HttpStatus;
-import com.linecorp.armeria.common.MediaType;
-import com.linecorp.armeria.common.ResponseHeaders;
-
-public class HttpHeadersHelper {
-  public static ResponseHeaders getHttpHeader(MediaType mediaType) {
-    return ResponseHeaders.of(HttpStatus.OK,
-    		HttpHeaderNames.CONTENT_TYPE, mediaType,
-    		HttpHeaderNames.SERVER, "armeria",
-    		HttpHeaderNames.DATE, DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now(ZoneOffset.UTC)));
-  }
-}

+ 8 - 16
frameworks/Java/armeria/src/main/java/hello/services/HelloService.java

@@ -1,37 +1,29 @@
 package hello.services;
 package hello.services;
 
 
-import hello.helpers.HttpHeadersHelper;
-import hello.models.Message;
-
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.StandardCharsets;
+import java.util.concurrent.CompletableFuture;
 
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.linecorp.armeria.common.HttpData;
 import com.linecorp.armeria.common.HttpResponse;
 import com.linecorp.armeria.common.HttpResponse;
+import com.linecorp.armeria.common.HttpStatus;
 import com.linecorp.armeria.common.MediaType;
 import com.linecorp.armeria.common.MediaType;
 import com.linecorp.armeria.server.annotation.Get;
 import com.linecorp.armeria.server.annotation.Get;
 import com.linecorp.armeria.server.annotation.ProducesJson;
 import com.linecorp.armeria.server.annotation.ProducesJson;
 
 
+import hello.models.Message;
+
 public class HelloService {
 public class HelloService {
   private static final byte[] PLAINTEXT =
   private static final byte[] PLAINTEXT =
       "Hello, World!".getBytes(StandardCharsets.UTF_8);
       "Hello, World!".getBytes(StandardCharsets.UTF_8);
-  private static final ObjectMapper MAPPER = new ObjectMapper();
 
 
   @Get("/plaintext")
   @Get("/plaintext")
   public HttpResponse plaintext() {
   public HttpResponse plaintext() {
-    return HttpResponse.of(
-    	HttpHeadersHelper.getHttpHeader(MediaType.PLAIN_TEXT_UTF_8),
-        HttpData.of(PLAINTEXT)
-        );
+    return HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, PLAINTEXT);
   }
   }
 
 
   @Get("/json")
   @Get("/json")
   @ProducesJson
   @ProducesJson
-  public HttpResponse json() throws JsonProcessingException {
-    return HttpResponse.of(
-    	HttpHeadersHelper.getHttpHeader(MediaType.JSON),
-        HttpData.of(MAPPER.writeValueAsBytes(new Message("Hello, World!")))
-        );
+  // TODO(anuraaga): Change return type to Message after https://github.com/line/armeria/issues/2078
+  public CompletableFuture<Message> json() {
+    return CompletableFuture.completedFuture(new Message("Hello, World!"));
   }
   }
 }
 }

+ 117 - 93
frameworks/Java/armeria/src/main/java/hello/services/PostgresDbService.java

@@ -1,29 +1,25 @@
 package hello.services;
 package hello.services;
 
 
-import hello.helpers.HttpHeadersHelper;
-import hello.helpers.PostgresDbHelper;
-import hello.models.World;
-
 import java.sql.Connection;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLException;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.ThreadLocalRandom;
 
 
 import javax.sql.DataSource;
 import javax.sql.DataSource;
 
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.linecorp.armeria.common.HttpData;
-import com.linecorp.armeria.common.HttpResponse;
-import com.linecorp.armeria.common.MediaType;
-import com.linecorp.armeria.server.annotation.Default;
+import com.zaxxer.hikari.HikariDataSource;
+
+import com.linecorp.armeria.server.ServiceRequestContext;
 import com.linecorp.armeria.server.annotation.Get;
 import com.linecorp.armeria.server.annotation.Get;
 import com.linecorp.armeria.server.annotation.Param;
 import com.linecorp.armeria.server.annotation.Param;
-import com.zaxxer.hikari.HikariDataSource;
+import com.linecorp.armeria.server.annotation.ProducesJson;
+
+import hello.helpers.PostgresDbHelper;
+import hello.models.World;
 
 
 public class PostgresDbService {
 public class PostgresDbService {
-  private static final ObjectMapper MAPPER = new ObjectMapper();
 
 
   private static final String SELECT_QUERY = "SELECT * FROM world WHERE id = ?";
   private static final String SELECT_QUERY = "SELECT * FROM world WHERE id = ?";
   private static final String UPDATE_QUERY =
   private static final String UPDATE_QUERY =
@@ -36,37 +32,49 @@ public class PostgresDbService {
   }
   }
 
 
   @Get("/db")
   @Get("/db")
-  public HttpResponse db() throws Exception {
-    return HttpResponse.of(
-    	HttpHeadersHelper.getHttpHeader(MediaType.JSON),
-        HttpData.of(MAPPER.writeValueAsBytes(getWorld(getRandomNumber())))
-        );
+  @ProducesJson
+  public CompletableFuture<World> db(ServiceRequestContext ctx) throws Exception {
+    return getWorld(getRandomNumber(), ctx);
+  }
+
+  @Get("/queries/{count}")
+  @ProducesJson
+  public CompletableFuture<World[]> queries(
+          @Param("count") String count,
+          ServiceRequestContext ctx) {
+    return doQueries(count, ctx);
+  }
+
+  @Get("/queries/")
+  @ProducesJson
+  public CompletableFuture<World[]> queries(ServiceRequestContext ctx) {
+    return doQueries("", ctx);
+  }
+
+  private CompletableFuture<World[]> doQueries(
+          @Param("count") String count,
+          ServiceRequestContext ctx) {
+    return getWorlds(getSanitizedCount(count), ctx);
   }
   }
 
 
-  // need to use regex as /queries/{count} doesn't work when count is null
-  @Get("regex:^/queries/(?<count>.*)$")
-  public HttpResponse queries(
-      @Param("count")
-      @Default("")
-          String count) throws JsonProcessingException, SQLException {
-    return HttpResponse.of(
-        HttpHeadersHelper.getHttpHeader(MediaType.JSON),
-        HttpData.of(
-            MAPPER.writeValueAsBytes(getWorlds(getSanitizedCount(count))))
-        );
+  @Get("/updates/{count}")
+  @ProducesJson
+  public CompletableFuture<World[]> update(
+          @Param("count") String count,
+          ServiceRequestContext ctx) {
+    return doUpdate(count, ctx);
   }
   }
 
 
-  @Get("regex:^/updates/(?<count>.*)$")
-  public HttpResponse update(
-      @Param("count")
-      @Default("")
-          String count) throws JsonProcessingException, SQLException {
-    return HttpResponse.of(
-        HttpHeadersHelper.getHttpHeader(MediaType.JSON),
-        HttpData.of(
-            MAPPER.writeValueAsBytes(
-                getUpdatedWorlds(getSanitizedCount(count))))
-        );
+  @Get("/updates/")
+  @ProducesJson
+  public CompletableFuture<World[]> update(ServiceRequestContext ctx) {
+    return doUpdate("", ctx);
+  }
+
+  private CompletableFuture<World[]> doUpdate(
+          String count,
+          ServiceRequestContext ctx) {
+    return getUpdatedWorlds(getSanitizedCount(count), ctx);
   }
   }
 
 
   private static int getRandomNumber() {
   private static int getRandomNumber() {
@@ -88,71 +96,87 @@ public class PostgresDbService {
     }
     }
   }
   }
 
 
-  private World getWorld(int number) throws SQLException {
-    try (final Connection connection = dataSource.getConnection();
-         final PreparedStatement statement =
-             connection.prepareStatement(SELECT_QUERY)) {
-
-      statement.setInt(1, number);
-
-      try (final ResultSet resultSet = statement.executeQuery()) {
-        resultSet.next();
-        return new World(resultSet.getInt(1), resultSet.getInt(2));
-      }
-    }
+  private CompletableFuture<World> getWorld(int number, ServiceRequestContext ctx) {
+    return CompletableFuture.supplyAsync(
+        () -> {
+          try (final Connection connection = dataSource.getConnection();
+               final PreparedStatement statement =
+                   connection.prepareStatement(SELECT_QUERY)) {
+
+            statement.setInt(1, number);
+
+            try (final ResultSet resultSet = statement.executeQuery()) {
+              resultSet.next();
+              return new World(resultSet.getInt(1), resultSet.getInt(2));
+            }
+          } catch (SQLException e) {
+            throw new IllegalStateException("Database error", e);
+          }
+        }, ctx.blockingTaskExecutor());
   }
   }
 
 
-  private World[] getWorlds(int count) throws SQLException {
-    World[] worlds = new World[count];
-
-    try (final Connection connection = dataSource.getConnection()) {
-      for (int i = 0; i < count; i++) {
-        final int id = getRandomNumber();
-
-        try (final PreparedStatement statement =
-                 connection.prepareStatement(SELECT_QUERY)) {
-          statement.setInt(1, id);
-
-          try (final ResultSet resultSet = statement.executeQuery()) {
-            resultSet.next();
-            worlds[i] = new World(id, resultSet.getInt(2));
+  private CompletableFuture<World[]> getWorlds(int count, ServiceRequestContext ctx) {
+    return CompletableFuture.supplyAsync(
+        () -> {
+          World[] worlds = new World[count];
+
+          try (final Connection connection = dataSource.getConnection()) {
+            for (int i = 0; i < count; i++) {
+              final int id = getRandomNumber();
+
+              try (final PreparedStatement statement =
+                       connection.prepareStatement(SELECT_QUERY)) {
+                statement.setInt(1, id);
+
+                try (final ResultSet resultSet = statement.executeQuery()) {
+                  resultSet.next();
+                  worlds[i] = new World(id, resultSet.getInt(2));
+                }
+              }
+            }
+          } catch (SQLException e) {
+            throw new IllegalStateException("Database error", e);
           }
           }
-        }
-      }
-    }
-    return worlds;
+          return worlds;
+        }, ctx.blockingTaskExecutor());
   }
   }
 
 
-  private World[] getUpdatedWorlds(int count) throws SQLException {
-    World[] worlds = new World[count];
+  private CompletableFuture<World[]> getUpdatedWorlds(int count, ServiceRequestContext ctx) {
+    return CompletableFuture.supplyAsync(
+        () -> {
 
 
-    try (final Connection connection = dataSource.getConnection()) {
-      for (int i = 0; i < count; i++) {
-        final int id = getRandomNumber();
-        final int randomNumber = getRandomNumber();
+          World[] worlds = new World[count];
 
 
-        try (final PreparedStatement select =
-                 connection.prepareStatement(SELECT_QUERY);
-             final PreparedStatement update =
-                 connection.prepareStatement(UPDATE_QUERY)) {
+          try (final Connection connection = dataSource.getConnection()) {
+            for (int i = 0; i < count; i++) {
+              final int id = getRandomNumber();
+              final int randomNumber = getRandomNumber();
 
 
-          // get
-          select.setInt(1, id);
+              try (final PreparedStatement select =
+                       connection.prepareStatement(SELECT_QUERY);
+                   final PreparedStatement update =
+                       connection.prepareStatement(UPDATE_QUERY)) {
 
 
-          try (final ResultSet set = select.executeQuery()) {
-            set.next();
+                // get
+                select.setInt(1, id);
 
 
-            // update
-            update.setInt(1, randomNumber);
-            update.setInt(2, id);
-            update.execute();
+                try (final ResultSet set = select.executeQuery()) {
+                  set.next();
 
 
-            worlds[i] = new World(id, set.getInt(2));
-            worlds[i].randomNumber = randomNumber;
+                  // update
+                  update.setInt(1, randomNumber);
+                  update.setInt(2, id);
+                  update.execute();
+
+                  worlds[i] = new World(id, set.getInt(2));
+                  worlds[i].randomNumber = randomNumber;
+                }
+              }
+            }
+          } catch (SQLException e) {
+            throw new IllegalStateException("Database error", e);
           }
           }
-        }
-      }
-    }
-    return worlds;
+          return worlds;
+        }, ctx.blockingTaskExecutor());
   }
   }
 }
 }

+ 58 - 46
frameworks/Java/armeria/src/main/java/hello/services/PostgresFortunesService.java

@@ -1,32 +1,36 @@
 package hello.services;
 package hello.services;
 
 
-import com.zaxxer.hikari.HikariDataSource;
-
-import hello.helpers.PostgresDbHelper;
-import hello.models.Fortune;
-import hello.helpers.HttpHeadersHelper;
-
-import java.io.InputStreamReader;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.IOException;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
 import java.sql.Connection;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
 
 
 import javax.sql.DataSource;
 import javax.sql.DataSource;
 
 
-import com.linecorp.armeria.common.HttpData;
+import com.github.mustachejava.DefaultMustacheFactory;
+import com.github.mustachejava.Mustache;
+import com.github.mustachejava.MustacheFactory;
+import com.zaxxer.hikari.HikariDataSource;
+
 import com.linecorp.armeria.common.HttpResponse;
 import com.linecorp.armeria.common.HttpResponse;
 import com.linecorp.armeria.common.HttpStatus;
 import com.linecorp.armeria.common.HttpStatus;
 import com.linecorp.armeria.common.MediaType;
 import com.linecorp.armeria.common.MediaType;
+import com.linecorp.armeria.server.ServiceRequestContext;
 import com.linecorp.armeria.server.annotation.Get;
 import com.linecorp.armeria.server.annotation.Get;
-import com.github.mustachejava.DefaultMustacheFactory;
-import com.github.mustachejava.Mustache;
-import com.github.mustachejava.MustacheFactory;
+
+import hello.helpers.PostgresDbHelper;
+import hello.models.Fortune;
 
 
 public class PostgresFortunesService {
 public class PostgresFortunesService {
   private static final String SELECT_QUERY = "SELECT * FROM fortune";
   private static final String SELECT_QUERY = "SELECT * FROM fortune";
@@ -44,43 +48,51 @@ public class PostgresFortunesService {
   }
   }
 
 
   @Get("/fortunes")
   @Get("/fortunes")
-  public HttpResponse fortunes() throws SQLException, IOException {
-    List<Fortune> fortunes = getFortunes();
-    fortunes.add(
-        new Fortune(0, "Additional fortune added at request time."));
-    fortunes.sort(Comparator.comparing(Fortune::getMessage));
-
-    return HttpResponse.of(
-        HttpHeadersHelper.getHttpHeader(MediaType.HTML_UTF_8),
-        HttpData.ofUtf8(buildMustacheTemplate(fortunes))
-        );
+  public CompletableFuture<HttpResponse> fortunes(ServiceRequestContext ctx) {
+    return getFortunes(ctx).thenApply(fortunes -> {
+      fortunes.add(
+          new Fortune(0, "Additional fortune added at request time."));
+      fortunes.sort(Comparator.comparing(Fortune::getMessage));
+
+      return HttpResponse.of(
+              HttpStatus.OK, MediaType.HTML_UTF_8, buildMustacheTemplate(fortunes));
+    });
   }
   }
 
 
-  private List<Fortune> getFortunes() throws SQLException {
-    List<Fortune> fortunes = new ArrayList<>();
-
-    try (final Connection connection = dataSource.getConnection();
-         final PreparedStatement statement =
-             connection.prepareStatement(SELECT_QUERY);
-         final ResultSet resultSet = statement.executeQuery()) {
-
-      while (resultSet.next()) {
-        fortunes.add(
-            new Fortune(
-                resultSet.getInt(1),
-                resultSet.getString(2)));
-      }
-    }
-    return fortunes;
+  private CompletableFuture<List<Fortune>> getFortunes(ServiceRequestContext ctx) {
+    return CompletableFuture.supplyAsync(
+        () -> {
+          List<Fortune> fortunes = new ArrayList<>();
+
+          try (final Connection connection = dataSource.getConnection();
+               final PreparedStatement statement =
+                   connection.prepareStatement(SELECT_QUERY);
+               final ResultSet resultSet = statement.executeQuery()) {
+
+            while (resultSet.next()) {
+              fortunes.add(
+                  new Fortune(
+                      resultSet.getInt(1),
+                      resultSet.getString(2)));
+            }
+          } catch (SQLException e) {
+            throw new IllegalStateException("Database error", e);
+          }
+          return fortunes;
+        }, ctx.blockingTaskExecutor()
+    );
   }
   }
 
 
-  private String buildMustacheTemplate(List<Fortune> fortunes)
-      throws IOException {
+  private byte[] buildMustacheTemplate(List<Fortune> fortunes) {
     Mustache mustache = mustacheFactory.compile("fortunes.mustache");
     Mustache mustache = mustacheFactory.compile("fortunes.mustache");
-    StringWriter stringWriter = new StringWriter();
+    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
 
 
-    mustache.execute(stringWriter, fortunes).flush();
+    try (Writer writer = new OutputStreamWriter(bytes, StandardCharsets.UTF_8)) {
+      mustache.execute(writer, fortunes);
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
 
 
-    return stringWriter.toString();
+    return bytes.toByteArray();
   }
   }
 }
 }

+ 13 - 0
frameworks/Java/armeria/src/main/resources/log4j2.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="WARN">
+  <Appenders>
+    <Console name="Console" target="SYSTEM_OUT">
+      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
+    </Console>
+  </Appenders>
+  <Loggers>
+    <Root level="info">
+      <AppenderRef ref="Console"/>
+    </Root>
+  </Loggers>
+</Configuration>