@channel.io/be-user-chat-mcp
Version:
Backend UserChat Model Context Protocol server for Channel.io
156 lines • 7.19 kB
JavaScript
const SENTRY_ORGANIZATION_SLUG = "channel-io"; // 요청에 따라 하드코딩
// Sentry API 기본 URL
const SENTRY_API_BASE_URL = "https://us.sentry.io/api/0";
/**
* 특정 프로젝트의 Sentry 로그 (Issues)를 검색합니다.
* Sentry API는 'Issues'라는 용어를 사용하며, 이는 그룹화된 오류들을 의미합니다.
* @param projectSlug Sentry 프로젝트 슬러그 (예: 'your-project-name')
* @param query 검색 쿼리 (예: "user.id:123 error.message:\"Database timeout\"")
* @param limit 반환할 결과 수 (기본값: 50)
* @param cursor 페이징을 위한 커서 (옵션)
* @param statsPeriod 검색 기간 (기본값: "24h")
* @returns 검색된 Sentry 이슈 목록
*/
export async function searchSentryLogs(projectSlug, query, statsPeriod = "24h", limit = 50, cursor, context) {
if (!projectSlug) {
throw new Error("Sentry project slug must be provided.");
}
const url = new URL(`${SENTRY_API_BASE_URL}/projects/${SENTRY_ORGANIZATION_SLUG}/${projectSlug}/issues/`);
if (query) {
url.searchParams.append("query", query);
}
url.searchParams.append("statsPeriod", statsPeriod); // 전달받은 statsPeriod 사용
url.searchParams.append("limit", String(limit));
if (cursor) {
url.searchParams.append("cursor", cursor);
}
try {
const response = await fetch(url.toString(), {
headers: {
Authorization: `Bearer ${context.sentryAuthToken}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const errorText = await response.text();
try {
const errorData = JSON.parse(errorText);
throw new Error(`Sentry API Error (${response.status}) for project ${projectSlug}: ${errorData.detail || errorText}`);
}
catch (e) {
const errorMessage = e instanceof Error ? e.message : String(e);
throw new Error(`Sentry API Error (${response.status}) for project ${projectSlug}: ${errorText}. Parsing error: ${errorMessage}`);
}
}
const issues = (await response.json());
// 페이징을 위한 Link 헤더 처리 로직이 필요하다면 여기에 추가
// const linkHeader = response.headers.get('Link');
return issues;
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`Error searching Sentry logs for project ${projectSlug}: ${errorMessage}`, error);
// Sentry SDK가 설정되어 있다면, 이 에러를 Sentry로 전송할 수 있습니다.
// if (Sentry.getCurrentHub().getClient()) { Sentry.captureException(error); }
throw error; // 에러를 다시 throw하여 호출 측에서 처리할 수 있도록 함
}
}
/**
* 특정 프로젝트의 Sentry 이벤트들을 검색합니다.
* @param projectSlug Sentry 프로젝트 슬러그
* @param query 검색 쿼리
* @param limit 반환할 결과 수
* @param cursor 페이징 커서
* @returns 검색된 Sentry 이벤트 목록
*/
export async function searchSentryEvents(projectSlug, query, limit = 50, cursor, context) {
// SentryEvent[] 반환
if (!projectSlug) {
throw new Error("Sentry project slug must be provided.");
}
const url = new URL(`${SENTRY_API_BASE_URL}/projects/${SENTRY_ORGANIZATION_SLUG}/${projectSlug}/events/`);
if (query) {
url.searchParams.append("query", query);
}
url.searchParams.append("limit", String(limit));
if (cursor) {
url.searchParams.append("cursor", cursor);
}
try {
const response = await fetch(url.toString(), {
headers: {
Authorization: `Bearer ${context.sentryAuthToken}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const errorText = await response.text();
try {
const errorData = JSON.parse(errorText);
throw new Error(`Sentry API Error (${response.status}) searching events in project ${projectSlug} with query "${query}": ${errorData.detail || errorText}`);
}
catch (e) {
const errorMessage = e instanceof Error ? e.message : String(e);
throw new Error(`Sentry API Error (${response.status}) searching events in project ${projectSlug} with query "${query}": ${errorText}. Parsing error: ${errorMessage}`);
}
}
const events = (await response.json());
return events;
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`Error searching Sentry events in project ${projectSlug} with query "${query}": ${errorMessage}`, error);
throw error;
}
}
/**
* 특정 Sentry 이슈(로그 그룹)의 이벤트 세부 정보를 가져옵니다.
* eventId가 제공되면 해당 특정 이벤트를, 그렇지 않으면 이슈의 최신 이벤트를 가져옵니다.
* @param issueId Sentry 이슈 ID
* @param eventId (선택적) Sentry 이벤트 ID
* @returns 해당 이벤트의 세부 정보
*/
export async function getSentryLogDetails(issueId, eventId, context) {
if (!issueId) {
throw new Error("Sentry issue ID must be provided.");
}
let urlString; // 변수명을 url에서 urlString으로 변경 (URL 객체와 혼동 방지)
let contextDescription;
if (eventId) {
// 특정 이벤트를 가져오는 경우
urlString = `${SENTRY_API_BASE_URL}/projects/${SENTRY_ORGANIZATION_SLUG}/*/events/${eventId}/`;
contextDescription = `event ${eventId} in issue ${issueId}`;
}
else {
// 이슈의 최신 이벤트를 가져오는 경우
urlString = `${SENTRY_API_BASE_URL}/issues/${issueId}/events/latest/`;
contextDescription = `latest event in issue ${issueId}`;
}
try {
const response = await fetch(urlString, {
headers: {
Authorization: `Bearer ${context.sentryAuthToken}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const errorText = await response.text();
try {
const errorData = JSON.parse(errorText);
throw new Error(`Sentry API Error (${response.status}) for ${contextDescription}: ${errorData.detail || errorText}`);
}
catch (e) {
const errorMessage = e instanceof Error ? e.message : String(e);
throw new Error(`Sentry API Error (${response.status}) for ${contextDescription}: ${errorText}. Parsing error: ${errorMessage}`);
}
}
const eventDetails = (await response.json());
return eventDetails;
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`Error fetching Sentry log details for ${contextDescription}: ${errorMessage}`, error);
throw error;
}
}
//# sourceMappingURL=sentry.service.js.map