웹서버 오류 분석
오류 수는 문제가 발생했음을 나타냅니다. 경로, 상태 코드, 릴리스, 요청 ID 등 구조화된 컨텍스트를 통해 손상된 부분을 식별하고 이를 배포와 연관시키는 데 도움이 됩니다.
가장 유용한 오류 이벤트는 사고 중에 필요한 차원을 보존합니다.
최신 웹 개발에서 모니터링과 로깅은 강력하고 안정적인 애플리케이션을 유지하는 데 중요한 측면입니다. Telemetry를 통해 개발자는 다양한 이벤트와 시스템 메트릭을 추적할 수 있으며, 이는 사용자 경험을 디버깅하고 개선하는 데 중요할 수 있습니다. 이 게시물에서는 Telemetry API를 사용하여 Express.js 웹 서버의 모든 오류를 포착하고 기록하는 방법을 살펴보겠습니다. 이 가이드에서는 Express만 다루고 있지만 아이디어는 Rails에서 Elixir 등 모든 웹 서버에 적용 가능합니다.
Telemetry 설정
데이터를 기록하려면 먼저 Telemetry를 설정해야 합니다. 이 예에서는 Telemetry JavaScript SDK를 사용합니다.
먼저 프로젝트에 Telemetry SDK를 설치합니다.
npm install telemetry-sh
그런 다음 API 키를 사용하여 애플리케이션에서 Telemetry 클라이언트를 초기화합니다.
const telemetry = require("telemetry-sh");
telemetry.init(process.env.TELEMETRY_API_KEY);
서버 환경에 TELEMETRY_API_KEY를 설정하세요. 키를 브라우저 코드에 넣거나 커밋하지 마세요.
Express 애플리케이션 만들기
다음으로 기본 Express 애플리케이션을 설정해 보겠습니다. Express가 아직 설치되어 있지 않은 경우 다음 명령을 사용하여 프로젝트에 Express를 추가할 수 있습니다.
npm install express
이제 간단한 Express 서버를 만듭니다.
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
구조화된 오류 미들웨어 추가
오류 처리기는 모든 경로 뒤에 속합니다. 비공개 값을 포함할 수 있는 원시 본문, 자격 증명, 스택 추적 또는 예외 메시지가 아닌 안전한 범주와 운영 컨텍스트를 캡처하세요.
// Add this after the real routes in your existing Express app.
app.use((err, req, res, next) => {
if (res.headersSent) return next(err);
const statusCode = Number(err.statusCode) || 500;
const rawCode = typeof err.code === "string" ? err.code : "";
const errorCode = /^[A-Z0-9_]{1,40}$/.test(rawCode)
? rawCode
: "UNCLASSIFIED_ERROR";
res.status(statusCode).json({ error: "Request failed" });
void Promise.resolve()
.then(() => telemetry.log("api_request_failed", {
route_template: req.route?.path ?? "unmatched_route",
method: req.method,
status_code: statusCode,
status: "error",
error_type: err.constructor?.name ?? "Error",
error_code: errorCode,
request_id: res.locals.requestId ?? "missing",
release: process.env.APP_RELEASE ?? "unknown",
}))
.catch(() => console.warn("Telemetry error event was not sent"));
});
이 핸들러를 실제 라우트를 처리하는 기존 Express 앱에 추가하세요. 위의 Hello World 예시만으로는 오류 이벤트가 생성되지 않습니다. 실제로 실패하는 요청을 한 번 실행한 뒤 api_request_failed에서 해당 행이 저장되었는지 쿼리로 확인하세요. 앱에서 신뢰할 수 있는 요청 ID를 생성한다면 이 핸들러보다 먼저 res.locals.requestId에 넣으세요. 이 예시는 응답을 먼저 보낸 뒤 Telemetry로 이벤트를 전송합니다. 서버리스 환경에서는 기다리지 않는 Promise에 의존하지 말고 플랫폼이 지원하는 백그라운드 작업 또는 플러시 방식을 사용하세요.
고객 식별자가 포함된 원시 경로가 아닌 /api/projects/:id와 같은 경로 템플릿을 사용하세요. 해당 오류가 워크플로에 중요한 경우 처리된 4xx 및 5xx 응답에 대해 이벤트 스키마를 동일하게 유지합니다.
오류 쿼리 및 시각화
먼저 라우트와 릴리스별 실패 건수를 확인하고, 조사에 사용할 최근 이벤트 표를 유지하세요.
SELECT
route_template,
release,
status_code,
error_code,
COUNT(*) AS failures,
MAX(timestamp_utc) AS last_seen_at
FROM api_request_failed
WHERE timestamp_utc >= now() - INTERVAL '24 hours'
GROUP BY route_template, release, status_code, error_code
ORDER BY failures DESC, last_seen_at DESC;
실제 오류율을 얻으려면 공유 status 또는 status_code 필드를 사용하여 동일한 테이블에 성공한 요청과 실패한 요청을 기록하세요. 오류 전용 테이블은 오류 순위를 지정할 수 있지만 분모를 제공할 수는 없습니다.
다음 단계
분모가 안전한 쿼리, 예시 시각화, 대시보드 레이아웃 및 알림 지침을 보려면 API 경로 레시피별 오류율을 사용하세요. 사고 보기에서 정확성과 속도를 모두 다룰 수 있도록 API 대기 시간 백분위수와 함께 사용하세요.