From 579ba7726f33c0e85510fe62f589644d1fe471e6 Mon Sep 17 00:00:00 2001 From: Gaetano Piazzolla Date: Mon, 8 May 2023 17:29:52 +0200 Subject: [PATCH] BAEL-6444 | Added P6Spy logging in spring boot observation module. (#13965) * BAEL-6444 | Added P6Spy logging in spring boot observation module. * BAEL-6444 | Added Find with name query and custom log format now working * BAEL-6444 | Formatting * BAEL-6444 | Renaming junit files * BAEL-6444 | Added start class * BAEL-6444 | Actualized code with Article * BAEL-6444 | Actualized code with Article * BAEL-6444 | redded commit() * BAEL-6444 | BDD naming strategy --- .../spring-boot-3-observation/pom.xml | 23 ++++++++ .../p6spy/SampleP6SpyApplication.java | 29 ++++++++++ .../p6spy/controllers/JDBCController.java | 54 +++++++++++++++++++ .../p6spy/controllers/StudentController.java | 29 ++++++++++ .../baeldung/p6spy/repository/Student.java | 53 ++++++++++++++++++ .../p6spy/repository/StudentRepository.java | 11 ++++ .../src/main/resources/spy.properties | 36 +++++++++++++ .../p6spy/JDBCControllerIntegrationTest.java | 53 ++++++++++++++++++ ...SampleP6SpyApplicationIntegrationTest.java | 49 +++++++++++++++++ .../src/test/resources/spy.properties | 3 ++ 10 files changed, 340 insertions(+) create mode 100644 spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/SampleP6SpyApplication.java create mode 100644 spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/controllers/JDBCController.java create mode 100644 spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/controllers/StudentController.java create mode 100644 spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/repository/Student.java create mode 100644 spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/repository/StudentRepository.java create mode 100644 spring-boot-modules/spring-boot-3-observation/src/main/resources/spy.properties create mode 100644 spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/p6spy/JDBCControllerIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/p6spy/SampleP6SpyApplicationIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-3-observation/src/test/resources/spy.properties diff --git a/spring-boot-modules/spring-boot-3-observation/pom.xml b/spring-boot-modules/spring-boot-3-observation/pom.xml index ed613ee98e..ddd81e3ca4 100644 --- a/spring-boot-modules/spring-boot-3-observation/pom.xml +++ b/spring-boot-modules/spring-boot-3-observation/pom.xml @@ -54,6 +54,25 @@ org.springframework.boot spring-boot-starter-aop + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-jdbc + + + + com.github.gavlyukovskiy + p6spy-spring-boot-starter + 1.9.0 + + + com.h2database + h2 + runtime + org.springframework.boot spring-boot-devtools @@ -63,4 +82,8 @@ + + com.baeldung.samples.SimpleObservationApplication + + diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/SampleP6SpyApplication.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/SampleP6SpyApplication.java new file mode 100644 index 0000000000..2be1255d72 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/SampleP6SpyApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.baeldung.p6spy; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleP6SpyApplication { + + public static void main(String[] args) { + SpringApplication.run(SampleP6SpyApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/controllers/JDBCController.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/controllers/JDBCController.java new file mode 100644 index 0000000000..d09e839165 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/controllers/JDBCController.java @@ -0,0 +1,54 @@ +package com.baeldung.p6spy.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("jdbc") +public class JDBCController { + + @Autowired + private DataSource dataSource; + + @RequestMapping("/commit") + public List> select() { + List> results = new ArrayList<>(); + try { + Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement(); + statement.executeQuery("SELECT * FROM student"); + connection.commit(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + return results; + } + + @RequestMapping("/rollback") + public List> rollback() { + List> results = new ArrayList<>(); + try (Connection connection = dataSource.getConnection()) { + connection.rollback(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + return results; + } + + @RequestMapping("/query-error") + public void error() { + try (Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement()) { + statement.execute("SELECT UNDEFINED()"); + } catch (Exception ignored) { + } + } +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/controllers/StudentController.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/controllers/StudentController.java new file mode 100644 index 0000000000..d60fd8b52e --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/controllers/StudentController.java @@ -0,0 +1,29 @@ +package com.baeldung.p6spy.controllers; + +import com.baeldung.p6spy.repository.Student; +import com.baeldung.p6spy.repository.StudentRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("student") +public class StudentController { + + @Autowired + private StudentRepository repository; + + @RequestMapping("/save") + public Long save() { + return repository.save(new Student("Pablo", "Picasso")).getId(); + } + + @RequestMapping("/find/{name}") + public List getAll(@PathVariable String name) { + return repository.findAllByFirstName(name); + } + +} diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/repository/Student.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/repository/Student.java new file mode 100644 index 0000000000..881f9409b8 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/repository/Student.java @@ -0,0 +1,53 @@ +package com.baeldung.p6spy.repository; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +@Entity +public class Student { + + @Id + @GeneratedValue + private Long id; + + private String firstName; + private String lastName; + + public Student() { + } + + public Student(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return "Student{" + "id=" + id + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + '}'; + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/repository/StudentRepository.java b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/repository/StudentRepository.java new file mode 100644 index 0000000000..90d2c22877 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/java/com/baeldung/p6spy/repository/StudentRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.p6spy.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface StudentRepository extends JpaRepository { + List findAllByFirstName(String firstName); +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-observation/src/main/resources/spy.properties b/spring-boot-modules/spring-boot-3-observation/src/main/resources/spy.properties new file mode 100644 index 0000000000..c14d381836 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/main/resources/spy.properties @@ -0,0 +1,36 @@ +# specifies the appender to use for logging +# Please note: reload means forgetting all the previously set +# settings (even those set during runtime - via JMX) +# and starting with the clean table +# (only the properties read from the configuration file) +# (default is com.p6spy.engine.spy.appender.FileLogger) +#appender=com.p6spy.engine.spy.appender.Slf4JLogger +#appender=com.p6spy.engine.spy.appender.StdoutLogger +appender=com.p6spy.engine.spy.appender.FileLogger + +# name of logfile to use, note Windows users should make sure to use forward slashes in their pathname (e:/test/spy.log) +# (used for com.p6spy.engine.spy.appender.FileLogger only) +# (default is spy.log) +logfile=database.log + +# append to the p6spy log file. if this is set to false the +# log file is truncated every time. (file logger only) +# (default is true) +append=true + +# class to use for formatting log messages (default is: com.p6spy.engine.spy.appender.SingleLineFormat) +logMessageFormat=com.p6spy.engine.spy.appender.CustomLineFormat + +# Custom log message format used ONLY IF logMessageFormat is set to com.p6spy.engine.spy.appender.CustomLineFormat +# default is %(currentTime)|%(executionTime)|%(category)|connection%(connectionId)|%(sqlSingleLine) +# Available placeholders are: +# %(connectionId) the id of the connection +# %(currentTime) the current time expressing in milliseconds +# %(executionTime) the time in milliseconds that the operation took to complete +# %(category) the category of the operation +# %(effectiveSql) the SQL statement as submitted to the driver +# %(effectiveSqlSingleLine) the SQL statement as submitted to the driver, with all new lines removed +# %(sql) the SQL statement with all bind variables replaced with actual values +# %(sqlSingleLine) the SQL statement with all bind variables replaced with actual values, with all new lines removed +customLogMessageFormat=%(currentTime)|%(executionTime)|%(category)|%(sqlSingleLine) + diff --git a/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/p6spy/JDBCControllerIntegrationTest.java b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/p6spy/JDBCControllerIntegrationTest.java new file mode 100644 index 0000000000..433641fcb0 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/p6spy/JDBCControllerIntegrationTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.baeldung.p6spy; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.client.RestTemplate; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +class JDBCControllerIntegrationTest { + + private final RestTemplate restTemplate = new RestTemplate(); + @Value("http://localhost:${local.server.port}/jdbc") + private String localhost; + + @Test + void testJdbcCommitRESTMethod_isSuccessful() { + Assertions.assertTrue(restTemplate.getForEntity(localhost + "/commit", String.class) + .getStatusCode().is2xxSuccessful()); + } + + @Test + void jdbcRollbackRESTMethod_isSuccessful() { + Assertions.assertTrue(restTemplate.getForEntity(localhost + "/rollback", String.class) + .getStatusCode().is2xxSuccessful()); + } + + @Test + void jdbcQueryErrorRESTMethod_isSuccessful() { + Assertions.assertTrue(restTemplate.getForEntity(localhost + "/query-error", String.class) + .getStatusCode().is2xxSuccessful()); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/p6spy/SampleP6SpyApplicationIntegrationTest.java b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/p6spy/SampleP6SpyApplicationIntegrationTest.java new file mode 100644 index 0000000000..ba6dd43195 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/test/java/com/baeldung/p6spy/SampleP6SpyApplicationIntegrationTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.baeldung.p6spy; + +import com.github.gavlyukovskiy.boot.jdbc.decorator.DecoratedDataSource; +import com.github.gavlyukovskiy.boot.jdbc.decorator.p6spy.P6SpyDataSourceDecorator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import javax.sql.DataSource; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(SpringExtension.class) +@SpringBootTest +class SampleP6SpyApplicationIntegrationTest { + + @Autowired + private DataSource dataSource; + + @Test + void whenP6SpyEnabled_datasourceIsDecorated() { + assertThat(dataSource).isInstanceOf(DecoratedDataSource.class); + } + + @Test + void whenP6SpyEnabled_decoratingChainContainsP6Spy() { + DecoratedDataSource decoratedDataSource = (DecoratedDataSource) dataSource; + assertThat(decoratedDataSource.getDecoratingChain().get(0).getDataSourceDecorator()).isInstanceOf(P6SpyDataSourceDecorator.class); + } + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-observation/src/test/resources/spy.properties b/spring-boot-modules/spring-boot-3-observation/src/test/resources/spy.properties new file mode 100644 index 0000000000..ea4525df98 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-observation/src/test/resources/spy.properties @@ -0,0 +1,3 @@ +# specifies the appender to use for logging. +# used to avoid the creation of logging file with tests. +appender=com.p6spy.engine.spy.appender.StdoutLogger \ No newline at end of file