Skip to content

Commit

Permalink
Populate events with dependencies metadata (#396)
Browse files Browse the repository at this point in the history
  • Loading branch information
romtsn committed Nov 2, 2022
1 parent 48101b1 commit 2ae060d
Show file tree
Hide file tree
Showing 38 changed files with 1,084 additions and 86 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 3.2.1

### Features

- Populate events with dependencies metadata ([#396](https://github.com/getsentry/sentry-android-gradle-plugin/pull/396))

### Fixes

- Ignore minified classes from any instrumentation ([#389](https://github.com/getsentry/sentry-android-gradle-plugin/pull/389))
Expand Down
26 changes: 26 additions & 0 deletions buildSrc/src/main/java/Dependencies.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import BuildPluginsVersion.SPRING_BOOT
import org.gradle.util.VersionNumber

object BuildPluginsVersion {
Expand All @@ -10,6 +11,11 @@ object BuildPluginsVersion {
// build/publications/maven
const val MAVEN_PUBLISH = "0.17.0"
const val PROGUARD = "7.1.0"
const val GROOVY_REDISTRIBUTED = "1.2"

const val SPRING_BOOT = "2.7.4"
const val SPRING_DEP_MANAGEMENT = "1.0.11.RELEASE"

// proguard does not support AGP 8 yet
fun isProguardApplicable(): Boolean = VersionNumber.parse(AGP).major < 8
}
Expand All @@ -28,6 +34,10 @@ object Libs {
val AGP = "com.android.tools.build:gradle:${BuildPluginsVersion.AGP}"
const val JUNIT = "junit:junit:${LibsVersion.JUNIT}"
const val PROGUARD = "com.guardsquare:proguard-gradle:${BuildPluginsVersion.PROGUARD}"
// this allows us to develop against a fixed version of Gradle, as opposed to depending on the
// locally available version. kotlin-gradle-plugin follows the same approach.
// More info: https://docs.nokee.dev/manual/gradle-plugin-development-plugin.html
const val GRADLE_API = "dev.gradleplugins:gradle-api:7.5"

// bytecode instrumentation
const val ASM = "org.ow2.asm:asm-util:${LibsVersion.ASM}"
Expand Down Expand Up @@ -83,4 +93,20 @@ object Samples {
private const val version = "1.3.5"
const val fragmentKtx = "androidx.fragment:fragment-ktx:${version}"
}

object SpringBoot {
val springBoot = "org.springframework.boot"
val springDependencyManagement = "io.spring.dependency-management"
val springBootStarter = "org.springframework.boot:spring-boot-starter:$SPRING_BOOT"
val springBootStarterTest = "org.springframework.boot:spring-boot-starter-test:$SPRING_BOOT"
val springBootStarterWeb = "org.springframework.boot:spring-boot-starter-web:$SPRING_BOOT"
val springBootStarterWebflux = "org.springframework.boot:spring-boot-starter-webflux:$SPRING_BOOT"
val springBootStarterAop = "org.springframework.boot:spring-boot-starter-aop:$SPRING_BOOT"
val springBootStarterSecurity = "org.springframework.boot:spring-boot-starter-security:$SPRING_BOOT"
val springBootStarterJdbc = "org.springframework.boot:spring-boot-starter-jdbc:$SPRING_BOOT"
val hsqldb = "org.hsqldb:hsqldb:2.6.1"
val aspectj = "org.aspectj:aspectjweaver"
val kotlinReflect = "org.jetbrains.kotlin:kotlin-reflect"
val kotlinStdLib = "stdlib-jdk8"
}
}
51 changes: 51 additions & 0 deletions examples/spring-boot-sample/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
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.android.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))
implementation("io.sentry:sentry-spring-boot-starter:6.5.0")
implementation("io.sentry:sentry-logback:6.5.0")

// database query tracing
implementation("io.sentry:sentry-jdbc:6.5.0")
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()
}
}
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,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;
}
}

0 comments on commit 2ae060d

Please sign in to comment.