Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SLCORE-1055 sentry integration #1188

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions backend/core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry</artifactId>
<version>7.16.0</version>
</dependency>
</dependencies>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.sonarsource.sonarlint.core.analysis;

import com.google.common.util.concurrent.MoreExecutors;
import io.sentry.Sentry;
import java.net.URI;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.Files;
Expand Down Expand Up @@ -674,6 +675,8 @@ public CompletableFuture<AnalysisResults> analyze(SonarLintCancelMonitor cancelM
} else {
LOG.error("Error during analysis", error);
}
var testException = new Exception();
Sentry.captureException(testException);
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* SonarLint Core - Implementation
* Copyright (C) 2016-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonarsource.sonarlint.core.monitoring;

import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.commons.lang3.SystemUtils;

@Named
@Singleton
public class DogfoodEnvironmentDetectionService {
private static final String SONARSOURCE_DOGFOODING_ENV_VAR_KEY = "SONARSOURCE_DOGFOODING";

public boolean isDogfoodEnvironment() {
return "1".equals(SystemUtils.getEnvironmentVariable(SONARSOURCE_DOGFOODING_ENV_VAR_KEY, "0"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* SonarLint Core - Implementation
* Copyright (C) 2016-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonarsource.sonarlint.core.monitoring;

import io.sentry.Sentry;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.commons.lang3.SystemUtils;
import org.sonarsource.sonarlint.core.commons.SonarLintCoreVersion;
import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger;
import org.sonarsource.sonarlint.core.rpc.protocol.backend.initialize.InitializeParams;

@Named
@Singleton
public class MonitoringService {
private static final SonarLintLogger LOG = SonarLintLogger.get();

private InitializeParams initializeParams;
private DogfoodEnvironmentDetectionService dogfoodEnvDetectionService;

public MonitoringService(InitializeParams initializeParams, DogfoodEnvironmentDetectionService dogfoodEnvDetectionService) {
this.initializeParams = initializeParams;
this.dogfoodEnvDetectionService = dogfoodEnvDetectionService;

this.init();
}

public void init() {
var productKey = initializeParams.getTelemetryConstantAttributes().getProductKey();
var environment = "dogfood";
var sonarQubeForIDEVersion = initializeParams.getTelemetryConstantAttributes().getProductVersion();
var ideVersion = initializeParams.getTelemetryConstantAttributes().getIdeVersion();
var releaseVersion = SonarLintCoreVersion.get();
var platform = SystemUtils.OS_NAME;
var architecture = SystemUtils.OS_ARCH;

if (dogfoodEnvDetectionService.isDogfoodEnvironment()) {
LOG.info("Initializing Sentry");
Sentry.init(sentryOptions -> {
sentryOptions.setDsn("https://[email protected]/4508201175089152");
sentryOptions.setRelease(releaseVersion);
sentryOptions.setEnvironment(environment);
sentryOptions.setTag("productKey", productKey);
sentryOptions.setTag("sonarQubeForIDEVersion", sonarQubeForIDEVersion);
sentryOptions.setTag("ideVersion", ideVersion);
sentryOptions.setTag("platform", platform);
sentryOptions.setTag("architecture", architecture);
sentryOptions.addInAppInclude("org.sonarsource.sonarlint");

sentryOptions.setBeforeSend((event, hint) -> {
LOG.debug("Sending Sentry event" + event);
return event;
});
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@
import org.sonarsource.sonarlint.core.TokenGeneratorHelper;
import org.sonarsource.sonarlint.core.VersionSoonUnsupportedHelper;
import org.sonarsource.sonarlint.core.analysis.AnalysisEngineCache;
import org.sonarsource.sonarlint.core.analysis.UserAnalysisPropertiesRepository;
import org.sonarsource.sonarlint.core.analysis.AnalysisService;
import org.sonarsource.sonarlint.core.analysis.NodeJsService;
import org.sonarsource.sonarlint.core.analysis.UserAnalysisPropertiesRepository;
import org.sonarsource.sonarlint.core.branch.SonarProjectBranchTrackingService;
import org.sonarsource.sonarlint.core.commons.SonarLintUserHome;
import org.sonarsource.sonarlint.core.embedded.server.AwaitingUserTokenFutureRepository;
Expand Down Expand Up @@ -76,6 +76,8 @@
import org.sonarsource.sonarlint.core.languages.LanguageSupportRepository;
import org.sonarsource.sonarlint.core.local.only.LocalOnlyIssueStorageService;
import org.sonarsource.sonarlint.core.mode.SeverityModeService;
import org.sonarsource.sonarlint.core.monitoring.DogfoodEnvironmentDetectionService;
import org.sonarsource.sonarlint.core.monitoring.MonitoringService;
import org.sonarsource.sonarlint.core.newcode.NewCodeService;
import org.sonarsource.sonarlint.core.plugin.PluginsRepository;
import org.sonarsource.sonarlint.core.plugin.PluginsService;
Expand Down Expand Up @@ -191,7 +193,9 @@
FindingReportingService.class,
PreviouslyRaisedFindingsRepository.class,
UserAnalysisPropertiesRepository.class,
OpenFilesRepository.class
OpenFilesRepository.class,
DogfoodEnvironmentDetectionService.class,
MonitoringService.class
})
public class SonarLintSpringAppConfig {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* SonarLint Core - Medium Tests
* Copyright (C) 2016-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package mediumtest.monitoring;

import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import mediumtest.fixtures.SonarLintBackendFixture;
import mediumtest.fixtures.SonarLintTestRpcServer;
import mediumtest.fixtures.TestPlugin;
import org.assertj.core.api.Assumptions;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.sonarsource.sonarlint.core.rpc.protocol.common.ClientFileDto;

import static mediumtest.fixtures.SonarLintBackendFixture.newBackend;
import static mediumtest.fixtures.SonarLintBackendFixture.newFakeClient;
import static org.assertj.core.api.Assertions.assertThat;
import static testutils.AnalysisUtils.analyzeFileAndGetIssues;
import static testutils.AnalysisUtils.createFile;

class MonitoringMediumTest {

private static SonarLintBackendFixture.FakeSonarLintRpcClient client;

private static final String A_JAVA_FILE_PATH = "Foo.java";
private static final String CONFIGURATION_SCOPE_ID = "configScopeId";
private static final List<String> logs = new CopyOnWriteArrayList<>();
private static SonarLintTestRpcServer backend;
// commercial plugins might not be available
// (if you pass -Dcommercial to maven, a profile will be activated that downloads the commercial plugins)
private static final boolean COMMERCIAL_ENABLED = System.getProperty("commercial") != null;

@BeforeAll
static void checkDogfoodingVariableSet() {
Assumptions.assumeThat(System.getenv("SONARSOURCE_DOGFOODING"))
.withFailMessage("Dogfooding environment variable is not set, skipping tests")
.isEqualTo("1");
}

@AfterAll
static void stop() throws ExecutionException, InterruptedException {
Thread.sleep(5_000);
if (backend != null) {
backend.shutdown().get();
}
}

@AfterEach
void cleanup() {
client.cleanRaisedIssues();
}

@Test
void shouldPostMonitoringPingToSentry(@TempDir Path baseDir) throws Throwable {
var content = "function foo() {\n"
+ " let x;\n"
+ " let y; //NOSONAR\n"
+ "}";
var inputFile = createFile(baseDir, "foo.js", content);

client = newFakeClient()
.withInitialFs(CONFIGURATION_SCOPE_ID, List.of(
new ClientFileDto(inputFile.toUri(), baseDir.relativize(inputFile), CONFIGURATION_SCOPE_ID, false, null, inputFile, null, null, true)
))
.build();

backend = newBackend()
.withUnboundConfigScope(CONFIGURATION_SCOPE_ID)
.withStandaloneEmbeddedPluginAndEnabledLanguage(TestPlugin.JAVASCRIPT)
.build(client);

analyzeFileAndGetIssues(inputFile.toUri(), client, backend, CONFIGURATION_SCOPE_ID);
}
}