안녕하세요 Lovefield입니다.
이번에 Nuxt로 넘어오면서 개발 구조가 마이크로 서비스화 되었습니다. 마이크로 서비스화가 되면서 사이트 접속시 요청에 대해서 `front-end -> api -> back-end` 순으로 실행됩니다. 최소 3번의 요청이 합쳐져야 페이지 하나를 표시 할 수 있게 되었죠, 이 상태에서 AWS x-ray를 연결하는 방법에 대한 글입니다.
먼저 Nuxt에 “server middleware”를 등록하고 Axios 설정을 합니다.
…
modules: ["@nuxtjs/axios"],
axios:{
proxy: true
},
proxy: {
"/api/": {
target: "BACKEND-URL",
pathRewrite: {
"^/api/": "/api/v1/",
},
},
},
serverMiddleware : ["serverMiddleware/x-ray"]
…
클라이언트는 프론트서버에 화면에 대한 요청과 API에 대한 요청을 하게됩니다. 즉 이 두가지를 구분해야함에 유의해서 코드를 작성합니다. x-ray역할을 할 파일인 “x-ray.js”를 “serverMiddleware”폴더에 만들어줍니다.
// x-ray는 소캣통신을 하기때문에 “dgram” 모듈을 사용합니다. (노드 기본 모듈)
import dgram from "dgram";
// 구분자 아이디 생성용 함수 a~f + 0~9로 이루어진 16자리여야 합니다.
function createRequestId() {
let possible = "abcdef0123456789";
let text = "";
for (let i = 0; i < 16; i += 1) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
// 실제 작동 코드 부분입니다.
export default function (req, res, next) {
let headers = req && req.headers ? Object.assign({}, req.headers) : {};
let traceHeader = headers["x-amzn-trace-id"]; // aws는 LB가 리퀘스트 헤더에 x-amzn-trace-id를 항상 붙여줍니다.
let requestURL = req.url;
let apiReg = new RegExp("\\/api", "i");
if (traceHeader !== undefined) {
let server = dgram.createSocket("udp4");
let requestDate = new Date().getTime() / 1000;
let requestId = createRequestId();
let isApiRequest = apiReg.test(requestURL);
let traceId = traceHeader.substr(5, 35);
if (isApiRequest == false) { // api 일경우 request에 데이터를 추가합니다. (axios plugin에서 사용)
req.requestId = requestId;
req.traceId = traceId;
}
// response가 끝나면 실행합니다.
res.on("finish", () => {
let jsonData = {
name: `appname`,
id: requestId,
origin: "AWS::EC2::Instance",
trace_id: traceId,
start_time: requestDate,
end_time: new Date().getTime() / 1000,
http: {
request: {
url: req.url,
method: req.method,
user_agent: headers["user-agent"],
x_forwarded_for: true,
},
response: {
status: res.statusCode,
},
},
};
if (isApiRequest == true) {
jsonData.type = "subsegment";
jsonData.parent_id = headers["requestid"];
}
let message = Buffer.from(`{"format": "json", "version": 1}\n` + JSON.stringify(jsonData));
server.send(message, 2000,"localhost", (err) => { // x-ray 는 로컬로 정보를 정송합니다.
server.close();
});
});
}
next();
}
기본적인 동작 코드는 위와 같습니다.
이제 axios plugin에서 몇가지 설정을 더 해야합니다.
export default function ({ req, $axios }) {
let requestId = req ? req.requestId : undefined;
$axios.onRequest((config) => {
if (requestId !== undefined) {
config.headers.common["requestid"] = requestId;
config.headers.common["X-Amzn-Trace-Id"] = `Root=${req.traceId};Parent=${requestId}`;
}
});
}
리퀘스트를 행할때 `x-ray.js` 에서 설정한 `requestId`가 있을경우 api request에도 해당 값을 넣어줍니다.
앱에서 설정할 사항은 전부 끝났습니다. 이제 AWS 인스턴스 에 접속해서 x-ray를 실행해줘야 하는데요.
인스턴스에 x-ray 설치 를 진행한 후에 `sudo service xray start`후 `sudo service xray status` 로 상태를 체크합니다.x-ray 기록은 CludWatch -> x-ray 기록 에서 보실수 있습니다.