openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
206 lines (161 loc) • 7.14 kB
text/coffeescript
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