[JAVA] Control log output with Doma2

It is [null] in charge of the 4th day (https://qiita.com/YujiSoftware/items/2dc002977e730a3293fd#%E3%81%BE%E3%81%A8%E3%82%81).

By default, a lot of logs are output at the INFO level, so control that.

environment

Java

openjdk 11.0.1 2018-10-16

Doma2

2.19.3

doma-spring-boot

1.1.1

Spring Boot

2.1.1

Source (part)

build.gradle


buildscript {
	ext {
		springBootVersion = '2.1.1.RELEASE'
	}
	repositories {
		mavenCentral()
	}
	dependencies {
		classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
	}
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

sourceCompatibility = 11
targetCompatibility = 11

compileJava.options.encoding = "UTF-8"

repositories {
	mavenCentral()
}

dependencies {
	implementation('org.springframework.boot:spring-boot-starter-jdbc')
	implementation('org.seasar.doma.boot:doma-spring-boot-starter:1.1.1') {
		exclude group: 'org.seasar.doma', module: 'doma'
	}
	implementation('org.seasar.doma:doma:2.19.3')
	runtimeOnly('com.h2database:h2')
}

processResources.destinationDir = compileJava.destinationDir
compileJava.dependsOn processResources

TestTable.java


package sample.springboot.doma2;

import org.seasar.doma.Entity;
import org.seasar.doma.GeneratedValue;
import org.seasar.doma.GenerationType;
import org.seasar.doma.Id;
import org.seasar.doma.Table;

@Table(name = "TEST_TABLE")
@Entity
public class TestTable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long id;
    public String name;

    @Override
    public String toString() {
        return "TestTable{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

TestTableDao.java


package sample.springboot.doma2;

import org.seasar.doma.Dao;
import org.seasar.doma.Insert;
import org.seasar.doma.Select;
import org.seasar.doma.boot.ConfigAutowireable;

import java.util.List;

@Dao
@ConfigAutowireable
public interface TestTableDao {
    
    @Select
    List<TestTable> findAll();
    
    @Insert
    int insert(TestTable testTable);
}

Doma2Application.java


package sample.springboot.doma2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Doma2Application {

	public static void main(String[] args) {
		try (ConfigurableApplicationContext context = SpringApplication.run(Doma2Application.class, args)) {
			TestTableDao dao = context.getBean(TestTableDao.class);

			System.out.println(dao.findAll());

			TestTable foo = new TestTable();
			foo.name = "foo";
			dao.insert(foo);

			TestTable bar = new TestTable();
			bar.name = "bar";
			dao.insert(bar);

			System.out.println(dao.findAll());
		}
	}
}

Execution result

2018-12-03 22:32:25.979  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2220] ENTER  :class=[sample.springboot.doma2.TestTableDaoImpl],Method=[findAll]
2018-12-03 22:32:26.038  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2076]SQL log:SQL file=[META-INF/sample/springboot/doma2/TestTableDao/findAll.sql],
SELECT *
  FROM TEST_TABLE
2018-12-03 22:32:26.049  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2221] EXIT   :class=[sample.springboot.doma2.TestTableDaoImpl],Method=[findAll]
[]
2018-12-03 22:32:26.049  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2220] ENTER  :class=[sample.springboot.doma2.TestTableDaoImpl],Method=[insert]
2018-12-03 22:32:26.068  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2076]SQL log:SQL file=[null],
insert into TEST_TABLE (id, name) values (null, 'foo')
2018-12-03 22:32:26.071  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2221] EXIT   :class=[sample.springboot.doma2.TestTableDaoImpl],Method=[insert]
2018-12-03 22:32:26.072  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2220] ENTER  :class=[sample.springboot.doma2.TestTableDaoImpl],Method=[insert]
2018-12-03 22:32:26.072  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2076]SQL log:SQL file=[null],
insert into TEST_TABLE (id, name) values (null, 'bar')
2018-12-03 22:32:26.072  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2221] EXIT   :class=[sample.springboot.doma2.TestTableDaoImpl],Method=[insert]
2018-12-03 22:32:26.072  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2220] ENTER  :class=[sample.springboot.doma2.TestTableDaoImpl],Method=[findAll]
2018-12-03 22:32:26.073  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2076]SQL log:SQL file=[META-INF/sample/springboot/doma2/TestTableDao/findAll.sql],
SELECT *
  FROM TEST_TABLE
