Skip to content

Commit 2403eeb

Browse files
committed
Merge branch '6.x.x' into feat/client-reports
2 parents 9da91fe + be0ebe0 commit 2403eeb

17 files changed

+519
-14
lines changed

.craft.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ targets:
2424
maven:io.sentry:sentry-spring:
2525
maven:io.sentry:sentry-spring-boot-starter:
2626
maven:io.sentry:sentry-servlet:
27+
maven:io.sentry:sentry-servlet-jakarta:
2728
maven:io.sentry:sentry-logback:
2829
maven:io.sentry:sentry-log4j2:
2930
maven:io.sentry:sentry-jul:

.github/ISSUE_TEMPLATE/bug_report_java.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ body:
1414
- sentry-apollo
1515
- sentry-kotlin-extensions
1616
- sentry-servlet
17+
- sentry-servlet-jakarta
1718
- sentry-spring-boot-starter
1819
- sentry-spring
1920
- sentry-logback

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Changelog
22

33
## Unreleased
4+
5+
* Feat: Add sentry-servlet-jakarta module (#1987)
6+
* Ref: Make options.printUncaughtStackTrace primitive type (#1995)
47
* Feat: Add client reports (#1982)
58

69
## 6.0.0-alpha.5
@@ -56,6 +59,14 @@ Breaking changes:
5659
* Remove `IUnknownPropertiesConsumer`
5760
* Bump: Kotlin to 1.5 and compatibility to 1.4 for sentry-android-timber (#1815)
5861

62+
## 5.7.3
63+
64+
* Fix: Sentry Timber integration throws an exception when using args (#1986)
65+
66+
## 5.7.2
67+
68+
* Fix: bring back support for `Timber.tag` ([#1974](https://github.com/getsentry/sentry-java/pull/1974))
69+
5970
## 5.7.1
6071

6172
* Fix: Sentry Timber integration does not submit msg.formatted breadcrumbs (#1957)

buildSrc/src/main/java/Config.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ object Config {
7676
val springAop = "org.springframework:spring-aop"
7777
val aspectj = "org.aspectj:aspectjweaver"
7878
val servletApi = "javax.servlet:javax.servlet-api:3.1.0"
79+
val servletApiJakarta = "jakarta.servlet:jakarta.servlet-api:5.0.0"
7980

8081
val apacheHttpClient = "org.apache.httpcomponents.client5:httpclient5:5.0.4"
8182

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
public class io/sentry/servlet/jakarta/SentryServletContainerInitializer : jakarta/servlet/ServletContainerInitializer {
2+
public fun <init> ()V
3+
public fun onStartup (Ljava/util/Set;Ljakarta/servlet/ServletContext;)V
4+
}
5+
6+
public class io/sentry/servlet/jakarta/SentryServletRequestListener : jakarta/servlet/ServletRequestListener {
7+
public fun <init> ()V
8+
public fun <init> (Lio/sentry/IHub;)V
9+
public fun requestDestroyed (Ljakarta/servlet/ServletRequestEvent;)V
10+
public fun requestInitialized (Ljakarta/servlet/ServletRequestEvent;)V
11+
}
12+
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension
2+
import net.ltgt.gradle.errorprone.errorprone
3+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
4+
import org.springframework.boot.gradle.plugin.SpringBootPlugin
5+
6+
plugins {
7+
`java-library`
8+
kotlin("jvm")
9+
jacoco
10+
id(Config.QualityPlugins.errorProne)
11+
id(Config.QualityPlugins.gradleVersions)
12+
id(Config.BuildPlugins.springBoot) version Config.springBootVersion apply false
13+
id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion
14+
}
15+
16+
the<DependencyManagementExtension>().apply {
17+
imports {
18+
mavenBom(SpringBootPlugin.BOM_COORDINATES)
19+
}
20+
}
21+
22+
configure<JavaPluginExtension> {
23+
sourceCompatibility = JavaVersion.VERSION_1_8
24+
targetCompatibility = JavaVersion.VERSION_1_8
25+
}
26+
27+
tasks.withType<KotlinCompile>().configureEach {
28+
kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString()
29+
kotlinOptions.languageVersion = Config.springKotlinCompatibleLanguageVersion
30+
}
31+
32+
dependencies {
33+
api(projects.sentry)
34+
compileOnly(Config.Libs.servletApiJakarta)
35+
36+
compileOnly(Config.CompileOnly.nopen)
37+
errorprone(Config.CompileOnly.nopenChecker)
38+
errorprone(Config.CompileOnly.errorprone)
39+
errorprone(Config.CompileOnly.errorProneNullAway)
40+
compileOnly(Config.CompileOnly.jetbrainsAnnotations)
41+
42+
// tests
43+
testImplementation(Config.Libs.servletApiJakarta)
44+
testImplementation(projects.sentryTestSupport)
45+
testImplementation(kotlin(Config.kotlinStdLib))
46+
testImplementation(Config.TestLibs.kotlinTestJunit)
47+
testImplementation(Config.TestLibs.mockitoKotlin)
48+
testImplementation(Config.TestLibs.awaitility)
49+
}
50+
51+
configure<SourceSetContainer> {
52+
test {
53+
java.srcDir("src/test/java")
54+
}
55+
}
56+
57+
jacoco {
58+
toolVersion = Config.QualityPlugins.Jacoco.version
59+
}
60+
61+
tasks.jacocoTestReport {
62+
reports {
63+
xml.required.set(true)
64+
html.required.set(false)
65+
}
66+
}
67+
68+
tasks {
69+
jacocoTestCoverageVerification {
70+
violationRules {
71+
rule { limit { minimum = Config.QualityPlugins.Jacoco.minimumCoverage } }
72+
}
73+
}
74+
check {
75+
dependsOn(jacocoTestCoverageVerification)
76+
dependsOn(jacocoTestReport)
77+
}
78+
}
79+
repositories {
80+
mavenCentral()
81+
}
82+
val compileKotlin: KotlinCompile by tasks
83+
compileKotlin.kotlinOptions {
84+
jvmTarget = JavaVersion.VERSION_1_8.toString()
85+
languageVersion = Config.springKotlinCompatibleLanguageVersion
86+
}
87+
val compileTestKotlin: KotlinCompile by tasks
88+
compileTestKotlin.kotlinOptions {
89+
jvmTarget = JavaVersion.VERSION_1_8.toString()
90+
languageVersion = Config.springKotlinCompatibleLanguageVersion
91+
}
92+
93+
tasks.withType<JavaCompile>().configureEach {
94+
options.errorprone {
95+
check("NullAway", net.ltgt.gradle.errorprone.CheckSeverity.ERROR)
96+
option("NullAway:AnnotatedPackages", "io.sentry")
97+
}
98+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package io.sentry.servlet.jakarta;
2+
3+
import io.sentry.EventProcessor;
4+
import io.sentry.SentryEvent;
5+
import io.sentry.protocol.Request;
6+
import io.sentry.util.Objects;
7+
import jakarta.servlet.http.HttpServletRequest;
8+
import java.util.Arrays;
9+
import java.util.Collections;
10+
import java.util.Enumeration;
11+
import java.util.HashMap;
12+
import java.util.List;
13+
import java.util.Locale;
14+
import java.util.Map;
15+
import org.jetbrains.annotations.NotNull;
16+
import org.jetbrains.annotations.Nullable;
17+
18+
/** Attaches information about HTTP request to {@link SentryEvent}. */
19+
final class SentryRequestHttpServletRequestProcessor implements EventProcessor {
20+
private static final List<String> SENSITIVE_HEADERS =
21+
Arrays.asList("X-FORWARDED-FOR", "AUTHORIZATION", "COOKIE");
22+
23+
private final @NotNull HttpServletRequest httpRequest;
24+
25+
public SentryRequestHttpServletRequestProcessor(@NotNull HttpServletRequest httpRequest) {
26+
this.httpRequest = Objects.requireNonNull(httpRequest, "httpRequest is required");
27+
}
28+
29+
// httpRequest.getRequestURL() returns StringBuffer which is considered an obsolete class.
30+
@SuppressWarnings("JdkObsolete")
31+
@Override
32+
public @NotNull SentryEvent process(
33+
@NotNull SentryEvent event, @Nullable Map<String, Object> hint) {
34+
final Request sentryRequest = new Request();
35+
sentryRequest.setMethod(httpRequest.getMethod());
36+
sentryRequest.setQueryString(httpRequest.getQueryString());
37+
sentryRequest.setUrl(httpRequest.getRequestURL().toString());
38+
sentryRequest.setHeaders(resolveHeadersMap(httpRequest));
39+
40+
event.setRequest(sentryRequest);
41+
return event;
42+
}
43+
44+
private @NotNull Map<String, String> resolveHeadersMap(
45+
final @NotNull HttpServletRequest request) {
46+
final Map<String, String> headersMap = new HashMap<>();
47+
for (String headerName : Collections.list(request.getHeaderNames())) {
48+
// do not copy personal information identifiable headers
49+
if (!SENSITIVE_HEADERS.contains(headerName.toUpperCase(Locale.ROOT))) {
50+
headersMap.put(headerName, toString(request.getHeaders(headerName)));
51+
}
52+
}
53+
return headersMap;
54+
}
55+
56+
private static @Nullable String toString(final @Nullable Enumeration<String> enumeration) {
57+
return enumeration != null ? String.join(",", Collections.list(enumeration)) : null;
58+
}
59+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.sentry.servlet.jakarta;
2+
3+
import com.jakewharton.nopen.annotation.Open;
4+
import jakarta.servlet.ServletContainerInitializer;
5+
import jakarta.servlet.ServletContext;
6+
import jakarta.servlet.ServletException;
7+
import java.util.Set;
8+
import org.jetbrains.annotations.NotNull;
9+
import org.jetbrains.annotations.Nullable;
10+
11+
/**
12+
* Servlet container initializer used to add the {@link SentryServletRequestListener} to the {@link
13+
* ServletContext}.
14+
*/
15+
@Open
16+
public class SentryServletContainerInitializer implements ServletContainerInitializer {
17+
@Override
18+
public void onStartup(@Nullable Set<Class<?>> c, @NotNull ServletContext ctx)
19+
throws ServletException {
20+
ctx.addListener(SentryServletRequestListener.class);
21+
}
22+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package io.sentry.servlet.jakarta;
2+
3+
import static io.sentry.TypeCheckHint.SERVLET_REQUEST;
4+
5+
import com.jakewharton.nopen.annotation.Open;
6+
import io.sentry.Breadcrumb;
7+
import io.sentry.HubAdapter;
8+
import io.sentry.IHub;
9+
import io.sentry.util.Objects;
10+
import jakarta.servlet.ServletRequest;
11+
import jakarta.servlet.ServletRequestEvent;
12+
import jakarta.servlet.ServletRequestListener;
13+
import jakarta.servlet.http.HttpServletRequest;
14+
import java.util.HashMap;
15+
import java.util.Map;
16+
import org.jetbrains.annotations.NotNull;
17+
18+
/**
19+
* This request listener pushes a new scope into sentry that enriches a Sentry event with the
20+
* details about the current request upon sending.
21+
*/
22+
@Open
23+
public class SentryServletRequestListener implements ServletRequestListener {
24+
25+
private final IHub hub;
26+
27+
public SentryServletRequestListener(@NotNull IHub hub) {
28+
this.hub = Objects.requireNonNull(hub, "hub is required");
29+
}
30+
31+
public SentryServletRequestListener() {
32+
this(HubAdapter.getInstance());
33+
}
34+
35+
@Override
36+
public void requestDestroyed(@NotNull ServletRequestEvent servletRequestEvent) {
37+
hub.popScope();
38+
}
39+
40+
@Override
41+
public void requestInitialized(@NotNull ServletRequestEvent servletRequestEvent) {
42+
hub.pushScope();
43+
44+
final ServletRequest servletRequest = servletRequestEvent.getServletRequest();
45+
if (servletRequest instanceof HttpServletRequest) {
46+
final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
47+
48+
final Map<String, Object> hintMap = new HashMap<>();
49+
hintMap.put(SERVLET_REQUEST, httpRequest);
50+
51+
hub.addBreadcrumb(
52+
Breadcrumb.http(httpRequest.getRequestURI(), httpRequest.getMethod()), hintMap);
53+
54+
hub.configureScope(
55+
scope -> {
56+
scope.addEventProcessor(new SentryRequestHttpServletRequestProcessor(httpRequest));
57+
});
58+
}
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.sentry.servlet.jakarta.SentryServletContainerInitializer

0 commit comments

Comments
 (0)