diff --git a/build.gradle.kts b/build.gradle.kts index 7f16e9c..bd05ee3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,6 +13,7 @@ plugins { alias(libs.plugins.asciidoctor.convert) apply false alias(libs.plugins.epages.restdocs.api.spec) apply false alias(libs.plugins.hidetake.swagger.generator) apply false + alias(libs.plugins.sentry.jvm.gradle) apply false } allprojects { diff --git a/docker/DockerfileDev b/docker/DockerfileDev index 2918072..d0a13a4 100644 --- a/docker/DockerfileDev +++ b/docker/DockerfileDev @@ -1,9 +1,17 @@ +FROM alpine:latest AS agent-downloader +RUN wget -O /sentry-opentelemetry-agent.jar https://get.sentry.io/sentry-opentelemetry-agent.jar + FROM amazoncorretto:21 ENV TZ="Asia/Seoul" -RUN mkdir -p /service/pida +RUN mkdir -p /service/pida /opt/sentry +COPY --from=agent-downloader /sentry-opentelemetry-agent.jar /opt/sentry/agent.jar COPY pida-core/core-api/build/libs/core-api-0.0.1.jar /service/pida/core-api-0.0.1.jar EXPOSE 8080 -CMD java -jar -Xmx2048m /service/pida/core-api-0.0.1.jar +CMD java \ + -javaagent:/opt/sentry/agent.jar \ + -Dsentry.auto.init=false \ + -Xmx2048m \ + -jar /service/pida/core-api-0.0.1.jar diff --git a/docker/DockerfileProd b/docker/DockerfileProd index 1b4301e..4b5cd08 100644 --- a/docker/DockerfileProd +++ b/docker/DockerfileProd @@ -1,15 +1,20 @@ +FROM alpine:latest AS agent-downloader +RUN wget -O /sentry-opentelemetry-agent.jar https://get.sentry.io/sentry-opentelemetry-agent.jar + FROM amazoncorretto:21 ENV TZ="Asia/Seoul" ARG PROFILE ENV PROFILE=${PROFILE} -RUN mkdir -p /service/pida - +RUN mkdir -p /service/pida /opt/sentry +COPY --from=agent-downloader /sentry-opentelemetry-agent.jar /opt/sentry/agent.jar COPY pida-core/core-api/build/libs/core-api-0.0.1.jar /service/pida/core-api-0.0.1.jar EXPOSE 8080 CMD java \ + -javaagent:/opt/sentry/agent.jar \ + -Dsentry.auto.init=false \ -Dspring.profiles.active=${PROFILE} \ -jar /service/pida/core-api-0.0.1.jar diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 04fc4c0..3c0cb92 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,7 +37,8 @@ hidetake_swagger_generator = "2.18.2" swaggerVersion = "2.8.5" # Sentry version -sentry = "7.3.0" +sentry = "8.31.0" +sentry_gradle = "6.0.0" # AWS version aws = "2.40.13" @@ -79,6 +80,9 @@ ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" } spring_boot = { id = "org.springframework.boot", version.ref = "spring_boot" } spring_dependency_management = { id = "io.spring.dependency-management", version.ref = "spring_dependency_management" } +# Sentry Plugin +sentry_jvm_gradle = { id = "io.sentry.jvm.gradle", version.ref = "sentry_gradle" } + # Api-Docs Plugins asciidoctor_convert = { id = "org.asciidoctor.jvm.convert", version.ref = "asciidoctor_convert" } epages_restdocs_api_spec = { id = "com.epages.restdocs-api-spec", version.ref = "epages_restdocs_api_spec" } @@ -184,6 +188,8 @@ epages_restdocs_api_spec_restassured = { module = "com.epages:restdocs-api-spec- # Monitoring & Logging Libraries micrometer_tracing_bridge_brave = { module = "io.micrometer:micrometer-tracing-bridge-brave" } micrometer_registry_prometheus = { module = "io.micrometer:micrometer-registry-prometheus" } +sentry_spring_boot_starter_jakarta = { module = "io.sentry:sentry-spring-boot-starter-jakarta", version.ref = "sentry" } +sentry_opentelemetry_agent = { module = "io.sentry:sentry-opentelemetry-agent", version.ref = "sentry" } slf4j = { module = "org.slf4j:slf4j-api", version = "2.0.9" } # AWS Libraries diff --git a/pida-core/core-api/build.gradle.kts b/pida-core/core-api/build.gradle.kts index e6a21c5..c493761 100644 --- a/pida-core/core-api/build.gradle.kts +++ b/pida-core/core-api/build.gradle.kts @@ -1,3 +1,18 @@ +plugins { + id("io.sentry.jvm.gradle") +} + +val hasSentryToken = System.getenv("SENTRY_AUTH_TOKEN") != null + +sentry { + includeSourceContext.set(hasSentryToken) + org.set("pida-za") + projectName.set("pida") + authToken.set(System.getenv("SENTRY_AUTH_TOKEN")) +} + +val sentryAgent: Configuration by configurations.creating + tasks.getByName("bootJar") { enabled = true } @@ -6,7 +21,18 @@ tasks.getByName("jar") { enabled = false } +tasks.register("copySentryAgent") { + from(sentryAgent) + into(layout.buildDirectory.dir("agent")) + rename { "sentry-opentelemetry-agent.jar" } +} + +tasks.named("build") { + dependsOn("copySentryAgent") +} + dependencies { + sentryAgent(libs.sentry.opentelemetry.agent) implementation(libs.spring.boot.starter.web) implementation(libs.spring.boot.starter.aop) implementation(libs.spring.boot.starter.validation) diff --git a/pida-supports/monitoring/build.gradle.kts b/pida-supports/monitoring/build.gradle.kts index 3a62eb8..b7b0142 100644 --- a/pida-supports/monitoring/build.gradle.kts +++ b/pida-supports/monitoring/build.gradle.kts @@ -1,4 +1,6 @@ dependencies { implementation(libs.spring.boot.starter.actuator) implementation(libs.micrometer.registry.prometheus) + implementation(libs.sentry.spring.boot.starter.jakarta) + implementation(project(":pida-core:core-domain")) } diff --git a/pida-supports/monitoring/src/main/kotlin/com/pida/monitoring/sentry/SentryFingerprintCallback.kt b/pida-supports/monitoring/src/main/kotlin/com/pida/monitoring/sentry/SentryFingerprintCallback.kt new file mode 100644 index 0000000..706e810 --- /dev/null +++ b/pida-supports/monitoring/src/main/kotlin/com/pida/monitoring/sentry/SentryFingerprintCallback.kt @@ -0,0 +1,44 @@ +package com.pida.monitoring.sentry + +import com.pida.support.error.AuthenticationErrorException +import com.pida.support.error.ErrorException +import io.sentry.Hint +import io.sentry.SentryEvent +import io.sentry.SentryOptions +import org.springframework.stereotype.Component + +@Component +class SentryFingerprintCallback : SentryOptions.BeforeSendCallback { + override fun execute( + event: SentryEvent, + hint: Hint, + ): SentryEvent { + val exception = event.throwable ?: return event + + val fingerprint = resolveFingerprint(exception) + if (fingerprint != null) { + event.fingerprints = fingerprint + } + + return event + } + + private fun resolveFingerprint(exception: Throwable): List? = + when (exception) { + is ErrorException -> + listOf( + "ErrorException", + exception.errorType.kind.name, + exception.errorType.name, + ) + + is AuthenticationErrorException -> + listOf( + "AuthenticationErrorException", + exception.authenticationErrorType.kind.name, + exception.authenticationErrorType.name, + ) + + else -> null + } +} diff --git a/pida-supports/monitoring/src/main/resources/monitoring.yml b/pida-supports/monitoring/src/main/resources/monitoring.yml index 4c6e2f0..f762fac 100644 --- a/pida-supports/monitoring/src/main/resources/monitoring.yml +++ b/pida-supports/monitoring/src/main/resources/monitoring.yml @@ -5,4 +5,21 @@ management: include: health, prometheus health: defaults: - enabled: false \ No newline at end of file + enabled: false + +sentry: + dsn: ${SENTRY_DSN} + traces-sample-rate: 1.0 + environment: ${SPRING_PROFILES_ACTIVE:local} + exception-resolver-order: -2147483648 + logging: + minimum-event-level: error + minimum-breadcrumb-level: info +--- +spring: + config: + activate: + on-profile: prod + +sentry: + traces-sample-rate: 0.1