2018-12-03 22:32:26.075  INFO 24784 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2221] EXIT   :class=[sample.springboot.doma2.TestTableDaoImpl],Method=[findAll]
[TestTable{id=1, name='foo'}, TestTable{id=2, name='bar'}]

By default, there are a lot of logs about Doma2 at the INFO level. Since it is not possible to move it in production as it is, output to DEBUG level and control various things.

Doma2 log output mechanism

doma2.jpg

--Doma2 log output is done via the JdbcLogger interface. --As an implementation class, ʻUtilLoggingJdbcLoggerthat usesjava.util.logging.Loggerby default is provided. --If you are using Spring Boot, SLF4J will eventually output logs even if you are usingjava.util.logging.Logger`. --For that, please refer to How jul-to-slf4j works-- Qiita

AbstractJdbcLogger.java


package org.seasar.doma.jdbc;

...

public abstract class AbstractJdbcLogger<LEVEL> implements JdbcLogger {

    /**Default log level*/
    protected LEVEL defaultLevel;

    protected AbstractJdbcLogger(LEVEL level) {
        if (level == null) {
            throw new DomaNullPointerException("level");
        }
        this.defaultLevel = level;
    }

    @Override
    public void logDaoMethodEntering(String callerClassName,
            String callerMethodName, Object... args) {
        logDaoMethodEntering(callerClassName, callerMethodName, args,
                defaultLevel, () -> Message.DOMA2220.getMessage( //★ Passing the log level of the instance field
                        callerClassName, callerMethodName));
    }

    protected void logDaoMethodEntering(String callerClassName,
            String callerMethodName, Object args[], LEVEL level,
            Supplier<String> messageSupplier) {
        log(level, callerClassName, callerMethodName, null, messageSupplier);
    }

...

--For example, logDaoMethodEntering () prints the log when Dao's method is started. --This method calls logDaoMethodEntering () which is protected and passes the default log level (defaultLevel) of the instance field to the log level (LEVEL) of the argument. --ʻAbstractJdbcLoggerdefines many other logging methods when Dao is executed, but they all have the same structure. --In other words, the default is to output logs at the log level set indefaultLevel of ʻAbstractJdbcLogger. --And the location where the default log level in question is set is in ʻUtilLoggingJdbcLogger`

UtilLoggingJdbcLogger.java


package org.seasar.doma.jdbc;

...

public class UtilLoggingJdbcLogger extends AbstractJdbcLogger<Level> {

    /**The logger used in this instance.*/
    protected final Logger logger;

    ...
    public UtilLoggingJdbcLogger() {
        this(Level.INFO); //★ INFO level when generated by default constructor
    }

    ...
    public UtilLoggingJdbcLogger(Level level) {
        this(level, Logger.getLogger(UtilLoggingJdbcLogger.class.getName()));
    }

    ...

--If ʻUtilLoggingJdbcLoggeris generated with the default constructor, the log level will be INFO --If you do not explicitly specify an instance ofJdbcLogger in the Doma2 settings, ʻUtilLoggingJdbcLogger is generated by the default constructor, resulting in all log output levels being INFO.

Change the default log output level

If you are using doma-spring-boot, you can configure Doma2 using DomaConfigBuilder.

Doma2Application.java


package sample.springboot.doma2;

import org.seasar.doma.boot.autoconfigure.DomaConfigBuilder;
import org.seasar.doma.jdbc.JdbcLogger;
import org.seasar.doma.jdbc.UtilLoggingJdbcLogger;
...
import org.springframework.context.annotation.Bean;

import java.util.logging.Level;

@SpringBootApplication
public class Doma2Application {

	public static void main(String[] args) {
		try (ConfigurableApplicationContext context = SpringApplication.run(Doma2Application.class, args)) {
			...
		}
	}
	
	@Bean
	public JdbcLogger jdbcLogger() {
		return new UtilLoggingJdbcLogger(Level.FINE); //★ Generated with log level set to FINE
	}

