아하 REST API 서버 개발 (13)

finallee
aha.official
Published in
10 min readFeb 14, 2019

안녕하세요!

정말 오랜만이죠?

원래는 좀 더 일찍 찾아뵙고 싶었는데, 일이다 연휴다 너무 정신없이 바빠서 강좌가 많이 늦어졌습니다.

네 사실….주말에 자느라….

어찌됐던 늦어진 만큼 알찬 내용으로 찾아왔습니다!

Logger

서비스를 배포해 보신 분이라면 누구나 공감할 이야기지만, 서비스는 개발할때가 가장 신나고 배포후에 운영할때가 가장 고통스럽습니다.

특히 서비스가 에러라도 내고 죽어버린다면 자다가도 벌떡 일어나서 회사에 출근해서 수정을 해야만 합니다.

근데.

자리에 앉았는데.

로그가 없어!

싸랑!!!!!!!!!!!!! ❤️

진짜 이런 상황에 놓이게 되면 멘탈이 쿠크다스처럼 바삭하게 깨져버립니다.

따라서 배포 코드에서 로거는 정말 정말 정말 중요합니다.

특히 에러 로깅은 그 어떤 부분보다 세심하게 신경써야합니다.

특히 node 기반 서버들은 Logger 를 잘 쓰기가 굉장히 어렵기 때문에 많은 공부를 하셔야 원하는 형식과 내용을 잘 기록할 수 있습니다.

이를 위해선 일단 morgan 모듈과 winston 모듈이 필요합니다.

npm install morgan winston

여기서 잠깐. Logger 가 필요한데 대체 왜 모듈을 두개나 설치해야 하는 것일까요?

그건 바로 morganrequestresponse 를 정말 깔끔하게 formatting 해주는 모듈입니다.

그렇게 formatting 된 logjson 형식으로 dump 로 파일에 기록해주는 모듈이 바로 winston 입니다.

morgan

위에서 설명은 드렸지만 morgan 이 뭐하는 놈인지 아직 감이 잘 안잡히시는 분들 계실겁니다.

백날 글로 설명하는 것보다는 그림 하나가 더 이해가 빠를것이니 morgan 이 무엇인지 그림으로 설명 드리겠습니다.

해당 출력은 그저 서버에 GET 으로 /v1/users 를 호출한 결과값입니다.

맨 마지막 라인을 보시게되면 GET /v1/users 200 44.098 ms — 2 부분을 보실 수 있는데 이게 express 가 기본적으로 출력해주는 output 이 아니고 morgan 이 현재 호출된 라우트가 어떤 상태이고 어떤 결과값인지를 잘 정리해서 보여주는 것입니다.

자 그러면 morgan 이 어떻게 사용되는지 한번 알아볼까요?

src/app.js

현재 logger 라고 하는 이름으로 활동하시는 분이었군요.

자 그럼 이 logger 가 좀 더 자세한 정보들을 불러올 수 있게 수정을 해보도록 하겠습니다.

morgan 이 어떻게 사용되는지는 아래 링크를 통해서 참고해주세요.

실제로 logger 는 파일을 기록하는 녀석으로 오해할 수 있기 때문에 먼저 logger 라는 이름을 morgan 으로 변경하도록 하겠습니다.

import morgan from 'morgan'

그리고 좀 더 자세한 정보를 출력하기 위해 아래와 같이 수정해보도록 합시다.

app.use(morgan('combined'))

상당히 유용한 정보들을 뿜뿜해주고 있는데 morgan 은 아래와 같은 여러 종류의 preset 을 가지고 있습니다.

combined 
[:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"]
common
[:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]]
dev
[:method :url :status :response-time ms - :res[content-length]]
short
[:remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms]
tiny
[:method :url :status :res[content-length] - :response-time ms]

어떠한 것을 사용하셔도 상관은 없지만 보통 배포시에는 combined 혹은 common 에 필요한 정보들을 추가하여 사용하는 것을 추천드립니다.

자 그럼 요청과 응답에 대한 전반적인 정보가 console 을 통해 출력되는 것을 확인 하였으니 이 정보들을 파일로 작성해보도록 합시다.

winston

다른 언어도 똑같지만 npm 에도 수많은 로깅 라이브러리가 존재하지만 winston 이 가장 큰 커뮤니티를 구축하고 있습니다.

애초에 모든것을 제로베이스에서 구축하려고 하지 않는다면 남들이 만들어 놓은 여러가지 플러그인이나 모듈을 사용하셔야 하는데, 이럴때는 기능이 우수한 것보다는 커뮤니티가 활발한 것부터 사용해보시는게 좋습니다.

일단 사용자가 많으면 내가 하고자 하는 것들을 이미 시도했을 가능성이 매우 높고 그에 대한 해답이 이미 존재할 확률도 매우 높기 때문입니다.

