I would like to get the username of the user in every request to add them to log file.
This is my solution:
First, I created a LoggedUser with a static property:
public class LoggedUser {
    private static final ThreadLocal<String> userHolder = 
        new ThreadLocal<>();
    public static void logIn(String user) {
        userHolder.set(user);
    }
    public static void logOut() {
        userHolder.remove();
    }
    public static String get() {
        return userHolder.get();
    }
}
Then I created a support class to get username:
public interface AuthenticationFacade {
    Authentication getAuthentication();
}
@Component
public class AuthenticationFacadeImpl implements AuthenticationFacade {
    @Override
    public Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }
}
Finally, I used them in my Controllers:
    @RestController
    public class ResourceController {
        Logger logger = LoggerFactory.getLogger(ResourceController.class);
        @Autowired
        private GenericService userService;
        @Autowired
        private AuthenticationFacade authenticationFacade;
        @RequestMapping(value ="/cities")
        public List<RandomCity> getCitiesAndLogWhoIsRequesting(){
        loggedUser.logIn(authenticationFacade.getAuthentication().getName());
        logger.info(LoggedUser.get()); //Log username
        return userService.findAllRandomCities();
        }
    }
The problem is I don't want to have AuthenticationFacade in every @Controller, If I have 10000 controllers, for example, it will be a lot of works.
Do you have any better solution for it?
The solution is called Fish Tagging. Every decent logging framework has this functionality. Some frameworks call it MDC(Mapped Diagnostic Context). You can read about it here and here.
The basic idea is to use ThreadLocal or InheritableThreadLocal to hold a few key-value pairs in a thread to track a request. Using logging configuration, you can configure how to print it in the log entries.
Basically, you can write a filter, where you would retrieve the username from the security context and put it into the MDC and just forget about it. In your controller you log only the business logic related stuff. The username will be printed in the log entries along with timestamp, log level etc. (as per your log configuration).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With