Browse Source

SONAR-9721 Opt-out of telemetry with a property

tags/6.6-RC1
Teryk Bellahsene 6 years ago
parent
commit
5c2b4dc4c2

+ 17
- 0
server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryClient.java View File

@@ -28,10 +28,13 @@ import okhttp3.Request;
import okhttp3.RequestBody;
import org.sonar.api.config.Configuration;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;

@ServerSide
public class TelemetryClient {
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private static final Logger LOG = Loggers.get(TelemetryClient.class);

private final OkHttpClient okHttpClient;
private final TelemetryUrl serverUrl;
@@ -50,6 +53,19 @@ public class TelemetryClient {
}
}

void optOut(String json) {
Request.Builder request = new Request.Builder();
request.url(serverUrl.get());
RequestBody body = RequestBody.create(JSON, json);
request.delete(body);

try {
okHttpClient.newCall(request.build()).execute();
} catch (IOException e) {
LOG.debug("Error when sending opt-out usage statistics: %s", e.getMessage());
}
}

private Request buildHttpRequest(String json) {
Request.Builder request = new Request.Builder();
request.url(serverUrl.get());
@@ -57,4 +73,5 @@ public class TelemetryClient {
request.post(body);
return request.build();
}

}

+ 31
- 2
server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryDaemon.java View File

@@ -30,19 +30,26 @@ import org.sonar.api.config.Configuration;
import org.sonar.api.platform.Server;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.server.property.InternalProperties;

import static org.sonar.api.utils.DateUtils.formatDate;
import static org.sonar.api.utils.DateUtils.parseDate;
import static org.sonar.server.telemetry.TelemetryProperties.PROP_ENABLE;
import static org.sonar.server.telemetry.TelemetryProperties.PROP_URL;

