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

Analytics / Telemetry #582

Merged
merged 44 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
57601d3
Use spring-boot instead of spring-boot-starter for auto install detec…
adinauer Aug 7, 2023
9b6fb59
Merge branch 'main' into feat/use-spring-boot-not-starter-for-auto-in…
adinauer Oct 9, 2023
c9c6e4a
changelog
adinauer Oct 9, 2023
529a591
analytics WIP
adinauer Oct 11, 2023
dd2326c
Fix build service registration
romtsn Oct 11, 2023
507a607
wip
adinauer Oct 18, 2023
290b710
Merge branch 'main' into feat/analytics
adinauer Oct 18, 2023
7d2a05d
set cli version, check saas, add headers to cli, set org as user, etc
adinauer Oct 23, 2023
f387d7a
Merge branch 'main' into feat/analytics
adinauer Oct 23, 2023
bad66b4
seemed to cause problems with older gradle versions
adinauer Oct 24, 2023
3b0282e
service optional
adinauer Oct 24, 2023
984739a
progress
adinauer Oct 24, 2023
23de9c9
Make it config-cache compatible
romtsn Oct 24, 2023
e984e30
more progress
adinauer Oct 25, 2023
cfb22d5
lazy init after taskGraph ready; only capture exceptions from sentry …
adinauer Nov 2, 2023
cd93aec
cleanup
adinauer Nov 3, 2023
0235e23
fix tests; cleanup
adinauer Nov 3, 2023
eb3a1d5
Merge branch 'main' into feat/analytics
adinauer Nov 3, 2023
402bbd3
changelog
adinauer Nov 3, 2023
2c62c2b
Clean up
romtsn Nov 15, 2023
fa983ed
Merge branch 'main' into feat/analytics
adinauer Nov 16, 2023
f64aad9
code review changes
adinauer Nov 16, 2023
e4ed7ef
test always exec
adinauer Nov 16, 2023
a42ddda
revert always use exec; actually use org and issaas
adinauer Nov 16, 2023
f2c3130
more code review changes
adinauer Nov 17, 2023
b494264
restore cli --version exec and parsing
adinauer Nov 17, 2023
92bad3d
wrap agp version tag with try/catch as it isnt available for jvm; fix…
adinauer Nov 17, 2023
81ce9fd
synch
adinauer Nov 17, 2023
935bc4c
fix lint
adinauer Nov 17, 2023
87591de
Use DSN in sentry org
adinauer Nov 17, 2023
e0af68c
add tests
adinauer Nov 17, 2023
85d8485
disable tests for now
adinauer Nov 17, 2023
62b7a38
remove imports
adinauer Nov 17, 2023
327bfdd
try to fix tests
adinauer Nov 17, 2023
33b81b8
fix tests
adinauer Nov 17, 2023
5cc4263
fix test...
adinauer Nov 17, 2023
10dcb9a
fix test ....
adinauer Nov 17, 2023
5e76b0a
once again ...
adinauer Nov 17, 2023
d880f23
Fix tests
romtsn Nov 20, 2023
d72d0fd
Fix
romtsn Nov 20, 2023
5bc3a42
Better changelog and tests
romtsn Nov 20, 2023
16f86c1
Disable telemetry to test
romtsn Nov 20, 2023
eda4ff7
Comment out tests completely
romtsn Nov 20, 2023
9d76cb9
ktlint
romtsn Nov 20, 2023
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

