1 | path = require 'path'
|
2 | ep = require 'event-pipe'
|
3 | os = require 'options-stream'
|
4 | levels = require './levels'
|
5 | Log = require './log'
|
6 |
|
7 | {info, debug, warn, error} = levels
|
8 |
|
9 | cwd = process.cwd()
|
10 |
|
11 | defaultAccessLogFile = "
|
12 | [#{cwd}/logs/#{path.basename (path.basename process.argv[1] , '.js'), '.coffee'}-access-]YYYY-MM-DD[.log]
|
13 | "
|
14 |
|
15 | logs = []
|
16 | flushTime = 1000
|
17 | timer = null
|
18 |
|
19 | heartBeat = ->
|
20 | now = new Date().getTime()
|
21 | inst.heartBeat now for inst in logs
|
22 | timer = setTimeout ->
|
23 | heartBeat()
|
24 | , flushTime
|
25 |
|
26 | heartBeat()
|
27 |
|
28 |
|
29 | traceid = new Buffer 16
|
30 | [v1, v2, v3] = process.version.substring(1).split('.')
|
31 | if v1 * 100000 + v2 * 1000 + Number(v3) > 11013
|
32 | getTraceId = (req)->
|
33 |
|
34 |
|
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'
|
43 | else
|
44 | getTraceId = (req)->
|
45 |
|
46 |
|
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 |
|
56 | factory =
|
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 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
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 |
|
112 | options.file.level |= info
|
113 | options.stdio.level |= info
|
114 |
|
115 | log = Log options
|
116 | logs.push log
|
117 |
|
118 | mw = (req, resp, next) =>
|
119 |
|
120 | req.__justLogStartTime = new Date
|
121 |
|
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 |
|
144 | create = (options)->
|
145 | log = new Log options
|
146 | logs.push log
|
147 | log
|
148 |
|
149 | create[k.toUpperCase()] = v for k, v of levels.levels
|
150 |
|
151 | module.exports = create
|
152 |
|
153 | module.exports[k] = v for k, v of factory
|