UNPKG

4.71 kBtext/coffeescriptView Raw
1path = require 'path'
2ep = require 'event-pipe'
3os = require 'options-stream'
4levels = require './levels'
5Log = require './log'
6
7{info, debug, warn, error} = levels
8
9cwd = process.cwd()
10
11defaultAccessLogFile = "
12[#{cwd}/logs/#{path.basename (path.basename process.argv[1] , '.js'), '.coffee'}-access-]YYYY-MM-DD[.log]
13"
14
15logs = []
16flushTime = 1000
17timer = null
18
19heartBeat = ->
20 now = new Date().getTime()
21 inst.heartBeat now for inst in logs
22 timer = setTimeout ->
23 heartBeat()
24 , flushTime
25
26heartBeat()
27
28
29traceid = new Buffer 16
30[v1, v2, v3] = process.version.substring(1).split('.')
31if v1 * 100000 + v2 * 1000 + Number(v3) > 11013
32 getTraceId = (req)->
33 # + ======== + ==== + ==== +
34 # + random bytes + ip^(masek|pid) + request time +
35 traceid.writeUInt32BE Math.random() * 4294967296
36 traceid.writeUInt32BE Math.random() * 4294967296, 4
37 [f1,f2,f3,f4] = req.socket.remoteAddress.split '.'
38 ip = Number(f1) << 24 | (Number(f2) << 16) | (Number(f3) << 8) | Number(f4)
39 ip ^= (Number(req.socket.remotePort) << 16) | process.pid
40 traceid.writeUInt32BE ip, 8
41 traceid.writeUInt32BE req.__justLogStartTime/1000, 12
42 traceid.toString 'base64'
43else
44 getTraceId = (req)->
45 # + ======== + ==== + ==== +
46 # + random bytes + ip^(masek|pid) + request time +
47 traceid.writeUInt32BE Math.random() * 4294967296, 0
48 traceid.writeUInt32BE Math.random() * 4294967296, 4
49 [f1,f2,f3,f4] = req.socket.remoteAddress.split '.'
50 ip = Number(f1) << 24 | (Number(f2) << 16) | (Number(f3) << 8) | Number(f4)
51 ip ^= (Number(req.socket.remotePort) << 16) | process.pid
52 traceid.writeUInt32BE ip, 8
53 traceid.writeUInt32BE parseInt(req.__justLogStartTime/1000), 12
54 traceid.toString 'base64'
55
56factory =
57 config : (opt)->
58 flushTime = opt.flushTime if opt.flushTime
59 clearTimeout timer if timer
60 heartBeat()
61
62 create : (options)->
63 log = Log options
64 logs.push log
65 log
66
67 end : (cb = ->)->
68 fns = []
69 fn = (inst)->
70 ->
71 inst.close @
72 for inst in logs
73 fns.push fn inst
74
75 logs.length = 0
76 pipe = ep()
77 pipe.on 'error', cb
78 pipe.lazy fns if fns.length
79 pipe.lazy ->
80 cb()
81 pipe.run()
82
83 ###
84 /**
85 * connect middleware
86 * @param {Object} options
87 * - {String} [encodeing='utf-8'], log text encoding
88 * - file :
89 * - {Number} [level=error|warn], file log levels
90 * - {String} [pattern='accesslog-rt'], log line pattern
91 * - {String} [mode='0664'], log file mode
92 * - {String} [dir_mode='2775'], log dir mode
93 * - {String} [path="[$CWD/logs/$MAIN_FILE_BASENAME-access-]YYYY-MM-DD[.log]"], log file path pattern
94 * - stdio:
95 * - {Number} [level=all], file log levels
96 * - {String} [pattern='accesslog-rt'], log line pattern
97 * - {WritableStream} [stdout=process.stdout], info & debug output stream
98 * - {WritableStream} [stderr=process.stderr], warn & error output stream
99 * @param {Function} cb(justlog)
100 * @return {Middlewtr}
101 ###
102 middleware : (options) ->
103 options = os
104 file:
105 path : defaultAccessLogFile
106 pattern : 'accesslog-rt'
107 stdio:
108 pattern : 'accesslog-color'
109 traceid : false
110 , options
111 # make sure level info need log
112 options.file.level |= info
113 options.stdio.level |= info
114 # new log object
115 log = Log options
116 logs.push log
117 # middleware
118 mw = (req, resp, next) =>
119 # response timer
120 req.__justLogStartTime = new Date
121 # hack resp.end
122 end = resp.end
123 resp.__justLogTraceId = req.__justLogTraceId = getTraceId(req) if options.traceid
124
125 resp.end = (chunk, encoding) ->
126 resp.end = end
127 resp.end chunk, encoding
128 log.info {
129 'remote-address' : req.socket.remoteAddress
130 'remote-port' : req.socket.remotePort
131 method : req.method
132 url : req.originalUrl || req.url
133 version : req.httpVersionMajor + '.' + req.httpVersionMinor
134 status : resp.statusCode
135 'content-length' : parseInt resp.getHeader('content-length'), 10
136 headers : req.headers
137 rt : new Date() - req.__justLogStartTime
138 traceid : req.__justLogTraceId
139 }
140 next()
141 mw.justlog = log
142 mw
143
144create = (options)->
145 log = new Log options
146 logs.push log
147 log
148# set levels const
149create[k.toUpperCase()] = v for k, v of levels.levels
150# exports
151module.exports = create
152
153module.exports[k] = v for k, v of factory