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
This commit is contained in:
Gaetano Piazzolla 2023-05-08 17:29:52 +02:00 committed by GitHub
parent e16bd13cc8
commit 579ba7726f
10 changed files with 340 additions and 0 deletions

View File

@ -54,6 +54,25 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- get latest version from https://github.com/gavlyukovskiy/spring-boot-data-source-decorator/releases-->
<dependency>
<groupId>com.github.gavlyukovskiy</groupId>
<artifactId>p6spy-spring-boot-starter</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
@ -63,4 +82,8 @@
</dependencies>
<properties>
<start-class>com.baeldung.samples.SimpleObservationApplication</start-class>
</properties>
</project>

View File

@ -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);
}
}

View File

@ -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<Map<String, String>> select() {
List<Map<String, String>> 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<Map<String, String>> rollback() {
List<Map<String, String>> 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) {
}
}
}

View File

@ -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<Student> getAll(@PathVariable String name) {
return repository.findAllByFirstName(name);
}
}

View File

@ -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 + '\'' + '}';
}
}

View File

@ -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<Student, Long> {
List<Student> findAllByFirstName(String firstName);
}

View File

@ -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)

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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