자 그러면 위에서 설치한 winston 의 설정을 좀 잡아주도록 합시다.

src/configs/winston.js

그리고 현재 콘솔에만 출력되는 morgan 로그를 파일로 옮겨 보죠.

src/app.js

자 이제 작동 확인을 위해서 npm test 한번 돌려보면, src/logs/info.log 파일이 생성되고 안에는 다음과 같은 내용들이 기록됩니다.

이제 우리는 서버에서 모든 사용자의 방문 기록을 추적할 수 있게 되었습니다.

참고로 현재 ::ffff 부분은 로컬 테스트 환경이라 원격 주소를 추적할 수 없기 때문에 저렇게 찍히는 거구요 나중에 배포를 하면 사용자들의 실제 주소들이 찍히게 됩니다.

자 이제 그러면 로그 중에서도 가장 중요한 에러 로그를 좀 다뤄보겠습니다.

error logging

어떠한 서비스를 운영하는 중에는 여러가지 신경쓸게 많습니다. 하지만 그 중에서도 에러를 잘 관리하는 것보다 중요한 것은 없습니다.

에러를 잘 관리하기 위해서는 처음부터 에러가 없는 프로그램을 만드는 것이 가장 중요하고, 그 다음으로는 만약 에러가 발생 하였다면 에러의 인과관계를 정확히 파악하여 다시는 에러가 발생하지 않도록 빠른 조치를 취해주는 것입니다.

아쉽게도 node 모듈들은 에러를 파악하기가 참 쉽지 않습니다.

심지어 로깅 라이브러리도 다른 언어에 비교하면 그다지 강력하다고 생각되진 않습니다. (이게 여러모로 참 아쉬운 부분입니다)

그래도 이런 부족한 정보들이라도 잘만 활용한다면 충분히 쓸만하게끔 가공할 수 있습니다.

자 그럼 에러 핸들러를 잠깐 좀 봐보죠.

// error handlerapp.use((err, req, res, next) => {

let apiError = err
if (!err.status) {
apiError = createError(err)
}
// set locals, only providing error in development
res.locals.message = apiError.message
res.locals.error = process.env.NODE_ENV === 'development' ? apiError : {}
// render the error page
return
response(
res,
{
message: apiError.message
},
apiError.status
)
})

현재 NODE_ENVdevelopment 일 경우에만 에러 스택을 파악할 수 있도록 res.locals 에 여러 정보들을 넣어주고 있습니다.

즉, production 상태일 경우에는 해당 정보들을 로그 파일에 넣어주면 된다는 말이죠!

일단은 test 에서 작동할 수 있도록 test 상태일 때 로깅을 해보도록 하겠습니다.

그리고 간단하게 src/controllers/v1/auth.controller.jstokenTest 함수를 살짝쿵 변경해주도록 하겠습니다.

const tokenTest = async (req, res, next) => {
try {
return next(createError(500, '테스트 에러'))
return response(res, req.user)
} catch (e) {
next(e)
}
}

그리고 npm test 를 실행시켜 보면 src/logs/error.log 에 많은 내용들이 기록되어 있습니다.

이건 사실 사람이 도저히 읽을수가 없기 때문에 jq 와 같은 라이브러리의 힘을 빌려야합니다.

cli 환경에서 json 을 예쁘게 출력해주는 라이브러리들은 많이 있으니 입맛대로 설치해주시면 되고, jq 를 사용하실 분들은 하기 링크를 통해서 설치하시면 됩니다.

cat error.log | jq

쨘~ 충분히 읽을만하게 찍혔죠?

자 오늘은 서버에서 가장 중요한 로깅에 대해서 배워보았습니다. 사실 로깅에 대해서는 이렇다할 정답이 있는것이 아닙니다.

서비스마다 중요하게 생각해야할 부분이 있고 아닌 부분도 있기 때문에 어떻게 구현해야 한다 정도만 알려드리고 세부 조정은 실제로 여러분이 사용하시면서 이것저것 해보시는걸 추천드립니다.

몇번 하시면서 로그들을 살펴보다 보면 아 대충 이렇게 하면 되겠구나? 하는 부분을 알 수 있으실 겁니다.

오늘 강의는 좀 길어졌는데요, 다음 강의는 라우트에 붙일 수 있는 로그를 알아보고 route validation 에 대해서 알아보도록 하겠습니다.

이제 슬슬 강좌가 끝을 향해 달려가는 듯한 느낌이 드네요^^

자 여러분 오늘도 건강 챙기시고 좋은 하루 보내세요!

아하에서 취준생 여러분들을 위해 자소서 공유 이벤트를 진행합니다.

취업 시즌을 맞아 자소서 작성에 어려움을 겪는 분에게 많이 공유 부탁드립니다~

--

--