1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 | 1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
1x
| moment = require 'moment'
logger = require 'winston'
events = require '../model/events'
messageStore = require '../middleware/messageStore'
config = require '../config/config'
config.events = config.get('events')
if !config.events
# maybe we're using outdated config
config.events = config.get('visualizer')
config.events.normalizationBuffer = config.events.orchestrationTsBufferMillis
enableTSNormalization = config.events.enableTSNormalization ? false
if enableTSNormalization is true
normalizationBuffer = 100
else
normalizationBuffer = 0
timestampAsMillis = (ts) -> moment(new Date(ts)).valueOf()
# Determine the difference between baseTS and the earliest timestamp
# present in a collection of routes (buffered for normalization)
calculateEarliestRouteDiff = (baseTS, routes) ->
earliestTS = 0
for route in routes
ts = timestampAsMillis route.request.timestamp
if earliestTS < ts then earliestTS = ts
tsDiff = baseTS - earliestTS
tsDiff += normalizationBuffer
return tsDiff
determineStatusType = (statusCode) ->
status = 'success'
if 500 <= statusCode <= 599
status = 'error'
return status
exports.saveEvents = saveEvents = (trxEvents, callback) ->
now = new Date
event.created = now for event in trxEvents
# bypass mongoose for quick batch inserts
# index needs to be ensured manually since the collection might not already exist
events.Event.collection.ensureIndex { created: 1 }, { expireAfterSeconds: 3600 }, ->
events.Event.collection.insert trxEvents, (err) -> return if err then callback err else callback()
createRouteEvents = (dst, transactionId, channel, route, type, tsAdjustment, autoRetryAttempt) ->
if route?.request?.timestamp? and route?.response?.timestamp?
startTS = timestampAsMillis route.request.timestamp
endTS = timestampAsMillis route.response.timestamp
if enableTSNormalization is true
startTS = startTS + tsAdjustment
endTS = endTS + tsAdjustment
if startTS > endTS then startTS = endTS
dst.push
channelID: channel._id
transactionID: transactionId
normalizedTimestamp: startTS
type: type
event: 'start'
name: route.name
mediator: route.mediatorURN
autoRetryAttempt: autoRetryAttempt
dst.push
channelID: channel._id
transactionID: transactionId
normalizedTimestamp: endTS
type: type
event: 'end'
name: route.name
mediator: route.mediatorURN
status: route.response.status
statusType: determineStatusType route.response.status
autoRetryAttempt: autoRetryAttempt
createChannelStartEvent = (dst, transactionId, requestTimestamp, channel, autoRetryAttempt) ->
dst.push
channelID: channel._id
transactionID: transactionId
normalizedTimestamp: timestampAsMillis requestTimestamp
type: 'channel'
event: 'start'
name: channel.name
autoRetryAttempt: autoRetryAttempt
createChannelEndEvent = (dst, transactionId, requestTimestamp, channel, response, autoRetryAttempt) ->
startTS = timestampAsMillis requestTimestamp
endTS = timestampAsMillis response.timestamp
if endTS < startTS then endTS = startTS
dst.push
channelID: channel._id
transactionID: transactionId
normalizedTimestamp: endTS + normalizationBuffer
type: 'channel'
event: 'end'
name: channel.name
status: response.status
statusType: determineStatusType response.status
autoRetryAttempt: autoRetryAttempt
createPrimaryRouteEvents = (dst, transactionId, requestTimestamp, channel, routeName, mediatorURN, response, autoRetryAttempt) ->
startTS = timestampAsMillis requestTimestamp
dst.push
channelID: channel._id
transactionID: transactionId
normalizedTimestamp: startTS
type: 'primary'
event: 'start'
name: routeName
mediator: mediatorURN
autoRetryAttempt: autoRetryAttempt
endTS = timestampAsMillis response.timestamp
if endTS < startTS then endTS = startTS
dst.push
channelID: channel._id
transactionID: transactionId
normalizedTimestamp: endTS + normalizationBuffer
type: 'primary'
event: 'end'
name: routeName
status: response.status
statusType: determineStatusType response.status
mediator: mediatorURN
autoRetryAttempt: autoRetryAttempt
createOrchestrationEvents = (dst, transactionId, requestTimestamp, channel, orchestrations) ->
if requestTimestamp
startTS = timestampAsMillis requestTimestamp
tsDiff = calculateEarliestRouteDiff startTS, orchestrations
createRouteEvents dst, transactionId, channel, orch, 'orchestration', tsDiff for orch in orchestrations
exports.createSecondaryRouteEvents = createSecondaryRouteEvents = (dst, transactionId, requestTimestamp, channel, routes) ->
startTS = timestampAsMillis requestTimestamp
tsDiff = calculateEarliestRouteDiff startTS, routes
for route in routes
createRouteEvents dst, transactionId, channel, route, 'route', tsDiff
if route.orchestrations
# find TS difference
tsDiff = calculateEarliestRouteDiff startTS, route.orchestrations
createRouteEvents dst, transactionId, channel, orch, 'orchestration', tsDiff for orch in route.orchestrations
exports.createTransactionEvents = (dst, transaction, channel) ->
getPrimaryRouteName = () ->
for r in channel.routes
if r.primary then return r.name
return null
timestamp = if transaction.request?.timestamp then transaction.request.timestamp else new Date()
if transaction.request and transaction.response
createPrimaryRouteEvents dst, transaction._id, timestamp, channel, getPrimaryRouteName(), null, transaction.response
if transaction.orchestrations
createOrchestrationEvents dst, transaction._id, timestamp, channel, transaction.orchestrations
if transaction.routes
createSecondaryRouteEvents dst, transaction._id, timestamp, channel, transaction.routes
exports.koaMiddleware = (next) ->
ctx = this
runAsync = (method) ->
do (ctx) ->
f = -> method ctx, (err) -> logger.err err if err
setTimeout f, 0
runAsync (ctx, done) ->
logger.debug "Storing channel start event for transaction: #{ctx.transactionId}"
trxEvents = []
createChannelStartEvent trxEvents, ctx.transactionId, ctx.requestTimestamp, ctx.authorisedChannel, ctx.currentAttempt
saveEvents trxEvents, done
yield next
runAsync (ctx, done) ->
logger.debug "Storing channel end and primary routes events for transaction: #{ctx.transactionId}"
trxEvents = []
mediatorURN = ctx.mediatorResponse?['x-mediator-urn']
orchestrations = ctx.mediatorResponse?.orchestrations
createPrimaryRouteEvents trxEvents, ctx.transactionId, ctx.requestTimestamp, ctx.authorisedChannel, ctx.primaryRoute.name, mediatorURN, ctx.response, ctx.currentAttempt
if orchestrations
createOrchestrationEvents trxEvents, ctx.transactionId, ctx.requestTimestamp, ctx.authorisedChannel, orchestrations, ctx.currentAttempt
createChannelEndEvent trxEvents, ctx.transactionId, ctx.requestTimestamp, ctx.authorisedChannel, ctx.response, ctx.currentAttempt
saveEvents trxEvents, done
|