logarithm
Version:
The Middleware For Web-Server To Record Hits In ElasticSearch.
128 lines (118 loc) • 3.08 kB
JavaScript
import { aqt } from 'rqt'
import { req } from './lib'
/**
* @param {_goa.Context} ctx
* @param {_logarithm.Config} options Options for the program.
*/
const process = (ctx, options) => {
const {
app, index = app, pipeline = 'info', url, timeout = 5000,
strategy = monthly,
} = options
const {
request: { ip, path },
headers: {
// closure compiler bug
// cookie, // eslint-disable-line no-unused-vars
...headers
},
method,
status,
query,
} = ctx
const date = new Date()
/** @type {!_logarithm.Hit} */
const body = {
app,
method,
ip,
path: decodeURI(path),
headers: {
'user-agent': '',
...headers,
'cookie': undefined,
},
status,
date,
}
const q = /** @type {!Object} */ (query)
if (Object.keys(q).length) body.query = q
const i = strategy(index, date)
const u = `${url}/${i}/_doc`
// todo: batch
req(u, {
spec: {
method: 'POST',
timeout,
},
query: { pipeline },
}, body).then(() => {
// process.stdout.write('.')
}).catch(({ message }) => {
console.log(`Logarithm ERROR: ${message}`)
})
}
/**
* Create a middleware for logging requests.
* @param {_logarithm.Config} options Options for the program.
*/
const logarithm = (options) => {
if (!options) throw new Error('Options are not given')
const { app } = options
if (!app) throw new Error('The app is not defined')
/** @type {!_goa.Middleware} */
const es = async (ctx, next) => {
const onerror = ctx.onerror
// override error handler which sets status
let handled = false
ctx.onerror = (err) => {
onerror.call(ctx, err)
if (err) {
handled = true
process(ctx, options)
}
}
await next()
if (handled)
console.log('[logarithm] Error has been handled by context but not thrown in middleware chain.')
else
process(ctx, options)
}
return es
}
/**
* Check that a connection to the server can be established.
* @param {string} url The ElasticSearch URL.
* @param {number} [timeout=30000] The timeout for the request in ms. Default `30000`.
*/
export const ping = async (url, timeout = 30000) => {
const { statusCode } = await aqt(url, { timeout, justHeaders: true, method: 'HEAD' })
if (statusCode != 200) throw new Error(`Server responded with status code ${statusCode}`)
}
/**
* Returns an index name by months.
* @param {string} index The name of the index.
* @param {!Date} date The date of the request.
*/
const monthly = (index, date) => {
const y = date.getFullYear()
const m = date.getMonth() + 1
return `${index}-${y}.${m}`
}
export default logarithm
/**
* @suppress {nonStandardJsDocs}
* @typedef {import('../').Config} _logarithm.Config
*/
/**
* @suppress {nonStandardJsDocs}
* @typedef {import('../').Hit} _logarithm.Hit
*/
/**
* @suppress {nonStandardJsDocs}
* @typedef {import('@typedefs/goa').Middleware} _goa.Middleware
*/
/**
* @suppress {nonStandardJsDocs}
* @typedef {import('@typedefs/goa').Context} _goa.Context
*/