Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

GitHub Maven Central

Build Status Hits of Code Lines of Code


EasyLog is an open source library for logging/debugging in Java projects.

Table of Contents


EasyLog allows you to start logging any method or all class's methods by adding just one annotation @LogIt.

    public Universe bigBang(int numberOfStars) {

You'll get following

13:36:06.021 [main] INFO  UneasyLogger - 
-> public Universe Universe.bigBang(int numberOfStars)
"numberOfStars": 1

13:36:06.205 [main] INFO  UneasyLogger - 
Execution/Response time:  162ms
<- Universe Universe.bigBang(int numberOfStars)
  "stars": [
      "name": "Star-b90637a4-81bb-4c46-9c05-99ecf2dc0502",
      "type": "RED_GIANT",
      "planets": [
          "name": "Planet-c5308178-4ebe-46c6-a02a-f78d489afc99",
          "haveSatellites": true
  "dateOfCreation": "Jun 29, 2018 1:36:06 PM"

You can use many features to customize your log output.

For example you can mask one or several field or subfield values (@LogIt(maskFields = {"dateOfCreation"})) then every time when dateOfCreation appears in logs it's value will be replaced with XXXMASKEDXXX

Quick Start

See how to setup EasyLog in example projects

Spring Projects


First, you need to setup your parent project


Second, you need to add 2 dependencies


If your project already has a different parent project (that project also has to pe a Spring project as well) you might not need spring-boot-starter-aop - just check

Extend EasyLogger

In your project create the class that extends the EasyLogger aspect and add the @Component annotation.

import io.lenar.easy.log.EasyLogger;
import org.springframework.stereotype.Component;

public class MyLogger extends EasyLogger {

back to Table of Contents

Non-Spring Projects


First, you need to add io.lenar:easy-log:{{ site.easylog_version }} dependency


Second setup build:plugins


Extend EasyLoggerNoSpring

public class MyLogger extends EasyLoggerNoSpring {

    @Around("execution(* *(..)) && @within(annotation)")
    public Object classLog(ProceedingJoinPoint jp, LogIt annotation) throws Throwable {
        return logItClassLevel(jp, annotation);

    @Around("execution(* *(..)) && @annotation(annotation)")
    public Object methodLog(ProceedingJoinPoint jp, LogIt annotation) throws Throwable {
        return logItMethodLevel(jp, annotation);

    @AfterThrowing(pointcut = "execution(* *(..)) && @within(annotation)", throwing = "e")
    public void classExceptionLog(JoinPoint jp, LogIt annotation, Throwable e) {
        logExceptionClassLevel(jp, annotation, e);

    @AfterThrowing(pointcut = "execution(* *(..)) && @annotation(annotation)", throwing = "e")
    public void methodExceptionLog(JoinPoint jp, LogIt annotation, Throwable e) {
        logExceptionMethodLevel(jp, annotation, e);


Just copy and past.

If you use IntelliJ make sure that you use AJC compiler if this wasn't set automatically. Also you may need to clear target folder (mvn clean or just right click and delete on it).

Maven commands work as expected.

back to Table of Contents

@LogIt annotation

Annotate the methods that you want to log with @LogIt annotation

public User createUser(CreateUserForm form) {

If you need to log all methods of a class you can annotate the class with @LogIt annotation

public class ClassWithMethods {

Note: If you use @LogIt for a method and for a class, class's one will be ignored.

back to Table of Contents

Logging Level

You can set the logging level by passing the parameter level with @LogIt annotation.

Available options: DEBUG, INFO, WARN, ERROR

By default level=Level.INFO

back to Table of Contents


Labels help you to simplify a search for specific entries in the logs. Just pass another annotation parameter String label.

Exclude parameters from logging

You can skip some parameters and not log them with String[] ignoreParameters.

By default there is no ignored parameter.

Mask fields

String[] maskFields() default {} - allows to replace actual values for field names for the results returned by the method with "XXXMASKEDXXX".

Note: We don't modify returned results, just customize how the results look in the logs.

By default there is no masked field.

Might be used for:

  • masking any sensitive information that shouldn't be logged
  • decreasing the amount of logged info. For example we can replace huge lists/arrays (in returned results) that are not important in terms of logging with "XXXMASKEDXXX"

back to Table of Contents

Logging Styles



Here PRETTY_PRINT means "pretty printed JSON".

COMPACT_WITH_NULLS and MINIMAL also mean JSON but not "pretty printed"

See the difference





Use PRETTY_PRINT_WITH_NULLS and COMPACT_WITH_NULLS if you want to log (serialize nulls)

Use PRETTY_PRINT_NO_NULLS and MINIMAL if you want to exclude nulls from logging.

AS_IS is used if you want to serialize the parameters and returned result with the toString method. In this case maskFields will be ignored

back to Table of Contents


If the method annotated with @LogIt (or belongs to the class annotated with LogIt) throws an exception, it will be logged like this

14:17:54.359 [main] ERROR  io.lenar.easy.log.ExceptionLogger - java.lang.ArithmeticException: / by zero 
 <- Universe.getStarsBeforeBigBang(): 
java.lang.ArithmeticException: / by zero
	at io.lenar.examples.model.Universe.getStarsBeforeBigBang_aroundBody4( [classes/:na]
	at io.lenar.examples.model.Universe$ ~[classes/:na]
	at org.aspectj.runtime.reflect.JoinPointImpl.proceed( ~[aspectjrt-1.8.7.jar:na]
	at io.lenar.easy.log.UneasyLogger.logMethod( ~[easy-log-1.1.5-SNAPSHOT.jar:na]
	at io.lenar.easy.log.EasyLoggerNoSpring.logItMethodLevel( ~[easy-log-1.1.5-SNAPSHOT.jar:na]
	at io.lenar.examples.log.MyLogger.methodLog( ~[classes/:na]
	at io.lenar.examples.model.Universe.getStarsBeforeBigBang( [classes/:na]
	at io.lenar.examples.LoggerTest.exceptionTest( [test-classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_152]
	at sun.reflect.NativeMethodAccessorImpl.invoke( ~[na:1.8.0_152]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke( ~[na:1.8.0_152]
	at java.lang.reflect.Method.invoke( ~[na:1.8.0_152]


EasyLog logs WebApplicationExceptions different way.

So if a service call throws the WebApplicationException exception then we will be also able to log error messages.

For example

08:34:40.439 [main] INFO  UneasyLogger - 
-> public LoginResponse AuthServiceClient.login(LoginRequest request)
request: {
  "password": "passasdfasdf",
  "loginID": ""

08:34:40.682 [main] ERROR io.lenar.easy.log.ExceptionLogger - HTTP 403 Forbidden
AUTH SERVICE CLIENT <- AuthServiceClient.login(..): 
{"errorMessage":"Invalid LoginID","errorDetail":"invalid loginID or password","errorCode":403}

Retry on Exception

If you need to retry a method on some specific exception or exceptions then you can use these parameters to setup the retry functionality.

Class<? extends Throwable>[] retryExceptions() default {} - a list of exceptions to retry on.

int retryAttempts() default 1 - retry retryAttempts times.

long retryDelay() default 0 - time delay between attempts in ms.

These parameters can be set for each method individually.

Retry Example

@LogIt(retryExceptions = {ForbiddenException.class, BadRequestException.class}, 
	retryDelay = 1000, 
	retryAttempts = 3)

In the logs you will see

16:26:43.969 [main] ERROR io.lenar.easy.log.UneasyLogger - HTTP 400 Bad Request 
 <- UserService.findUser(..)
Retry 1/3 in 1000 ms
16:26:45.017 [main] ERROR io.lenar.easy.log.UneasyLogger - HTTP 400 Bad Request 
 <- UserService.findUser(..)
Retry 2/3 in 1000 ms
16:26:46.063 [main] ERROR io.lenar.easy.log.UneasyLogger - HTTP 400 Bad Request 
 <- UserService.findUser(..)
Retry 3/3 in 1000 ms
16:26:47.112 [main] ERROR io.lenar.easy.log.ExceptionLogger - HTTP 400 Bad Request
 <- UserService.findUser(..): 
{"code":400,"message":"First name is required","path":null,"parameterName":"firstName"}

Note: You can specify a parent exception to cover all child exceptions. For example WebApplicationException covers BadRequestException, ForbiddenException,NotFoundException etc

back to Table of Contents


If you want to log interface's method in all interface implementations then you can enable that feature by adding LoggerExtension like that

public class LoggerExtension extends EasyLoggerExtension {

    @Pointcut("execution(* com.yourcompany.yourapp...*.*(..))")
    public void anyMethodInPackage() {}

    public Object method(ProceedingJoinPoint jp) throws Throwable {
        return logIfMethodHasAnnotatedInterface(jp);


com.yourcompany.yourapp is your application package. It might be the top level package or some specific package in your application.

Now you can annotate any method of any interface or any interface inside this package and its sub-packages. It will apply for all implementations of the interface.

RESTEasy Client Interfaces

You can even annotate RESTful client interfaces that are used for RESTEasy Client Proxies (interfaces with JAX-RS annotations)._

public interface UserService {

   User getUser(@PathParam("id") int id);

   User createUser(User user);

   User updateUser(@PathParam("id") int id, User user);

LogIt can be used either for the whole interface or for its methods

back to Table of Contents


@LogIt(label="DEBUGGING ISSUE 1234", level=DEBUG)
public class ClassWithMethods {
public class ClassWithMethods {
@LogIt(label="USER CARDS", maskFields={"cardNumber", "pin"})
public UserCardsInfo getUserCards(..) {
@LogIt(label="USER SERVICE CALL", maskFields={"password"})
public User login(String userName, String password) {

back to Table of Contents

Working example projects


EasyLog walks through all passed and returned objects fields but It should not noticeably affect the performance

If you’re passing/returning very big objects or lists/arrays in highly loaded applications and concerned about performance I’d recommend to use AS_IS style and use your own toString() methods for serialization. Another option is to exclude those fields from logging with maskFields


    public Universe bigBang(int numberOfStars) {
   public User login(String userName, String password) {

Issues and suggestions

Report your issues or suggestions here


This is an opensource project - feel free to send your pull requests

Hot issues to work on:

back to Table of Contents


EasyLog is an open source library for logging/debugging in Java projects








No packages published