Skip to content

Latest commit

 

History

History
26 lines (15 loc) · 2.36 KB

logging.adoc

File metadata and controls

26 lines (15 loc) · 2.36 KB

Logging

Logging is a complex topic in SonarLint. At the moment, SonarLint Core is used as a library in SonarLint Eclipse and SonarLint IntelliJ. It means using a framework like SLF4J may output logs in the IDE logs, while we choose to have all SonarLint logs in the SonarLint Console/ToolWindow.

In order to not "leak" SonarLint logs in IDE logs, we experimented 2 strategies:

1. Use our own logging facade in the Sonar Plugin Api (org.sonar.api.utils.log.Logger)

By asking the plugin’s author not to use SLF4J but instead to use our own facade, we thought it would make our life easier. Having a dedicated class makes it easier to provide our own implementation, without risking having a higher-level classloader already providing an instance of the logging interface.

The first issue is that before introducing this facade, we already had some plugins using SLF4J. So during the deprecation period (I’m not even sure we have officially deprecated the use of SLF4J in plugins) we still need to support SLF4J. The second issue is that even if analyzers try to only use our logging facade, they may embed third-party libraries that are themselves relying on SLF4J. So in the end, introducing our own logging facade was just one more case to maintain. We will likely still need to maintain SLF4J support forever. Interesting reading about why having a wrapper on top of SLF4J is usually not a good idea: https://www.slf4j.org/faq.html#optional_dependency

Also, our logging facade is now outdated compared to SLF4J 2.0 (fluent API).

2. Intercept SLF4J logs from plugins and redirect them to the SonarLint log output

This is quite tricky, because of the way SLF4J is loaded into classloaders. The hosting IDE may or may not already contain SLF4J, and the default classloading strategy is to be a parent first, so even if we put our own SLF4J in the SonarLint plugin classloader, it will be "masked" by the instance in the parent classloader.

Since we are already creating custom classloaders for plugins, the trick is to hide parent SLF4J classes, and inject both slf4j-api and our custom provider into plugin classloaders.

In SonarLint Core codebase, we can’t use SLF4J, or we would have to create another layer of custom classloaders.

In the long run, having SonarLint backend running as a separate Java process will allow us to remove all these hacks, and simply use SLF4J everywhere.