2020package org .sonarsource .sonarlint .core .rpc .impl ;
2121
2222import ch .qos .logback .classic .Level ;
23+ import ch .qos .logback .classic .encoder .PatternLayoutEncoder ;
24+ import ch .qos .logback .classic .spi .ILoggingEvent ;
25+ import ch .qos .logback .core .rolling .FixedWindowRollingPolicy ;
26+ import ch .qos .logback .core .rolling .RollingFileAppender ;
27+ import ch .qos .logback .core .rolling .SizeBasedTriggeringPolicy ;
28+ import ch .qos .logback .core .util .FileSize ;
2329import com .google .common .util .concurrent .MoreExecutors ;
2430import io .sentry .Attachment ;
2531import io .sentry .Hint ;
3137import java .io .PrintWriter ;
3238import java .lang .reflect .InvocationTargetException ;
3339import java .nio .charset .StandardCharsets ;
40+ import java .nio .file .Path ;
3441import java .nio .file .Paths ;
3542import java .util .concurrent .CompletableFuture ;
3643import java .util .concurrent .CompletionException ;
4855import org .slf4j .Logger ;
4956import org .slf4j .LoggerFactory ;
5057import org .slf4j .bridge .SLF4JBridgeHandler ;
58+ import org .sonarsource .sonarlint .core .UserPaths ;
5159import org .sonarsource .sonarlint .core .commons .log .SonarLintLogger ;
5260import org .sonarsource .sonarlint .core .commons .progress .ExecutorServiceShutdownWatchable ;
5361import org .sonarsource .sonarlint .core .commons .storage .SonarLintDatabase ;
7280import org .sonarsource .sonarlint .core .rpc .protocol .backend .initialize .InitializeParams ;
7381import org .sonarsource .sonarlint .core .rpc .protocol .backend .issue .IssueRpcService ;
7482import org .sonarsource .sonarlint .core .rpc .protocol .backend .labs .IdeLabsRpcService ;
83+ import org .sonarsource .sonarlint .core .rpc .protocol .backend .log .LogLevel ;
7584import org .sonarsource .sonarlint .core .rpc .protocol .backend .log .LogRpcService ;
7685import org .sonarsource .sonarlint .core .rpc .protocol .backend .newcode .NewCodeRpcService ;
7786import org .sonarsource .sonarlint .core .rpc .protocol .backend .progress .TaskProgressRpcService ;
@@ -190,8 +199,10 @@ public CompletableFuture<Void> initialize(InitializeParams params) {
190199 return CompletableFutures .computeAsync (requestAndNotificationsSequentialExecutor , cancelChecker -> {
191200 SonarLintLogger .get ().setLevel (LogService .convert (params .getLogLevel ()));
192201 SonarLintLogger .get ().setTarget (logOutput );
202+ var root = (ch .qos .logback .classic .Logger ) LoggerFactory .getLogger (Logger .ROOT_LOGGER_NAME );
193203 // for flyway logging level
194- setLogbackRootLogger (params );
204+ setLogbackRootLogger (root , params .getLogLevel ());
205+ setupFileAppender (root , UserPaths .from (params ).getStorageRoot ());
195206 if (initializeCalled .compareAndSet (false , true ) && !initialized .get ()) {
196207 springApplicationContextInitializer = new SpringApplicationContextInitializer (client , params );
197208 initialized .set (true );
@@ -203,17 +214,49 @@ public CompletableFuture<Void> initialize(InitializeParams params) {
203214 });
204215 }
205216
206- private static void setLogbackRootLogger (InitializeParams params ) {
207- var root = (ch .qos .logback .classic .Logger ) LoggerFactory .getLogger (Logger .ROOT_LOGGER_NAME );
208- var logLevel = switch (params .getLogLevel ()) {
217+ private void setupFileAppender (ch .qos .logback .classic .Logger root , Path storageRoot ) {
218+ var loggerContext = root .getLoggerContext ();
219+
220+ var encoder = new PatternLayoutEncoder ();
221+ encoder .setContext (loggerContext );
222+ encoder .setPattern ("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{30} - %msg%n" );
223+ encoder .start ();
224+
225+ var rollingPolicy = new FixedWindowRollingPolicy ();
226+ rollingPolicy .setContext (loggerContext );
227+
228+ // This is the file appender we will configure later
229+ var baseFileName = "slcore" ;
230+ var triggeringPolicy = new SizeBasedTriggeringPolicy <ILoggingEvent >();
231+ triggeringPolicy .setMaxFileSize (new FileSize (10 * 1024 * 1024L ));
232+ var rollingFileAppender = new RollingFileAppender <ILoggingEvent >();
233+ rollingFileAppender .setContext (loggerContext );
234+ rollingFileAppender .setName ("ROLLING_FILE" );
235+ rollingFileAppender .setFile (storageRoot .resolve ("logs" ).resolve (baseFileName + ".log" ).toAbsolutePath ().toString ());
236+ rollingFileAppender .setEncoder (encoder );
237+ rollingFileAppender .setRollingPolicy (rollingPolicy );
238+ rollingFileAppender .setTriggeringPolicy (triggeringPolicy );
239+ rollingPolicy .setParent (rollingFileAppender );
240+ rollingPolicy .setFileNamePattern (baseFileName + ".%i.log" );
241+ rollingPolicy .setMinIndex (1 );
242+ rollingPolicy .setMinIndex (10 );
243+
244+ rollingPolicy .start ();
245+ triggeringPolicy .start ();
246+ rollingFileAppender .start ();
247+
248+ root .addAppender (rollingFileAppender );
249+ }
250+
251+ private static void setLogbackRootLogger (ch .qos .logback .classic .Logger root , LogLevel logLevel ) {
252+ root .setLevel (switch (logLevel ) {
209253 case OFF -> Level .OFF ;
210254 case ERROR -> Level .ERROR ;
211255 case WARN -> Level .WARN ;
212256 case INFO -> Level .INFO ;
213257 case DEBUG -> Level .DEBUG ;
214258 case TRACE -> Level .TRACE ;
215- };
216- root .setLevel (logLevel );
259+ });
217260 }
218261
219262 public ConfigurableApplicationContext getInitializedApplicationContext () {
0 commit comments