Skip to content

whelk-io/spring-boot-starter-data-logging

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

spring-boot-starter-data-logging

CodeFactor release

Spring-Boot starter for reducing logging boilerplate with Spring-AOP annotations. Takes advantage of tracing and logging capabilities in Spring-Data, Spring-Cloud-Sleuth, and Lombok.

This library is a pure AOP implementation without Java reflection, which allows for compilation on GraalVM and use on high performance frameworks such as Quarkus and Micronaut.


Basic Method Wrapper

Any method on a Spring managed bean can be wrapped with logging by annotating with @Log.Around.

@Component
public class SomeBean {

  @Log.Around
  public String someMethod(String param) {
    return "someReturn";
  }

}
2020-08-22 18:36:28,811 c.e.d.SomeBean DEBUG : before [method=someMethod, args=("someParam")]

2020-08-22 18:36:28,813 c.e.d.SomeBean DEBUG : after [method=someMethod, return="someReturn"]

Change Log Level

@Component
public class SomeBean {

  // change log level with @Log.{Level}.{Pointcut}
  @Log.Info.Around
  public String someMethod(String param) {
    return "foobar"
  }

  // or, on the @Log.{Pointcut} attribute
  @Log.Around(withLevel = Log.Level.Info)
  public String otherMethod() {
    return "foobar"
  }

}
2020-08-22 18:36:28,811 c.e.d.SomeBean INFO : before [method=someMethod, args=("someParam")]

2020-08-22 18:36:28,813 c.e.d.SomeBean INFO : after [method=someMethod, return="someReturn"]

2020-08-22 18:36:28,814 c.e.d.SomeBean INFO : before [method=otherMethod]

2020-08-22 18:36:28,814 c.e.d.SomeBean INFO : after [method=otherMethod, return="otherReturn"]

Additional Pointcuts

@Log.Before

// log before method is invoked
@Log.Before 
public String someMethod(String param) {
  return "someReturn";
}
2020-08-22 18:45:07,631 c.e.d.SomeBean DEBUG : before [method=someMethod, args=("someParam")]

@Log.After

// log after method has been invoked
@Log.After 
public String otherMethod() {
  return "otherReturn";
}
2020-08-22 18:45:07,634 c.e.d.SomeBean DEBUG : after [method=otherMethod]

@Log.AfterReturning

// log after method is invoked 
// and include any value returned
@Log.AfterReturning 
public String otherMethod() {
  return "otherReturn";
}
2020-08-22 18:48:58,171 c.e.d.SomeBean DEBUG : after [method=otherMethod, return="otherReturn"]

@Log.AfterThrowing

// log after method is invoked
// and only if exception is thrown
@Log.AfterThrowing
public String someMethod(String param) {
  throw new RuntimeException("some error");
}
2020-08-22 18:54:56,499 c.e.d.SomeBean ERROR : thrown [method=someMethod, exception=java.lang.RuntimeException, message=some error]

{stacktrace}

Log Arguments Using Jackson

@Log.Before(withArgs = 
    @Log.Args(withWriter = JacksonArgWriter.class))

@Log.AfterReturning(withReturnType = 
    @Log.ReturnType(withWriter = JacksonReturnTypeWriter.class))

public Foo someMethod(Foo foo) {
  return foo;
}
2020-08-23 11:31:13,865 c.e.d.SomeBean DEBUG : before [method=someMethod, args=({"name":"foo","description":"foobar"})]

2020-08-23 11:31:13,870 c.e.d.SomeBean DEBUG : after [method=someMethod, return={"name":"foo","description":"foobar"}]

ArgWriter and ReturnTypeWriter can be globally configured for all methods, see Global Configuration.


Method Configuration

@Log.Before

Log message (with method parameters) before method is invoked

Attribute Type Default Value Description
withLevel @Log.Level @Log.Level.Debug Level of message when logged
withArgs @Log.Args @Log.Args Configuration for writing method parameters

@Log.After

Log message after method is invoked.

Attribute Type Default Value Description
withLevel @Log.Level @Log.Level.Debug Level of message when logged
withReturnException @Log.ReturnException @Log.ReturnException Configuration for handling uncaught exceptions