@ServerSide
public class TelemetryDaemon implements Startable {
private static final String THREAD_NAME_PREFIX = "sq-telemetry-service-";
private static final int SEVEN_DAYS = 7 * 24 * 60 * 60 * 1_000;
private static final String I_PROP_LAST_PING = "sonar.telemetry.lastPing";
private static final String I_PROP_OPT_OUT = "sonar.telemetry.optOut";
private static final Logger LOG = Loggers.get(TelemetryDaemon.class);

private final TelemetryClient telemetryClient;
private final Configuration config;
private final InternalProperties internalProperties;
private final Server server;
private final System2 system2;
@@ -50,16 +57,38 @@ public class TelemetryDaemon implements Startable {

private ScheduledExecutorService executorService;

public TelemetryDaemon(TelemetryClient telemetryClient, InternalProperties internalProperties, Server server, System2 system2, Configuration config) {
public TelemetryDaemon(TelemetryClient telemetryClient, Configuration config, InternalProperties internalProperties, Server server, System2 system2) {
this.telemetryClient = telemetryClient;
this.config = config;
this.frequencyInSeconds = new TelemetryFrequency(config);
this.internalProperties = internalProperties;
this.server = server;
this.frequencyInSeconds = new TelemetryFrequency(config);
this.system2 = system2;
}

@Override
public void start() {
boolean isTelemetryActivated = config.getBoolean(PROP_ENABLE).orElseThrow(() -> new IllegalStateException(String.format("Setting '%s' must be provided.", PROP_URL)));
if (!internalProperties.read(I_PROP_OPT_OUT).isPresent()) {
if (!isTelemetryActivated) {
StringWriter json = new StringWriter();
try (JsonWriter writer = JsonWriter.of(json)) {
writer.beginObject();
writer.prop("id", server.getId());
writer.endObject();
}
telemetryClient.optOut(json.toString());
internalProperties.write(I_PROP_OPT_OUT, String.valueOf(system2.now()));
LOG.info("Sharing of SonarQube statistics is disabled.");
} else {
internalProperties.write(I_PROP_OPT_OUT, null);
}
}

if (!isTelemetryActivated) {
return;
}
LOG.info("Sharing of SonarQube statistics is enabled.");
executorService = Executors.newSingleThreadScheduledExecutor(
new ThreadFactoryBuilder()
.setNameFormat(THREAD_NAME_PREFIX + "%d")

+ 6
- 0
server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryProperties.java View File

@@ -25,6 +25,11 @@ import org.sonar.api.Property;

@Properties({
@Property(
key = TelemetryProperties.PROP_ENABLE,
defaultValue = "true",
name = "Share SonarQube statistics",
global = false),
@Property(
key = TelemetryProperties.PROP_FREQUENCY,
// 6 hours in seconds
defaultValue = "21600",
@@ -37,6 +42,7 @@ import org.sonar.api.Property;
global = false)
})
public class TelemetryProperties {
static final String PROP_ENABLE = "sonar.telemetry.enable";
static final String PROP_FREQUENCY = "sonar.telemetry.frequency";
static final String PROP_URL = "sonar.telemetry.url";
}

+ 15
- 4
server/sonar-server/src/test/java/org/sonar/server/telemetry/TelemetryDaemonTest.java View File

@@ -55,7 +55,7 @@ public class TelemetryDaemonTest {
settings = new MapSettings(new PropertyDefinitions(TelemetryProperties.class));
system2.setNow(System.currentTimeMillis());

underTest = new TelemetryDaemon(client, internalProperties, server, system2, settings.asConfig());
underTest = new TelemetryDaemon(client, settings.asConfig(), internalProperties, server, system2);
}

@Test
@@ -63,7 +63,7 @@ public class TelemetryDaemonTest {
settings.setProperty("sonar.telemetry.frequency", "1");
underTest.start();

verify(client, timeout(2_000).atLeastOnce()).send(anyString());
verify(client, timeout(1_000).atLeastOnce()).send(anyString());
}

@Test
@@ -73,7 +73,6 @@ public class TelemetryDaemonTest {
long sevenDaysAgo = now - (ONE_DAY * 7L);
internalProperties.write("sonar.telemetry.lastPing", String.valueOf(sixDaysAgo));
settings.setProperty("sonar.telemetry.frequency", "1");
underTest = new TelemetryDaemon(client, internalProperties, server, system2, settings.asConfig());
underTest.start();
verify(client, timeout(1_000).never()).send(anyString());
internalProperties.write("sonar.telemetry.lastPing", String.valueOf(sevenDaysAgo));
@@ -114,7 +113,19 @@ public class TelemetryDaemonTest {

underTest.start();

verify(client, timeout(2_000)).send(anyString());
verify(client, timeout(1_000).atLeastOnce()).send(anyString());
assertThat(internalProperties.read("sonar.telemetry.lastPing").get()).isEqualTo(String.valueOf(today));
}

@Test
public void opt_out_sent_once() {
settings.setProperty("sonar.telemetry.frequency", "1");
settings.setProperty("sonar.telemetry.enable", "false");
underTest.start();
underTest.start();


verify(client, timeout(1_000).never()).send(anyString());
verify(client, timeout(1_000).times(1)).optOut(anyString());
}
}

+ 6
- 0
sonar-application/src/main/assembly/conf/sonar.properties View File

@@ -342,6 +342,12 @@
#sonar.path.data=data
#sonar.path.temp=temp

# Telemetry - Share anonymous SonarQube statistics
# By sharing anonymous SonarQube statistics, you help us understand how SonarQube is used so we can improve the product to work even better for you.
# We don't collect source code or IP addresses. And we don't share the data with anyone else.
# To see an example of the data shared: login as a global administrator, call the WS api/system/info and check the Statistics field.
#sonar.telemetry.enable=true


#--------------------------------------------------------------------------------------------------
# DEVELOPMENT - only for developers

+ 21
- 0
tests/src/test/java/org/sonarqube/tests/telemetry/TelemetryTest.java View File

@@ -70,4 +70,25 @@ public class TelemetryTest {

orchestrator.stop();
}

@Test
public void opt_out_of_telemetry() throws Exception {
String serverId = randomAlphanumeric(40);
orchestrator = Orchestrator.builderEnv()
.addPlugin(xooPlugin())
.setServerProperty("sonar.telemetry.enable", "false")
.setServerProperty("sonar.telemetry.url", url)
.setServerProperty("sonar.telemetry.frequency", "1")
.setServerProperty("sonar.core.id", serverId)
.build();
orchestrator.start();

RecordedRequest request = server.takeRequest(1, TimeUnit.SECONDS);

assertThat(request.getMethod()).isEqualTo("DELETE");
assertThat(request.getBody().readUtf8()).contains(serverId);
assertThat(request.getHeader(HttpHeaders.USER_AGENT)).contains("SonarQube");

orchestrator.stop();
}
}

Loading…
Cancel
Save