최근 개인적으로 Node.js스터디를 진행하고 있습니다. 책을 한권 구해 차근차근 따라가던 중 express의 logger 미들웨어가 동작하지 않더군요. 우선 기본 개념은 인터넷 참조없이 책만으로 해결하려고 마음먹었는데 당황했습니다. 바로 아래와 같은 에러 메세지가 등장합니다.
간단히 해석하면 "대부분의 미들웨어(로거와 같은)는 더 이상 익스프레스에 기본으로 제공되지 않으니 반드시 개별로 설치해라. 그리고 url을 봐라"라는군요. (express 4.x버전부터 삭제되었습니다.) logger뿐만 아니라 많은 미들웨어가 제거 되었나봅니다. 앞으로 몇번의 난관이 더 있을거라는 이야기군요.
우선은 express.logger()를 대체할 API를 찾다보니 morgan이라는 모듈이 검색이 됩니다. morgan의 사용법을 알아봅시다.
morgan module을 설치합니다.
아래 나오는 api는 https://github.com/expressjs/morgan을 참조하였습니다. 거의 없다시피한 영어 실력으로 번역하였으므로, 오역이 상당히 많을것으로 예상됩니다.
API
var morgan = require('morgan');
morgan(format, options)
morgan 로거 미들웨어 함수는 주어진 format, options을 이용하여 생성합니다. format은 미리 정의된 이름의 문자열(아래 참조), 형식 문자열, 또는 로그 항목을 생성하는 함수가 될 수 있습니다.
Options
morgan은 다음과같은 속성을 옵션으로 받아들입니다.
immediate
response대신 request에 따라 로그를 작성합니다. 서버 크래시가 발생하여도 request들은 기록되지만, reponse(response code, 컨텐츠 길이 등등)의 데이터는 기록할 수 없기 때문입니다.
skip
로깅의 스킵여부를 결정하기 위한 함수입니다. 기본값은 false. 이 함수는 "skip(req, res)" 형식으로 호출됩니다.
// 예 : 에러 response만 기록합니다. morgan('combined', { skip : function(req, res) { return res.statusCode < 400 } });
실습 해봅시다! 간단히 예제코드 작성해봤습니다.
var http = require('http'); var express = require('express'); var morgan = require('morgan'); var app = express(); var router = express.Router(); // 이곳으로 접근하면 로그를 출력 router.get('/logging', function(req, res) { console.log('access logging'); res.writeHead(404, { 'Content-Type' : 'text/html' }); res.end('error!!'); }); // 이곳으로 접근하면 로그 출력하지 않음 router.get('/skip', function(req, res) { console.log('access skip'); res.writeHead(200, { 'Content-Type' : 'text/html' }); res.end('success!!'); }); // Create new Morgan var myMorgan = morgan('combined', { skip : function(req, res) { return res.statusCode < 400 } }); app.use(myMorgan); app.use('/', router); // 서버 생성 및 리슨 http.createServer(app).listen(10000, function() { console.log('Server Start!!'); });
위의 코드를 작성하고 서버를 띄운 후 http://localhost:10000/logging 과 http://localhost:10000/skip에 접근하여봅시다.
access skip
access logging
::1 - - [07/Apr/2015:05:23:26 +0000] "GET /logging HTTP/1.1" 404 - "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.104 Safari/537.36"
stream
로그 작성을 위한 Output stream옵션입니다. 기본값은 process.stdout입니다.
정의된 포맷들
다양한 정의돈 포맷들이 제공됩니다:
combined
표준 Apache combined 로그 출력
:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
common
표준 Apache common 로그 출력.
:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]
dev
개발용을 위해 response에 따라 색상이 입혀진 축약된 로그를 출력합니다. :status값이 빨간색이면 서버 에러코드, 노란색이면 클라이언트 에러 코드, 청록색은 리다이렉션 코드, 그외 코드는 컬러가 입없습니다.
: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
Tokens
새 토큰 생성
토큰을 정의하기 위해서는 단순히 morgan.toke()함수를 이름, 콜백함수와 함께 호출하면 됩니다. 이 콜백함수는 string값을 리턴할것이라고 예상합니다. 아래의 콜백함수에서 리턴하는 값은 ":type"으로 사용할 수 있습니다:
morgan.token('type', function(req, res){ return req.headers['content-type']; })
morgan.toke()함수를 호출할 때 같은 이름을 사용하면 기존 token정의는 덮어쓰여지게 됩니다.
:date[format]
현재의 UTC날짜/시간. 사용 가능한 포맷:
clf
일반적인 로그 포맷 ("10/Oct/2000:13:55:36 +0000"
)iso
공통 ISO 8601 날짜/시간 포맷 (2000-10-10T13:55:36.000Z
)web
공통 RFC 1123 날짜/시간 포맷 (Tue, 10 Oct 2000 13:55:36 GMT
)
포맷을 설정하지 않을경우 기본값은 web
입니다.
:http-version
request의 HTTP버전.
:method
request의 메소드(get,post.....).
:referrer
request의 Referer header.
:remote-addr
request의 remote address. 이 값은 req.ip
를 사용한다, 그렇지 않으면 표준req.connection.remoteAddress
값을 사용 (socket address).
:remote-user
인증된 사용자.
:req[header]
The given header
정보.
:res[header]
The given header
of the response.
:response-time
request가 morgan으로 들어오고 response header가 쓰여지기 까지의 시간(millis).
:status
reponse status code.
:url
request의 URL. req.originalUrl
이 존재하면 상용하고, 아닐경우 req.url
을 사용한다.
:user-agent
User-Agent header의 내용.
Examples
express/connect
모든 요청에 대해서 Aapache combinded 포맷의 로그를 출력하는 간단한 앱 예제
var express = require('express') var morgan = require('morgan') var app = express() app.use(morgan('combined')) app.get('/', function (req, res) { res.send('hello, world!') })
아래는 express모듈을 사용하지 않은 앱의 예제
var finalhandler = require('finalhandler') var http = require('http') var morgan = require('morgan') // create "middleware" var logger = morgan('combined') http.createServer(function (req, res) { var done = finalhandler(req, res) logger(req, res, function (err) { if (err) return done(err) // respond to request res.setHeader('content-type', 'text/plain') res.end('hello, world!') })})
사용자 정의 토큰을 사용하기
모든 요청에 ID값을 붙여넣은 후 :id토큰을 이용하여 로그를 출력하는 예제
var express = require('express') var morgan = require('morgan') var uuid = require('node-uuid') morgan.token('id', function getId(req) { return req.id }) var app = express() app.use(assignId) app.use(morgan(':id :method :url :response-time')) app.get('/', function (req, res) { res.send('hello, world!') }) function assignId(req, res, next) { req.id = uuid.v4() next() }