@Log.AfterReturning

Log message with return value after method is invoked.

Attribute Type Default Value Description
withLevel @Log.Level @Log.Level.Debug Level of message when logged
withReturnType @Log.ReturnType @Log.ReturnType Configuration for writing value return from method
withReturnException @Log.ReturnException @Log.ReturnException Configuration for handling uncaught exceptions

@Log.AfterThrowing

Log message only after throwing an exception.

Attribute Type Default Value Description
withLevel @Log.Level @Log.Level.Debug Level of message when logged
withReturnException @Log.ReturnException @Log.ReturnException Configuration for handling uncaught exceptions

@Log.Around

Combines other annotations to wrap a method with logging before, after, and on exception.

Attribute Type Default Value Description
withLevel @Log.Level @Log.Level.Debug Level of message when logged
withArgs @Log.Args @Log.Args Configuration for writing method parameters
withReturnType @Log.ReturnType @Log.ReturnType Configuration for writing value return from method
withReturnException @Log.ReturnException @Log.ReturnException Configuration for handling uncaught exceptions

@Log.Args

Configuration for logging method parameters

Attribute Type Default Value Description
enabled boolean true Whether to log method parameters
withWriter ArgWriter SimpleArgWriter1 Converts method parameters to String for logging

1 See Global Configuration to change value for all logging annotations.


@Log.ReturnType

Configuration for logging any value returned from method.

Attribute Type Default Value Description
enabled boolean true Whether to log return type
withWriter ReturnTypeWriter SimpleReturnTypeWriter1 Converts return type to String for logging

1 See Global Configuration to change value for all logging annotations.


@Log.ReturnException

Configuration for logging any uncaught exception thrown by method.

Attribute Type Default Value Description
withStacktrace boolean true Whether to log stacktrace on exception
withOverride boolean true Whether to override withLevel with Log.Level.Error on method annotation when logging exception

1 See Global Configuration to change value for all logging annotations.


@Log.Level

Supported log levels.

Levels
Log.Level.Trace
Log.Level.Debug
Log.Level.Info
Log.Level.Warn
Log.Level.Error
Log.Level.Fatal

Global Configuration

By default, SimpleArgWriter and SimpleReturnTypeWriter are globally wired for method annotations. These can be changed by wiring a new @Primary @Bean for ArgWriter and ReturnTypeWriter repectively.

@Configuration
public class LogConfiguration {

  @Bean
  @Primary
  public ArgWriter argWriter(JacksonArgWriter jacksonArgWriter) {
    return jacksonArgWriter;
  }

  @Bean
  @Primary
  public ReturnTypeWriter returnTypeWriter(JacksonReturnTypeWriter jacksonReturnTypeWriter) {
    return jacksonReturnTypeWriter;
  }

}

Alternatively, custom writers which implement ArgWriter or ReturnTypeWriter can also be wired.


Auto-Logging with Spring-Data-Rest

When spring-boot-starter-data-rest is on the classpath, pointcuts are automatically applied to the default methods.

GET /employees

2020-08-23 13:28:26,064 tingRepository DEBUG : before [method=findAll, args=({"sort":{"sorted":false,"unsorted":true,"empty":true},"offset":0,"pageNumber":0,"pageSize":20,"paged":true,"unpaged":false})]

2020-08-23 13:28:26,073 tingRepository DEBUG : after [method=findAll, return={"content":[{"id":1,"name":"Alan Turing"}],"pageable":{"sort":{"sorted":false,"unsorted":true,"empty":true},"offset":0,"pageNumber":0,"pageSize":20,"paged":true,"unpaged":false},"last":true,"totalPages":1,"totalElements":1,"size":20,"number":0,"sort":{"sorted":false,"unsorted":true,"empty":true},"numberOfElements":1,"first":true,"empty":false}]

GET /employees/1

2020-08-23 13:23:51,586 CrudRepository DEBUG : before [method=findById, args=(1)]

2020-08-23 13:23:51,611 CrudRepository DEBUG : after [method=findById, return={"id":1,"name":"Alan Turing"}]

POST /employees

