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)๊ฐ ๋ธ๋ผ์ฐ์ ์ ๋ ธ์ถ๋๋ฏ๋ก ๋ณด์ ๊ด์ ์์๋ ํ ์คํธ ํ๊ฒฝ์๋ง ๋์ ํด์ผํ ๊ฒ์ผ๋ก ์๊ฐ๋๋ค.