overleaf/services/web/app/src/Features/Analytics/AnalyticsManager.js
Jessica Lawshe 41d77889da Merge pull request #2354 from overleaf/em-disallow-console
Disallow console.log in backend code

GitOrigin-RevId: 53ff1f2f2585d05a0f2380336227c50524aee08c
2019-11-13 14:39:58 +00:00

162 lines
4.2 KiB
JavaScript

const settings = require('settings-sharelatex')
const logger = require('logger-sharelatex')
const request = require('request')
const FaultTolerantRequest = require('../../infrastructure/FaultTolerantRequest')
const Errors = require('../Errors/Errors')
// check that the request should be made: ignore smoke test user and ensure the
// analytics service is configured
const checkAnalyticsRequest = function(userId) {
if (
settings.smokeTest &&
settings.smokeTest.userId &&
settings.smokeTest.userId.toString() === userId.toString()
) {
// ignore smoke test user
return { error: null, skip: true }
}
if (!settings.apis.analytics) {
return {
error: new Errors.ServiceNotConfiguredError(
'Analytics service not configured'
),
skip: true
}
}
return { error: null, skip: false }
}
// prepare the request: set `fromv2` param and full URL
const prepareAnalyticsRequest = function(options) {
if (settings.overleaf != null) {
options.qs = Object.assign({}, options.qs, { fromV2: 1 })
}
const urlPath = options.url
options.url = `${settings.apis.analytics.url}${urlPath}`
options.timeout = options.timeout || 30000
return options
}
// make the request to analytics after checking and preparing it.
// request happens asynchronously in the background and will be retried on error
const makeAnalyticsBackgroundRequest = function(userId, options, callback) {
let { error, skip } = checkAnalyticsRequest(userId)
if (error || skip) {
return callback(error)
}
prepareAnalyticsRequest(options)
// With the tweaked parameter values (BACKOFF_BASE=3000, BACKOFF_MULTIPLIER=3):
// - the 6th attempt (maxAttempts=6) will run after 5.5 to 11.5 minutes
// - the 9th attempt (maxAttempts=9) will run after 86 to 250 minutes
options.maxAttempts = options.maxAttempts || 9
options.backoffBase = options.backoffBase || 3000
options.backoffMultiplier = options.backoffMultiplier || 3
FaultTolerantRequest.backgroundRequest(options, callback)
}
// make synchronous request to analytics without retries after checking and
// preparing it.
const makeAnalyticsRequest = function(userId, options, callback) {
let { error, skip } = checkAnalyticsRequest(userId)
if (error || skip) {
return callback(error)
}
prepareAnalyticsRequest(options)
request(options, callback)
}
module.exports = {
identifyUser(userId, oldUserId, callback) {
if (!callback) {
// callback is optional
callback = () => {}
}
const opts = {
body: {
old_user_id: oldUserId
},
json: true,
method: 'POST',
url: `/user/${userId}/identify`
}
makeAnalyticsBackgroundRequest(userId, opts, callback)
},
recordEvent(userId, event, segmentation, callback) {
if (segmentation == null) {
// segmentation is optional
segmentation = {}
}
if (!callback) {
// callback is optional
callback = () => {}
}
const opts = {
body: {
event,
segmentation
},
json: true,
method: 'POST',
url: `/user/${userId}/event`
}
makeAnalyticsBackgroundRequest(userId, opts, callback)
},
updateEditingSession(userId, projectId, countryCode, callback) {
if (!callback) {
// callback is optional
callback = () => {}
}
const query = {
userId,
projectId
}
if (countryCode) {
query.countryCode = countryCode
}
const opts = {
method: 'PUT',
url: '/editingSession',
qs: query,
maxAttempts: 6 // dont retry for too long as session ping timestamp are
// recorded when the request is received on the analytics
}
makeAnalyticsBackgroundRequest(userId, opts, callback)
},
getLastOccurrence(userId, event, callback) {
const opts = {
body: {
event
},
json: true,
method: 'POST',
timeout: 1000,
url: `/user/${userId}/event/last_occurrence`
}
makeAnalyticsRequest(userId, opts, function(err, response, body) {
if (err != null) {
logger.warn({ userId, err }, 'error getting last occurance of event')
callback(err)
} else {
callback(null, body)
}
})
}
}