2020-08-23 13:22:07,634 CrudRepository DEBUG : before [method=save, args=({"name":"Alan Turing"})]

2020-08-23 13:22:07,646 CrudRepository DEBUG : after [method=save, return={"id":1,"name":"Alan Turing"}]

PATCH /employees/1

2020-08-23 13:27:02,567 CrudRepository DEBUG : before [method=save, args=({"id":1,"name":"Alan Turing"})]

2020-08-23 13:27:02,580 CrudRepository DEBUG : after [method=save, return={"id":1,"name":"Alan Turing"}]

PUT /employees/1

2020-08-23 13:26:10,042 CrudRepository DEBUG : before [method=save, args=({"id":1,"name":"Alan Turing"})]

2020-08-23 13:26:10,055 CrudRepository DEBUG : after [method=save, return={"id":1,"name":"Alan Turing"}]

DELETE /employees/1

2020-08-23 13:25:28,326 CrudRepository DEBUG : before [method=deleteById, args=(1)]

2020-08-23 13:25:28,341 CrudRepository DEBUG : after [method=deleteById]

Auto-Logging with Spring-Data-JPA

When spring-boot-starter-data-jpa is on the classpath, the inherited methods of JpaRepository<T,ID> are automatically applied.

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> { }
@Service
@RequiredArgsConstructor
public class EmployeeService {

  private final EmployeeRepository employeeRepository;

    public Optional<Employee> findEmployeeByName(String name) {
        var exampleEmployee = new Employee();
        exampleEmployee.setName(name);

        // findOne(..) from JpaRepository automatically pointcut for logs
        return employeeRepository.findOne(Example.of(exampleEmployee));
    }

}
2020-08-23 13:48:43.697 QueryByExampleExecutor DEBUG : before [method=findOne, args=({"probe":{"name":"Alan Turing"},"matcher":{"nullHandler":"IGNORE","defaultStringMatcher":"DEFAULT","propertySpecifiers":{"specifiers":[]},"ignoredPaths":[],"ignoreCaseEnabled":false,"matchMode":"ALL","allMatching":true,"anyMatching":false},"probeType":"com.example.demo.model.Employee"})]

2020-08-23 13:48:43.705 QueryByExampleExecutor DEBUG : after [method=findOne, return={"id":1,"name":"Alan Turing"}]

Auto-Logging with Spring-Cloud-Sleuth

When spring-cloud-starter-sleuth is on the classpath with spring-boot-starter-data-rest, spans are automatically applied to all repository methods.

POST /employees

2020-08-23 13:33:48.358 [demo,18aa9a69178dcc3f,e555838da7405451] CrudRepository DEBUG: before [method=save, args=({"name":"Alan Turing"})]

2020-08-23 13:33:48.370 [demo,18aa9a69178dcc3f,e555838da7405451] CrudRepository DEBUG : after [method=save, return={"id":1,"name":"Alan Turing"}]

Supported Dependencies

Package Version
Spring-Boot-Starter 2.3.1-RELEASE
Spring-Boot-Starter-AOP 2.3.1-RELEASE 1
Spring-Boot-Starter-Data-Rest 2.3.1-RELEASE 1
Spring-Boot-Starter-Data-JPA 2.3.1-RELEASE 1
Spring-Boot-Starter-Data-MongoDB 2.3.1-RELEASE 1
Spring-Cloud Hoxton.SR6
Spring-Cloud-Starter-Sleuth 2.2.3.RELEASE 2
Lombok 1.18.12 1
Jackson-Databind 2.11.0 1
Java 11

1 Dependency versioning inherited from Spring-Boot-Starter.

2 Dependency versioning inherited from Spring-Cloud.


Maven Integration

<dependency>
    <groupId>io.whelk.spring.data.logging</groupId>
    <artifactId>spring-boot-starter-data-logging</artifactId>
    <version>${spring-boot-starter-data-logging.version}</version>
</dependency>

About

Spring-Boot starter for reducing logging boilerplate with Spring-AOP annotations. Takes advantage of tracing and logging capabilities in Spring-Data, Spring-Cloud-Sleuth, and Lombok.

Topics

Resources

License

Stars

Watchers

Forks

Languages