├── .gitignore ├── examples ├── simple.js ├── cb.js └── fancy.js ├── test ├── simple.js ├── format.js └── advanced.js ├── package.json ├── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/simple.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var accesslog = require('../'); 3 | 4 | http.createServer(function(req, res) { 5 | accesslog(req, res); 6 | res.end(); 7 | }).listen(8000, 'localhost', function() { 8 | console.log('Listening on localhost:8000'); 9 | }); 10 | -------------------------------------------------------------------------------- /examples/cb.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var accesslog = require('../'); 3 | 4 | http.createServer(function(req, res) { 5 | accesslog(req, res, function(s) { 6 | console.log('> ' + s + ' <'); 7 | }); 8 | res.end(); 9 | }).listen(8000, 'localhost', function() { 10 | console.log('Listening on localhost:8000'); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/fancy.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var accesslog = require('../'); 3 | 4 | var format = 'url=":url" method=":method" statusCode=":statusCode" delta=":delta" ip=":ip"'; 5 | 6 | http.createServer(function(req, res) { 7 | accesslog(req, res, format, function(s) { 8 | console.log(s); 9 | }); 10 | res.end(); 11 | }).listen(8000, 'localhost', function() { 12 | console.log('Listening on localhost:8000'); 13 | }); 14 | -------------------------------------------------------------------------------- /test/simple.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | 3 | var accesslog = require('../'); 4 | 5 | var host = '127.0.0.1'; 6 | var port = 9127; 7 | 8 | http.createServer(onrequest).listen(port, host, started); 9 | 10 | function onrequest(req, res) { 11 | accesslog(req, res); 12 | res.end(); 13 | } 14 | 15 | function started() { 16 | console.log('server started'); 17 | 18 | var req = http.request('http://localhost:9127/testing', function() { 19 | process.exit(0); 20 | }); 21 | req.end(); 22 | } 23 | -------------------------------------------------------------------------------- /test/format.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | 3 | var accesslog = require('../'); 4 | 5 | var host = '127.0.0.1'; 6 | var port = 9127; 7 | 8 | var format = ':ip :method :statusCode :url (:deltams)'; 9 | 10 | http.createServer(onrequest).listen(port, host, started); 11 | 12 | function onrequest(req, res) { 13 | accesslog(req, res, format); 14 | res.end(); 15 | } 16 | 17 | function started() { 18 | console.log('server started'); 19 | 20 | var req = http.request('http://localhost:9127/testing', function() { 21 | process.exit(0); 22 | }); 23 | req.end(); 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "access-log", 3 | "description": "Add simple access logs to any http or https server", 4 | "version": "0.2.2", 5 | "author": "Dave Eddy (http://www.daveeddy.com)", 6 | "contributors": [], 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/bahamas10/node-access-log.git" 10 | }, 11 | "scripts": { 12 | "test": "for f in test/*; do echo \"$f\"; node \"$f\" || exit 1; done; echo Passed; exit 0" 13 | }, 14 | "main": "./index.js", 15 | "dependencies": { 16 | "strftime": "~0.6.2" 17 | }, 18 | "bin": {}, 19 | "devDependencies": {}, 20 | "optionalDependencies": {}, 21 | "engines": { 22 | "node": "*" 23 | }, 24 | "keywords": [ 25 | "access", 26 | "apache", 27 | "clf", 28 | "logs" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /test/advanced.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | 3 | var accesslog = require('../'); 4 | 5 | var host = '127.0.0.1'; 6 | var port = 9127; 7 | 8 | var format = [ 9 | 'clfDate: :clfDate', 10 | 'contentLength: :contentLength', 11 | 'delta: :delta', 12 | 'endDate: :endDate', 13 | 'endTime: :endTime', 14 | 'httpVersion: :httpVersion', 15 | 'ip: :ip', 16 | 'method: :method', 17 | 'protocol: :protocol', 18 | 'referer: :referer', 19 | 'startDate: :startDate', 20 | 'startTime: :startTime', 21 | 'statusCode: :statusCode', 22 | 'url: :url', 23 | 'urlDecoded: :urlDecoded', 24 | 'userID: :userID', 25 | 'userAgent: :userAgent', 26 | ].join('\n'); 27 | 28 | http.createServer(onrequest).listen(port, host, started); 29 | 30 | function onrequest(req, res) { 31 | accesslog(req, res, format); 32 | res.end(); 33 | } 34 | 35 | function started() { 36 | console.log('server started'); 37 | 38 | var req = http.request('http://localhost:9127/testing', function() { 39 | process.exit(0); 40 | }); 41 | req.end(); 42 | } 43 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var strftime = require('strftime'); 2 | 3 | var defaultformat = ':ip - :userID [:clfDate] ":method :url HTTP/:httpVersion" :statusCode :contentLength ":referer" ":userAgent"'; 4 | 5 | module.exports = accesslog; 6 | 7 | function accesslog(req, res, format, cb) { 8 | if (typeof format === 'function') { 9 | cb = format; 10 | format = null; 11 | } 12 | 13 | format = format || defaultformat; 14 | cb = cb || console.log.bind(console); 15 | 16 | var uriDecoded = req.url; 17 | try { 18 | uriDecoded = decodeURIComponent(uriDecoded); 19 | } catch (e) {} 20 | 21 | var start = new Date(); 22 | 23 | // override res.writeHead to track contentLength 24 | var resWriteHead = res.writeHead.bind(res); 25 | res.writeHead = function(statusCode, reason, headers) { 26 | resWriteHead.apply(res, arguments); 27 | 28 | if (typeof reason === "object" && !headers) { 29 | headers = reason; 30 | reason = null; 31 | } 32 | 33 | if (headers) { 34 | for (var k in headers) { 35 | if (k.toLowerCase() == "content-length") { 36 | res.contentLength = headers[k]; 37 | } 38 | } 39 | } 40 | }; 41 | 42 | // override res.end to capture all responses 43 | var resend = res.end.bind(res); 44 | res.end = function() { 45 | // call the original 46 | resend.apply(res, arguments); 47 | 48 | var end = new Date(); 49 | var delta = end - start; 50 | var s = format 51 | .replace(':clfDate', strftime('%d/%b/%Y:%H:%M:%S %z', end)) 52 | .replace(':contentLength', res.getHeader('content-length') || res.contentLength || '-') 53 | .replace(':delta', delta) 54 | .replace(':endDate', end.toISOString()) 55 | .replace(':endTime', end.getTime()) 56 | .replace(':httpVersion', req.httpVersion) 57 | .replace(':ip', req.headers['x-forwarded-for'] || req.connection.remoteAddress || '-') 58 | .replace(':method', req.method) 59 | .replace(':protocol', req.connection.encrypted ? 'HTTPS' : 'HTTP') 60 | .replace(':referer', req.headers['referer'] || '-') 61 | .replace(':startDate', start.toISOString()) 62 | .replace(':startTime', start.getTime()) 63 | .replace(':statusCode', res.statusCode) 64 | .replace(':url', req.url) 65 | .replace(':urlDecoded', uriDecoded) 66 | .replace(':userID', (req.session && (req.session.user || req.session.id)) || '-') 67 | .replace(':userAgent', req.headers['user-agent'] || '-'); 68 | 69 | // log it 70 | cb(s); 71 | }; 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | access-log 2 | ========== 3 | 4 | Add simple access logs to any http or https server 5 | 6 | Usage 7 | ----- 8 | 9 | ``` js 10 | var http = require('http'); 11 | var accesslog = require('access-log'); 12 | 13 | http.createServer(function(req, res) { 14 | accesslog(req, res); 15 | res.end(); 16 | }).listen(80, '0.0.0.0'); 17 | ``` 18 | 19 | This will automatically log requests as they come in to the 20 | web server that look like... 21 | 22 | ``` 23 | 127.0.0.1 - - [13/Sep/2013:01:38:09 -0400] "GET / HTTP/1.1" 200 - "-" "-" 24 | 127.0.0.1 - - [13/Sep/2013:01:38:09 -0400] "GET /testing HTTP/1.1" 200 - "-" "-" 25 | 127.0.0.1 - - [13/Sep/2013:01:38:10 -0400] "GET /index.html HTTP/1.1" 200 - "-" "-" 26 | ``` 27 | 28 | Customization 29 | ------------- 30 | 31 | ### accesslog(req, res, [format], [function]) 32 | 33 | #### format 34 | 35 | You can pass in a format string, the default is Apache Common Log Format 36 | http://en.wikipedia.org/wiki/Common_Log_Format 37 | 38 | ``` 39 | :ip :userAgent :userID [:clfDate] ":method :url HTTP/:httpVersion" :statusCode :contentLength 40 | ``` 41 | 42 | - `clfDate`: The date of the end of the response in Apache Common Log format 43 | - `contentLength`: The response `Content-Length` header, or `-` if unset 44 | - `delta`: The time in ms from request to response 45 | - `endDate`: The ISO formatted string when the response was ended 46 | - `endTime`: The epoch time when the response was ended 47 | - `httpVersion`: The HTTP version used (ie. `1.0`, `1.1`) 48 | - `ip`: The remote IP, using `X-Forwarded-For` if set 49 | - `method`: The HTTP method 50 | - `protocol`: `HTTP` or `HTTPS` 51 | - `referer`: The request `Referer` header, or `-` if unset 52 | - `startDate`: The ISO formatted string when the request was received 53 | - `startTime`: The epoch time when the request was received 54 | - `statusCode`: The response status code sent from the server 55 | - `url`: The requested URL 56 | - `urlDecoded`: The decoded request URL (ie. `%20` => ` `) 57 | - `userID`: The username if applicable 58 | - `userAgent`: The request `User-Agent` header, or `-` if unset 59 | 60 | #### function 61 | 62 | You can also pass in your own custom callback, the default is console.log. 63 | The only argument passed is the access log string 64 | 65 | Example 66 | ------- 67 | 68 | ``` js 69 | var format = 'url=":url" method=":method" statusCode=":statusCode" delta=":delta" ip=":ip"'; 70 | 71 | accesslog(req, res, format, function(s) { 72 | console.log(s); 73 | }); 74 | ``` 75 | 76 | yields 77 | 78 | ``` 79 | url="/projects" method="GET" statusCode="200" delta="0" ip="127.0.0.1" 80 | url="/testing" method="GET" statusCode="200" delta="1" ip="127.0.0.1" 81 | url="/index.html" method="GET" statusCode="200" delta="0" ip="127.0.0.1" 82 | ``` 83 | 84 | Installation 85 | ------------ 86 | 87 | npm install access-log 88 | 89 | Extend 90 | ------ 91 | 92 | Consider further customizing the access logs by using the [log-timestamp] 93 | (https://github.com/bahamas10/node-log-timestamp) module to prepend a timestamp 94 | automatically. 95 | 96 | License 97 | ------- 98 | 99 | MIT Licensed 100 | --------------------------------------------------------------------------------