Add unique request IDs to streaming API to improve logs
parent
0af3401553
commit
4d2be9f432
|
@ -66,6 +66,7 @@
|
||||||
"sinon": "^1.17.6",
|
"sinon": "^1.17.6",
|
||||||
"style-loader": "^0.13.1",
|
"style-loader": "^0.13.1",
|
||||||
"utf-8-validate": "^3.0.0",
|
"utf-8-validate": "^3.0.0",
|
||||||
|
"uuid": "^3.0.1",
|
||||||
"webpack": "^1.14.0",
|
"webpack": "^1.14.0",
|
||||||
"websocket.js": "^0.1.7",
|
"websocket.js": "^0.1.7",
|
||||||
"ws": "^2.0.2"
|
"ws": "^2.0.2"
|
||||||
|
|
|
@ -6,6 +6,7 @@ import pg from 'pg'
|
||||||
import log from 'npmlog'
|
import log from 'npmlog'
|
||||||
import url from 'url'
|
import url from 'url'
|
||||||
import WebSocket from 'ws'
|
import WebSocket from 'ws'
|
||||||
|
import uuid from 'uuid'
|
||||||
|
|
||||||
const env = process.env.NODE_ENV || 'development'
|
const env = process.env.NODE_ENV || 'development'
|
||||||
|
|
||||||
|
@ -43,6 +44,13 @@ const allowCrossDomain = (req, res, next) => {
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setRequestId = (req, res, next) => {
|
||||||
|
req.requestId = uuid.v4()
|
||||||
|
res.header('X-Request-Id', req.requestId)
|
||||||
|
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
const accountFromToken = (token, req, next) => {
|
const accountFromToken = (token, req, next) => {
|
||||||
pgPool.connect((err, client, done) => {
|
pgPool.connect((err, client, done) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -90,7 +98,7 @@ const authenticationMiddleware = (req, res, next) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorMiddleware = (err, req, res, next) => {
|
const errorMiddleware = (err, req, res, next) => {
|
||||||
log.error(err)
|
log.error(req.requestId, err)
|
||||||
res.writeHead(err.statusCode || 500, { 'Content-Type': 'application/json' })
|
res.writeHead(err.statusCode || 500, { 'Content-Type': 'application/json' })
|
||||||
res.end(JSON.stringify({ error: err.statusCode ? `${err}` : 'An unexpected error occurred' }))
|
res.end(JSON.stringify({ error: err.statusCode ? `${err}` : 'An unexpected error occurred' }))
|
||||||
}
|
}
|
||||||
|
@ -98,7 +106,7 @@ const errorMiddleware = (err, req, res, next) => {
|
||||||
const placeholders = (arr, shift = 0) => arr.map((_, i) => `$${i + 1 + shift}`).join(', ');
|
const placeholders = (arr, shift = 0) => arr.map((_, i) => `$${i + 1 + shift}`).join(', ');
|
||||||
|
|
||||||
const streamFrom = (redisClient, id, req, output, needsFiltering = false) => {
|
const streamFrom = (redisClient, id, req, output, needsFiltering = false) => {
|
||||||
log.verbose(`Starting stream from ${id} for ${req.accountId}`)
|
log.verbose(req.requestId, `Starting stream from ${id} for ${req.accountId}`)
|
||||||
|
|
||||||
redisClient.on('message', (channel, message) => {
|
redisClient.on('message', (channel, message) => {
|
||||||
const { event, payload, queued_at } = JSON.parse(message)
|
const { event, payload, queued_at } = JSON.parse(message)
|
||||||
|
@ -107,7 +115,7 @@ const streamFrom = (redisClient, id, req, output, needsFiltering = false) => {
|
||||||
const now = new Date().getTime()
|
const now = new Date().getTime()
|
||||||
const delta = now - queued_at;
|
const delta = now - queued_at;
|
||||||
|
|
||||||
log.silly(`Transmitting for ${req.accountId}: ${event} ${payload} Delay: ${delta}ms`)
|
log.silly(req.requestId, `Transmitting for ${req.accountId}: ${event} ${payload} Delay: ${delta}ms`)
|
||||||
output(event, payload)
|
output(event, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +162,7 @@ const streamToHttp = (req, res, redisClient) => {
|
||||||
const heartbeat = setInterval(() => res.write(':thump\n'), 15000)
|
const heartbeat = setInterval(() => res.write(':thump\n'), 15000)
|
||||||
|
|
||||||
req.on('close', () => {
|
req.on('close', () => {
|
||||||
log.verbose(`Ending stream for ${req.accountId}`)
|
log.verbose(req.requestId, `Ending stream for ${req.accountId}`)
|
||||||
clearInterval(heartbeat)
|
clearInterval(heartbeat)
|
||||||
redisClient.quit()
|
redisClient.quit()
|
||||||
})
|
})
|
||||||
|
@ -168,11 +176,16 @@ const streamToHttp = (req, res, redisClient) => {
|
||||||
// Setup stream output to WebSockets
|
// Setup stream output to WebSockets
|
||||||
const streamToWs = (req, ws, redisClient) => {
|
const streamToWs = (req, ws, redisClient) => {
|
||||||
ws.on('close', () => {
|
ws.on('close', () => {
|
||||||
log.verbose(`Ending stream for ${req.accountId}`)
|
log.verbose(req.requestId, `Ending stream for ${req.accountId}`)
|
||||||
redisClient.quit()
|
redisClient.quit()
|
||||||
})
|
})
|
||||||
|
|
||||||
return (event, payload) => {
|
return (event, payload) => {
|
||||||
|
if (ws.readyState !== ws.OPEN) {
|
||||||
|
log.error(req.requestId, 'Tried writing to closed socket')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ws.send(JSON.stringify({ event, payload }))
|
ws.send(JSON.stringify({ event, payload }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,6 +197,7 @@ const getRedisClient = () => redis.createClient({
|
||||||
password: process.env.REDIS_PASSWORD
|
password: process.env.REDIS_PASSWORD
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.use(setRequestId)
|
||||||
app.use(allowCrossDomain)
|
app.use(allowCrossDomain)
|
||||||
app.use(authenticationMiddleware)
|
app.use(authenticationMiddleware)
|
||||||
app.use(errorMiddleware)
|
app.use(errorMiddleware)
|
||||||
|
@ -206,11 +220,11 @@ app.get('/api/v1/streaming/hashtag', (req, res) => {
|
||||||
wss.on('connection', ws => {
|
wss.on('connection', ws => {
|
||||||
const location = url.parse(ws.upgradeReq.url, true)
|
const location = url.parse(ws.upgradeReq.url, true)
|
||||||
const token = location.query.access_token
|
const token = location.query.access_token
|
||||||
const req = {}
|
const req = { requestId: uuid.v4() }
|
||||||
|
|
||||||
accountFromToken(token, req, err => {
|
accountFromToken(token, req, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.error(err)
|
log.error(req.requestId, err)
|
||||||
ws.close()
|
ws.close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -5644,6 +5644,10 @@ uuid@^2.0.1, uuid@^2.0.2:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
|
||||||
|
|
||||||
|
uuid@^3.0.1:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
|
||||||
|
|
||||||
v8flags@^2.0.10:
|
v8flags@^2.0.10:
|
||||||
version "2.0.11"
|
version "2.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881"
|
resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881"
|
||||||
|
|
Loading…
Reference in New Issue