Sentry
Sentry๋ ์ค๋ฅ ๋๋ ์์ธ๋ฅผ ์ถ์ ํ๊ธฐ ์ํ ๋๊ตฌ๋ก ํ์ฌ์์ ์์คํ ์ ๊ตฌ์ฑํ๋ ์ธ์ด์ธ ์๋ฐ, ํ์ด์ฌ, Vue ๋ฑ ๋ค์ํ ์ธ์ด ํ๋ซํผ๊ณผ์ ์ฐ๋์ ์ง์ํ๋ค. Sentry๋ฅผ ๋์ ํ๊ฒ ๋๋ ์ด์ ๋ ๊ฐ๋ฐ์๊ฐ ํ ์คํธํ๋ ๊ณผ์ ์์ ๋ฐ๊ฒฌ๋์ง ์๊ณ QA ์์ง๋์ด๊ฐ ํ ์คํธํ๋ ๊ณผ์ ํน์ ๊ณ ๊ฐ ํ ์คํธ ํ๊ฒฝ์์ ๋ง์ง๋ง์ผ๋ก ๊ฒ์ํ๋ ๊ณผ์ ์์ ๋ฐ๊ฒฌ๋์ง ์์ ์ทจ์ฝ์ ์ ์์์ฑ๊ธฐ ์ํจ์ด๋ค. ๊ทธ๋์ ๊ฒฝํํ๋ ๋๋ถ๋ถ์ ํ์ง ์ด์๋ ๋ช ํํ์ง ์์ ์๊ตฌ์ฌํญ๊ณผ ๋ถ์กฑํ ๋ฆฌ๋ทฐ ๊ณผ์ ์ผ๋ก ์ธํด์ ์ธํ๋ผ ๊ตฌ์ฑ๊ณผ ์ฌ์ฉ์์ ๋์์ ๋ฐ๋ผ ๋ฐ์ํ๋ ์ํฉ์ด ๋๋ถ๋ถ์ด์๋ค๊ณ ์๊ฐํ๋ค.
์์คํ ์ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๊ณ ์์ธกํ๋ ๊ธฐ๋ฅ์ ๊ฒฝ์ฐ ๋ณ๋์ ํ์ด์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ด๋นํ๋ ํ์์ ๊ด๋ฆฌํ๊ณ ์์ผ๋ฏ๋ก Sentry๋ฅผ ๋์ ํ์ง ์๊ณ ์๋ค.
Self-Hosted Sentry
Self-Hosted Sentry์์ ์ ๊ณตํ๋ ์ค์น ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ์ฌ On-Premise ํ๊ฒฝ์์ Sentry๋ฅผ ๊ตฌ์ฑํ๊ณ ์คํํ์๋ค. ์ค์น ์คํฌ๋ฆฝํธ์ ๋์ปค ์ปดํฌ์ฆ ๋ฌธ์๋ฅผ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์ ์คํ ์์ฒด๋ ๊ฐ๋จํ๋ฐ ์๊ฐ๋ณด๋ค ๋ง์ ์ปจํ ์ด๋๊ฐ ๊ตฌ๋๋๋ ๋ถ๋ถ์ด ์๋ค. ์ธํ๋ผ ๋น์ฉ์ ์๋ผ๊ณ ์ ๋ฆฌ์์ค ์์ ์ฌ์ฉ๋ฅ ์ด ์ ์กฐํ ์ธ์คํด์ค์ ์คํํ ์ํ์ธ๋ฐ ๋ณ๋์ ์ธ์คํด์ค๋ก ๋ถ๋ฆฌํ๋ ๊ฒ์ ๊ณ ๋ คํ๊ณ ์๋ค.
Keep in mind that all this setup uses single-nodes for all services, including Kafka. For larger loads, youโd need a beefy machine with lots of RAM and disk storage. To scale up even further, you are very likely to use clusters with a more complex tool, such as Kubernetes. Due to self-hosted installationsโ very custom nature, we do not offer any recommendations or guidance around scaling up.
Spring Boot
์์คํ ์ ๊ตฌ์ฑํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ Spring Boot๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด sentry-spring-boot-starter๋ฅผ ์ถ๊ฐํ์ฌ ์๋ ๊ตฌ์ฑ์ ์ฌ์ฉํ ์ ์๋ค.
implementation platform('io.sentry:sentry-bom:6.19.0')
implementation 'io.sentry:sentry-spring-boot-starter'
When you are using multiple Sentry dependencies, you can avoid specifying the version of each dependency with a BOM or Bill Of Materials.
๊ฐ๋ฐ์๊ฐ ์ฒดํฌํ์ง ์์ ์์ธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์์ง๋๋ฉฐ @ExceptionHandler๋ฅผ ์ ์ธํ ์์ธ ์ฒ๋ฆฌ ํจ์์์ Sentry ์๋ฒ๋ก ์์ธ ์ ๋ณด๋ฅผ ์ ๋ฌํ๋๋ก ์ฝ๋๋ฅผ ๊ตฌํํ๋ฉด ๋๋ค.
import io.sentry.Sentry;
try {
throw new Exception("This is a test.");
} catch (Exception e) {
Sentry.captureException(e);
}
์์ธ ์์ง ์ ๋ณด ์ปค์คํฐ๋ง์ด์ง
Advanced Usage ๋ฌธ์์ ๋ฐ๋ฅด๋ฉด ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋ Sentry์ ์์ง๋ ์ค๋ฅ๋ฅผ ๋ณด๋ด๊ธฐ ์ง์ ์ ์กฐ์ํ ์ ์๋ ์ฝ๋ฐฑ์ ์ ๊ณตํ๊ณ ์๋ค. ๋ ธ์ถ๋๋ฉด ์๋๋ ์ ๋ณด๋ ๋ช ์์ ์ผ๋ก ์ ๊ฑฐํ ์ ์์ผ๋ฉฐ ์์งํ์ง ์์ ์์ธ ํด๋์ค์ ๋ํด์๋ Ignored Exceptions For Type์ ์ง์ ํ์ฌ ์ ์ธ์ํฌ ์ ์๋ค.
sentry.ignored-exceptions-for-type:
- org.springframework.security.access.AccessDeniedException
- org.springframework.security.authentication.BadCredentialsException
ํน์ ์์ธ ํด๋์ค ์ด์ธ์ ์ผ๋ถ ์๋ฌ ์ด๋ฒคํธ๋ฅผ ํํฐ๋งํ๊ณ ์ ํ๋ค๋ฉด SentryOptions.BeforeSendCallback ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ํด๋์ค๋ฅผ ๋น์ผ๋ก ๋ฑ๋กํ์ฌ ์ฒ๋ฆฌํ ์ ์๋ค.
@Component
public class CustomBeforeSendCallback implements SentryOptions.BeforeSendCallback {
@Override
public SentryEvent execute(SentryEvent event, Hint hint) {
// Example: Never send server name in events
event.setServerName(null);
return event;
}
}
์ฌ์ฉ์ ์ ๋ณด ์์งํ๊ธฐ
Spring MVC ๋ชจ๋์ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด Record User Information ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์ฌ ์ฌ์ฉ์ ์ด๋ฆ(Principal#name)๊ณผ IP ์ฃผ์๋ฅผ ์์งํ๋๋ก ํ์ฑํ ํ ์ ์๋ค. ๋ง์ฝ, ์คํ๋ง ์ํ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ธ์ฆ ์ฒด๊ณ๋ฅผ ๊ตฌํํ์๋ค๋ฉด UserDetails์ Username์ด ์ค๋ฅ์ ํจ๊ป ๊ธฐ๋ก๋๋ค.
sentry.send-default-pii: true
๋น๋๊ธฐ ํจ์ ์ฒ๋ฆฌ
Sentryโs SDK for Java๋ ์ค์ฝํ์ ์ปจํ ์คํธ๋ฅผ ThreadLocal์ ์ ์ฅํ๋๋ก ๊ตฌํ๋์ด์๋ค. Async Methods ๋ฌธ์์ ๋ฐ๋ฅด๋ฉด Sentry Context์์ ๋น๋๊ธฐ ํจ์์ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๊ทผํ๊ธฐ ์ํด์๋ ThreadPoolTaskExecutor ๋ด์ SentryTaskDecorator๋ฅผ ์ ์ฉํด์ผ ํ๋ค๊ณ ์ค๋ช ํ๋ค.
@Configuration(proxyBeanMethods = false)
public class SentryConfiguration {
@Bean
public SentryTaskDecorator sentryTaskDecorator() {
return new SentryTaskDecorator();
}
}
@Configuration
public class AsyncMethodConfiguration implements AsyncConfigurer {
private final SentryTaskDecorator sentryTaskDecorator;
public AsyncMethodConfiguration(SentryTaskDecorator sentryTaskDecorator) {
this.sentryTaskDecorator = sentryTaskDecorator;
}
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(sentryTaskDecorator);
executor.initialize();
return executor;
}
}
๋ฉ๋ชจ๋ฆฌ ๋์
TransactionPerfomanceCollector์ ์ํ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฌธ์ ๊ฐ ์์์ผ๋ฉฐ 6.13.0 ๊ทธ๋ฆฌ๊ณ 6.13.1 ์์ OOM ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์๋ค.
- 6.13.0 - Prevent OOM by disabling TransactionPerformanceCollector for now (#2498)
- 6.13.1 - Fix transaction performance collector oom (#2505)
์ด์ธ์๋ ์ง์์ ์ผ๋ก ์ฑ๋ฅ ๊ฐ์ ๊ณผ ์ฌ๋ฌ๊ฐ์ง ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋๊ณ ์์ผ๋ ์ฃผ๊ธฐ์ ์ผ๋ก Sentry ์๋ฒ๋ฅผ ์ ๊ทธ๋ ์ด๋ํด์ผํ ํ์์ฑ์ด ์์ด๋ณด์ธ๋ค.
Vue
Sentry for Vue๋ฅผ ์ฐธ๊ณ ํ์ฌ Vue ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฐ์ํ๋ ์ค๋ฅ๋ค๋ ์์งํ ์ ์๋ค.
npm install --save @sentry/vue
import Vue from 'vue'
import * as Sentry from '@sentry/vue'
import axios from 'axios';
export function init(router) {
Sentry.init({
Vue,
dsn: process.env.SENTRY_DSN,
envinroment: process.env.NODE_ENV,
release: process.env.SENTRY_RELEASE
integrations: [
new Sentry.BrowserTracing({
routingInstrumentation: Sentry.vueRouterInstrumentation(router)
}),
],
tracingOptions: {
trackComponents: true
},
attachProps: true,
logErrors: true,
tracesSampleRate: 1.0,
})
}
process.env.SENTRY_DSN์ process.env.SENTRY_RELEASE๋ ๋น๋ํ๋ ๊ณผ์ ์์ ์ฃผ์ ๋๋๋ก ๊ตฌํํด์ผํ๋ฉฐ process.env.SENTRY_RELEASE๋ SourceMap์ ์ ๋ก๋ํ๋ ๊ณผ์ ์์ ๋ฑ๋กํ๋ ๋ฆด๋ฆฌ์ฆ ๋ฒ์ ๊ณผ ๋์ผํด์ผํ๋ค.
API ์ค๋ฅ ์ ์์ฒญ๊ณผ ์๋ต ์ ๋ณด ์์งํ๊ธฐ
Browser JavaScript SDK์์๋ ๊ธฐ๋ณธ์ ์ธ ์คํฌ๋ฆฝํธ ์ค๋ฅ๋ ์๋์ผ๋ก ์์ง๋๋ฉฐ Axios์ ๊ฐ์ HTTP ํด๋ผ์ด์ธํธ ์์ฒญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์๋์ ๊ฐ์ด API ์์ฒญ ๊ณผ์ ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค๋ฉด Sentry๋ก ์์ง๋๋๋ก ์์ฑํด์ผํ๋ค.
axios.interceptors.response.use(
response => response,
error => {
const { url, params, data } = error.config
Sentry.setContext('Request', {
url,
params,
data
})
const { status, data } = error.config
Sentry.setContext('Response', {
status,
data
})
Sentry.captureException(error)
return Promise.reject(error)
})
์ธ์ฆ ์ฌ์ฉ์ ์ ๋ณด ์์งํ๊ธฐ
Identify Users ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ๋ฉด ์ฌ์ฉ์ ์ด๋ฆ๊ณผ ์์ดํผ ์ฃผ์๋ฅผ ์์งํ ์ ์๋๋ก ๊ตฌ์ฑํ ์ ์๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก๋ ์์ดํผ ์ฃผ์๊ฐ ์์ง๋๋๋ฐ ์ธ์ฆ๋ ์ฌ์ฉ์๋ผ๋ฉด ์ฌ์ฉ์ ์๋ณ ์์ด๋๋ ์ด๋ฆ์ ๊ฐ์ ธ์ฌ ์ ์์ผ๋ฏ๋ก ์๋์ ๊ฐ์ด ๋ณด๋ค ์ ํํ ์ ๋ณด๋ฅผ ์์งํ ์ ์๋ค.
Sentry.setUser({
id: window.auth.userId,
username: window.auth.userName,
ip_address: '{{auto}}'
})
If the userโs ip_address is set to โโ, Sentry will infer the IP address from the connection between your app and Sentryโs server.
์คํ ํธ๋ ์ด์ค ์ถ์ ํ๊ธฐ
์ผ๋ฐ์ ์ผ๋ก Vue์ ๊ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น๋๋์ด ๋ฐฐํฌ๋๋ ๊ฒฝ์ฐ์ ๋ฒ๋ค์ ์ต์ํํ๋ ๊ณผ์ ์ ๊ฑฐ์น๊ฒ ๋๋ฏ๋ก ์ค๋ฅ๊ฐ Sentry์ ์์ง๋๋๋ผ๋ ์คํ ํธ๋ ์ด์ค๋ฅผ ํตํด ์์ธ์ด ๋๋ ์ฝ๋ ๋ผ์ธ์ ์ ๋๋ก ์ฐพ์๊ฐ๊ธฐ ํ๋ค ๊ฐ๋ฅ์ฑ์ด ์๋ค. ๋ธ๋ผ์ฐ์ ๊ฐ ์๋ Sentry ์์ ๋งํผ์ ์คํ ํธ๋ ์ด์ค๋ฅผ ๊น๋ํ๊ฒ ๋ณผ ์ ์๋๋ก SourceMap์ ์ง์ํ๊ณ ์๋ค. ๋ค์์ Webpack์ ๋ฒ๋ค๋ฌ๋ก์จ ์ฌ์ฉํ๊ณ ์์๋ ์ฌ์ฉํ ์ ์๋ ํ๋ฌ๊ทธ์ธ์ ์ค์นํ๋ ์์๋ฅผ ๋ณด์ฌ์ค๋ค.
npm install --save-dev @sentry/webpack-plugin
const SentryWebpackPlugin = require("@sentry/webpack-plugin")
module.exports = {
devtool: "source-map",
plugins: [
new SentryWebpackPlugin({
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
include: "./dist",
ignore: ["node_modules", "webpack.config.js", "webpack.config.prod.js"],
authToken: process.env.SENTRY_AUTH_TOKEN,
release: process.env.SENTRY_RELEASE
})
]
}
SENTRY_RELEASE๋ ๋น๋์ ๋ฐํ์ ์์ ์ ๊ฐ์ ๋์ผํ๊ฒ ์ฌ์ฉํด์ผ Sentry์์ ์ ๋๋ก ์ถ์ ํ ์ ์์์ ์ฃผ์ํด์ผํ๋ค. ๋ฐํ์ ๊ตฌ์ฑ ์ ์ฌ์ฉํ๋ DSN๊ฐ ์๋๋ผ Sentry ์ฌ์ฉ์์ ๋ํ ํ ํฐ์ ๋ฐ๊ธํด์ผํ๋ฉฐ ํ๋ก์ ํธ ์ ๋ณด๋ ํฌํจํด์ผํ๋ค.
๋๋ง์น๋ฉฐ
์นด์นด์คํ์ด์์ ๊ณต์ ํ Sentry๋ก ์ฐ์ํ๊ฒ ํ๋ก ํธ์๋ ์๋ฌ ์ถ์ ํ๊ธฐ์ ๋ผ์ธ์์ ๊ณต์ ํ Sentry๋ก ์ฌ๋ด ์๋ฌ ๋ก๊ทธ ์์ง ์์คํ ๊ตฌ์ถํ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ์ฌ Sentry ํ์ฉ์ ๋ํด ๋ ์์ธํ ์์๊ฐ ์ ์๋ค. ๊ฐ์ธ์ ์ผ๋ก ๋์ ์ ์ฌ์๋ณด์ด์ง๋ง ์ํ๋ ๋ฐฉ์๋๋ก ์ปค์คํฐ๋ง์ด์ง ํ๊ธฐ์๋ ์๊ฐ๋ณด๋ค ์ด๋ ค์ด ๊ฒ ๊ฐ๋ค. ์๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๋ค๋ฅด๊ฒ ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ Data Source Name (DSN)๊ฐ ๋ธ๋ผ์ฐ์ ์ ๋ ธ์ถ๋๋ฏ๋ก ๋ณด์ ๊ด์ ์์๋ ํ ์คํธ ํ๊ฒฝ์๋ง ๋์ ํด์ผํ ๊ฒ์ผ๋ก ์๊ฐ๋๋ค.