All files / src/middleware events.coffee

25% Statements 20/80
5% Branches 1/20
0% Functions 0/21
25.32% Lines 20/79
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 2061x 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