- Print a warning if the Sentry plugin is not applied on the app module ([#586](https://github.com/getsentry/sentry-android-gradle-plugin/pull/586))
- Add new `excludes` option to exclude classes from instrumentation ([#590](https://github.com/getsentry/sentry-android-gradle-plugin/pull/590))
- Send telemetry data for plugin usage ([#582](https://github.com/getsentry/sentry-android-gradle-plugin/pull/582))
- This will collect errors and timings of the plugin and its tasks (anonymized, except the sentry org id), so we can better understand how the plugin is performing. If you wish to opt-out of this behavior, set `telemetry = false` in the `sentry` plugin configuration block.

### Chores

Expand Down
3 changes: 2 additions & 1 deletion buildSrc/src/main/java/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ object LibsVersion {
const val JUNIT = "4.13.2"
const val ASM = "7.0" // compatibility matrix -> https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/instrumentation/InstrumentationContext#apiversion
const val SQLITE = "2.1.0"
const val SENTRY = "6.23.0"
const val SENTRY = "6.31.0"
}

object Libs {
Expand All @@ -47,6 +47,7 @@ object Libs {
const val ASM_COMMONS = "org.ow2.asm:asm-commons:${LibsVersion.ASM}"
const val SQLITE = "androidx.sqlite:sqlite:${LibsVersion.SQLITE}"
const val SQLITE_FRAMEWORK = "androidx.sqlite:sqlite-framework:${LibsVersion.SQLITE}"
const val SENTRY = "io.sentry:sentry:${LibsVersion.SENTRY}"
const val SENTRY_ANDROID = "io.sentry:sentry-android:${LibsVersion.SENTRY}"
const val SENTRY_ANDROID_OKHTTP = "io.sentry:sentry-android-okhttp:${LibsVersion.SENTRY}"

Expand Down
21 changes: 21 additions & 0 deletions examples/multi-module-sample/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// ktlint-disable max-line-length
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm")
id("io.sentry.jvm.gradle")
}

tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}

sentry {
debug.set(true)
telemetry.set(false)
includeSourceContext.set(true)
additionalSourceDirsForSourceContext.set(setOf("testsrc"))
}
2 changes: 2 additions & 0 deletions examples/multi-module-sample/sentry.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
defaults.project=sentry-java
defaults.org=sentry-sdks
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// ktlint-disable max-line-length
import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id(Samples.SpringBoot.springBoot) version
BuildPluginsVersion.SPRING_BOOT
id(Samples.SpringBoot.springDependencyManagement) version
BuildPluginsVersion.SPRING_DEP_MANAGEMENT
kotlin("jvm")
kotlin("plugin.spring") version BuildPluginsVersion.KOTLIN
id("io.sentry.jvm.gradle")
}

group = "io.sentry.samples.spring-boot"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8
java.targetCompatibility = JavaVersion.VERSION_1_8

repositories {
mavenCentral()
}

dependencies {
implementation(Samples.SpringBoot.springBootStarterSecurity)
implementation(Samples.SpringBoot.springBootStarterWeb)
implementation(Samples.SpringBoot.springBootStarterWebflux)
implementation(Samples.SpringBoot.springBootStarterAop)
implementation(Samples.SpringBoot.aspectj)
implementation(Samples.SpringBoot.springBootStarter)
implementation(Samples.SpringBoot.kotlinReflect)
implementation(Samples.SpringBoot.springBootStarterJdbc)
implementation(kotlin(Samples.SpringBoot.kotlinStdLib, KotlinCompilerVersion.VERSION))

runtimeOnly(Samples.SpringBoot.hsqldb)
testImplementation(Samples.SpringBoot.springBootStarterTest) {
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
}
}

tasks.withType<Test> {
useJUnitPlatform()
}

tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}

sentry {
debug.set(true)
telemetry.set(false)
includeSourceContext.set(true)
additionalSourceDirsForSourceContext.set(setOf("testsrc"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
defaults.project=sentry-java
defaults.org=sentry-sdks
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.sentry.samples.spring.boot;

import io.sentry.EventProcessor;
import io.sentry.Hint;
import io.sentry.SentryEvent;
import io.sentry.protocol.SentryRuntime;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.SpringBootVersion;
import org.springframework.stereotype.Component;

/**
* Custom {@link EventProcessor} implementation lets modifying {@link SentryEvent}s before they are
* sent to Sentry.
*/
@Component
public class CustomEventProcessor implements EventProcessor {
private final String springBootVersion;

public CustomEventProcessor(String springBootVersion) {
this.springBootVersion = springBootVersion;
}

public CustomEventProcessor() {
this(SpringBootVersion.getVersion());
}

@Override
public @NotNull SentryEvent process(@NotNull SentryEvent event, @NotNull Hint hint) {
final SentryRuntime runtime = new SentryRuntime();
runtime.setVersion(springBootVersion);
runtime.setName("Spring Boot");
event.getContexts().setRuntime(runtime);
return event;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.sentry.samples.spring.boot;

import io.sentry.spring.tracing.SentryTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
* {@link SentryTransaction} added on the class level, creates transaction around each method
* execution of every method of the annotated class.
*/
@Component
@SentryTransaction(operation = "scheduled")
public class CustomJob {

private static final Logger LOGGER = LoggerFactory.getLogger(CustomJob.class);

@Scheduled(fixedRate = 3 * 1000L)
void execute() throws InterruptedException {
LOGGER.info("Executing scheduled job");
Thread.sleep(2000L);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.sentry.samples.spring.boot;

public class Person {
private final String firstName;
private final String lastName;

public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

public String getFirstName() {
return firstName;
}

public String getLastName() {
return lastName;
}

@Override
public String toString() {
return "Person{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + '}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.sentry.samples.spring.boot;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/person/")
public class PersonController {
private final PersonService personService;
private static final Logger LOGGER = LoggerFactory.getLogger(PersonController.class);

public PersonController(PersonService personService) {
this.personService = personService;
}

@GetMapping("{id}")
Person person(@PathVariable Long id) {
LOGGER.info("Loading person with id={}", id);
throw new IllegalArgumentException("Something went wrong [id=" + id + "]");
}

@PostMapping
Person create(@RequestBody Person person) {
return personService.create(person);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.sentry.samples.spring.boot;

import io.sentry.ISpan;
import io.sentry.Sentry;
import io.sentry.spring.tracing.SentrySpan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

/**
* {@link SentrySpan} can be added either on the class or the method to create spans around method
* executions.
*/
@Service
@SentrySpan
public class PersonService {
private static final Logger LOGGER = LoggerFactory.getLogger(PersonService.class);

private final JdbcTemplate jdbcTemplate;
private int createCount = 0;

public PersonService(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

Person create(Person person) {
createCount++;
final ISpan span = Sentry.getSpan();
if (span != null) {
span.setMeasurement("create_count", createCount);
}

jdbcTemplate.update(
"insert into person (firstName, lastName) values (?, ?)",
person.getFirstName(),
person.getLastName());
return person;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.sentry.samples.spring.boot;

import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
@SuppressWarnings("deprecation") // WebSecurityConfigurerAdapter has been deprecated
public class SecurityConfiguration
extends org.springframework.security.config.annotation.web.configuration
.WebSecurityConfigurerAdapter {

// this API is meant to be consumed by non-browser clients thus the CSRF protection is not needed.
@Override
@SuppressWarnings("lgtm[java/spring-disabled-csrf-protection]")
protected void configure(final @NotNull HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic();
}

@Bean
@Override
public @NotNull UserDetailsService userDetailsService() {
final PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();

final UserDetails user =
User.builder()
.passwordEncoder(encoder::encode)
.username("user")
.password("password")
.roles("USER")
.build();

return new InMemoryUserDetailsManager(user);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.sentry.samples.spring.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;

@SpringBootApplication
@EnableScheduling
public class SentryDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SentryDemoApplication.class, args);
}

@Bean
RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}

@Bean
WebClient webClient(WebClient.Builder builder) {
return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package io.sentry.samples.spring.boot

class Test
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.sentry.samples.spring.boot;

public class Todo {
private final Long id;
private final String title;
private final boolean completed;

public Todo(Long id, String title, boolean completed) {
this.id = id;
this.title = title;
this.completed = completed;
}

public Long getId() {
return id;
}

public String getTitle() {
return title;
}

public boolean isCompleted() {
return completed;
}
}
Loading
Loading