	@Bean
	public DomaConfigBuilder domaConfigBuilder() {
		DomaConfigBuilder builder = new DomaConfigBuilder();
		builder.jdbcLogger(jdbcLogger()); //★ Set jdbcLogger
		return builder;
	}
}

Execution result


[]
[TestTable{id=1, name='foo'}, TestTable{id=2, name='bar'}]

--Formed by setting the log level to FINE in the constructor argument of ʻUtilLoggingJdbcLogger, and set it to jdbcLogger () of DomaConfigBuilder. --The log output level is now FINE(DEBUG level in SLF4J etc.), so the log is no longer output. --The correspondence between the log level ofjava.util.logging.Logger and the log level of SLF4J is [Javadoc] of SLF4JBridgeHandler` (https://www.slf4j.org/api/org/slf4j/bridge/SLF4JBridgeHandler. See html)

Change the log output level for each method

If you want to output only a specific log at a level different from the default log level, such as "I want to output only SQL output at the INFO level", I probably do the following.

MyJdbcLogger.java


package sample.springboot.doma2;

import org.seasar.doma.jdbc.Sql;
import org.seasar.doma.jdbc.UtilLoggingJdbcLogger;

import java.util.function.Supplier;
import java.util.logging.Level;

//★ Create your own logger by inheriting UtilLoggingJdbcLogger
public class MyJdbcLogger extends UtilLoggingJdbcLogger {
    
    public MyJdbcLogger() {
        super(Level.FINE); //★ The default log level is FINE
    }

    //★ Override the logging method that outputs SQL
    @Override
    protected void logSql(String callerClassName, String callerMethodName, Sql<?> sql, Level level, Supplier<String> messageSupplier) {
        //★ Argument level(Default log level)Ignore and forcibly replace with INFO
        super.logSql(callerClassName, callerMethodName, sql, Level.INFO, messageSupplier);
    }
}

Doma2Application.java


package sample.springboot.doma2;

...

@SpringBootApplication
public class Doma2Application {

	public static void main(String[] args) {
		try (ConfigurableApplicationContext context = SpringApplication.run(Doma2Application.class, args)) {
			...
		}
	}
	
	@Bean
	public JdbcLogger jdbcLogger() {
		return new MyJdbcLogger(); //★ Use your own logger
	}

	@Bean
	public DomaConfigBuilder domaConfigBuilder() {
		DomaConfigBuilder builder = new DomaConfigBuilder();
		builder.jdbcLogger(jdbcLogger());
		return builder;
	}
}

Execution result


2018-12-03 23:09:34.627  INFO 18180 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2076]SQL log:SQL file=[META-INF/sample/springboot/doma2/TestTableDao/findAll.sql],
SELECT *
  FROM TEST_TABLE
[]
2018-12-03 23:09:34.656  INFO 18180 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2076]SQL log:SQL file=[null],
insert into TEST_TABLE (id, name) values (null, 'foo')
2018-12-03 23:09:34.660  INFO 18180 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2076]SQL log:SQL file=[null],
insert into TEST_TABLE (id, name) values (null, 'bar')
2018-12-03 23:09:34.661  INFO 18180 --- [           main] o.s.doma.jdbc.UtilLoggingJdbcLogger      : [DOMA2076]SQL log:SQL file=[META-INF/sample/springboot/doma2/TestTableDao/findAll.sql],
SELECT *
  FROM TEST_TABLE
[TestTable{id=1, name='foo'}, TestTable{id=2, name='bar'}]

--Make your own logger by inheriting ʻUtilLoggingJdbcLogger --And you are overriding the logging method you want to change the log level (protected`) and replacing it with the level you want to change the log level. --Now, only the replaced logging method will be output at a different log level.

reference

-Java-[doma2] [Spring Boot] I don't know how to set the SQL log non-output. | teratail --Adapter to Log Output Library | Settings — Doma 2.0 Documentation


That's all for tomorrow's Java Advent Calendar, null.
</ del> Someone! write! !! !! !! </ del>

Tomorrow's charge will be @orekyuu.

Recommended Posts

Control log output with Doma2
Replaced Tomcat 8.5 log output with Log4j2.8 or later
About Java log output
Build Doma1 with Ant
Output FizzBuzz with stream
Output log to external file with slf4j + logback with Maven
csv file output with opencsv
Log output in Json format using lograge / lograge-sql with RubyOnRails
Version control Java with SDKMAN
CSV output with Apache Commons CSV
Java version control with jenv
Java standard log output sample
Version control CocoaPods with Docker
Output "Izumi Oishi" with dokojava
Output Excel with formulas with XlsMapper
A story stuck with log output in Docker + Play framework environment
Output characters like conversation with JavaFX
Database linkage with doma2 (Spring boot)
Log output to file in Java
[SRE / Docker] Start control with Dockerize
Output PDF and TIFF with Java 8
Log output of WebServiceTemplate request / response
Spring Data JPA SQL log output