Skip to content
Snippets Groups Projects
Commit 772de020 authored by Rémi PAILHAREY's avatar Rémi PAILHAREY :fork_knife_plate:
Browse files

Merge branch '25-follow-up-from-detailed-sentry-logs' into 'main'

feat: detailed sentry logs

See merge request !44
parents aafdb1e6 e1de1d35
No related branches found
No related tags found
1 merge request!44feat: detailed sentry logs
Pipeline #70609 passed
Showing
with 219 additions and 89 deletions
......@@ -22,6 +22,7 @@
"source.fixAll": true,
"source.organizeImports": true
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"cSpell.words": [
"acces",
"apikey",
......
......@@ -36,7 +36,7 @@ describe('activateContract', () => {
)
expect(serviceId).toBe(78232791)
} catch (error) {
expect(error).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
expect(error.message).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
}
mockParseServiceId.mockRestore()
......@@ -56,7 +56,7 @@ describe('activateContract', () => {
)
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
expect(error.message).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
}
mockParseServiceId.mockRestore()
......@@ -87,7 +87,7 @@ describe('activateContract', () => {
)
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
expect(error.message).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
}
mockParseServiceId.mockRestore()
......
......@@ -61,7 +61,7 @@ describe('getContractStartDate', () => {
await getContractStartDate()
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.VENDOR_DOWN)
expect(error.message).toBe(errors.VENDOR_DOWN)
}
})
......@@ -84,7 +84,7 @@ describe('getContractStartDate', () => {
)
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.NOT_EXISTING_DIRECTORY)
expect(error.message).toBe(errors.NOT_EXISTING_DIRECTORY)
}
})
})
......@@ -40,7 +40,7 @@ describe('terminateContract', () => {
},
})
} catch (error) {
expect(error).toBe(errors.VENDOR_DOWN)
expect(error.message).toBe(errors.VENDOR_DOWN)
}
})
it('should throw VENDOR_DOWN on bad request🚫', async () => {
......@@ -56,7 +56,7 @@ describe('terminateContract', () => {
)
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.VENDOR_DOWN)
expect(error.message).toBe(errors.VENDOR_DOWN)
}
})
it('should throw VENDOR_DOWN 🚫', async () => {
......@@ -80,7 +80,7 @@ describe('terminateContract', () => {
)
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.VENDOR_DOWN)
expect(error.message).toBe(errors.VENDOR_DOWN)
}
})
})
......@@ -74,7 +74,7 @@ describe('verifyContract', () => {
)
expect(serviceId).toBe(78232791)
} catch (error) {
expect(error).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
expect(error.message).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
}
mockParseContracts.mockRestore()
......@@ -126,7 +126,7 @@ describe('verifyContract', () => {
)
expect(serviceId).toBe(78232791)
} catch (error) {
expect(error).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
expect(error.message).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
}
mockParseContracts.mockRestore()
......@@ -186,7 +186,7 @@ describe('verifyContract', () => {
)
expect(serviceId).toBe(null)
} catch (error) {
expect(error).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
expect(error.message).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
}
mockParseContracts.mockRestore()
......@@ -204,7 +204,7 @@ describe('verifyContract', () => {
)
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
expect(error.message).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
}
})
it('should return CAPTCHA_RESOLUTION_FAILED if issue in parsing 🚫', async () => {
......@@ -229,7 +229,7 @@ describe('verifyContract', () => {
)
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
expect(error.message).toBe(errors.CAPTCHA_RESOLUTION_FAILED)
}
})
it('should return NULL if no contract are found 🚫', async () => {
......
......@@ -34,7 +34,7 @@ describe('findUserAddress', () => {
await findUserAddress()
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.VENDOR_DOWN)
expect(error.message).toBe(errors.VENDOR_DOWN)
}
})
......@@ -48,7 +48,7 @@ describe('findUserAddress', () => {
await findUserAddress()
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.VENDOR_DOWN)
expect(error.message).toBe(errors.VENDOR_DOWN)
}
})
})
......@@ -75,7 +75,7 @@ describe('recherchePoint', () => {
await findUserPdl()
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.VENDOR_DOWN)
expect(error.message).toBe(errors.VENDOR_DOWN)
}
})
})
......@@ -35,7 +35,7 @@ describe('verifyUserIdentity', () => {
)
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.LOGIN_FAILED)
expect(error.message).toBe(errors.LOGIN_FAILED)
}
})
......@@ -56,7 +56,7 @@ describe('verifyUserIdentity', () => {
)
expect(true).toBe(false)
} catch (error) {
expect(error).toBe(errors.TERMS_VERSION_MISMATCH)
expect(error.message).toBe(errors.TERMS_VERSION_MISMATCH)
}
})
......
......@@ -58,8 +58,8 @@ describe('Backoffice routes', () => {
'69383'
)
expect(true).toBe(false)
} catch (e) {
expect(e).toBe(errors.MAINTENANCE)
} catch (error) {
expect(error.message).toBe(errors.MAINTENANCE)
}
})
})
......@@ -122,8 +122,8 @@ describe('Backoffice routes', () => {
'123456'
)
expect(true).toBe(false)
} catch (e) {
expect(e).toBe(errors.MAINTENANCE)
} catch (error) {
expect(error.message).toBe(errors.MAINTENANCE)
}
})
})
......@@ -161,8 +161,8 @@ describe('Backoffice routes', () => {
try {
await deleteBoConsent('http://test.com', 'token', 1)
expect(true).toBe(false)
} catch (e) {
expect(e).toBe(errors.MAINTENANCE)
} catch (error) {
expect(error.message).toBe(errors.MAINTENANCE)
}
})
})
......@@ -202,8 +202,8 @@ describe('Backoffice routes', () => {
inseeCode: '69383',
})
expect(true).toBe(false)
} catch (e) {
expect(e).toBe(errors.MAINTENANCE)
} catch (error) {
expect(error.message).toBe(errors.MAINTENANCE)
}
})
})
......
......@@ -10,7 +10,7 @@ describe('getInseeCode', () => {
try {
await getInseeCode(69069)
} catch (error) {
expect(error).toEqual(errors.USER_ACTION_NEEDED)
expect(error.message).toBe(errors.USER_ACTION_NEEDED)
}
})
......@@ -18,7 +18,7 @@ describe('getInseeCode', () => {
try {
await getInseeCode(69290)
} catch (error) {
expect(error).toEqual(errors.USER_ACTION_NEEDED)
expect(error.message).toBe(errors.USER_ACTION_NEEDED)
}
})
......@@ -54,7 +54,7 @@ describe('getInseeCode', () => {
try {
await getInseeCode(26600, 'e')
} catch (error) {
expect(error).toEqual(errors.USER_ACTION_NEEDED)
expect(error.message).toBe(errors.USER_ACTION_NEEDED)
}
})
})
......
......@@ -44,10 +44,19 @@ async function activateContract(
endDate
),
}).catch(err => {
log('error', 'commanderCollectePublicationMesures')
log('error', err)
Sentry.captureException('commanderCollectePublicationMesures', err)
throw errors.CAPTCHA_RESOLUTION_FAILED
const errorMessage = `Error while activating contract : ${err}`
log('debug', errorMessage)
Sentry.captureException(errorMessage, {
tags: {
section: 'activateContract',
},
extra: {
pointId: pointId,
dates: [startDate, endDate],
},
})
throw new Error(errors.CAPTCHA_RESOLUTION_FAILED)
})
const parsedReply = await xml2js.parseStringPromise(response.body, {
......@@ -71,7 +80,7 @@ async function activateContract(
// TODO: handle SGT4B8: Il existe déjà plusieurs demandes en cours sur le point ?
// TODO: handle SGT4H9: La demande ne porte pas sur un point équipé d'un compteur communicant ouvert aux services niveau 2.
// TODO: handle SGT589: La demande ne peut pas aboutir car le compteur n'est actuellement pas téléopérable.
throw errors.CAPTCHA_RESOLUTION_FAILED
throw new Error(errors.CAPTCHA_RESOLUTION_FAILED)
}
}
......
......@@ -32,8 +32,15 @@ async function getContractStartDate(url, apiAuthKey, userLogin, pointId) {
}).catch(err => {
const errorMessage = 'Error while fetching contract start date : ' + err
log('error', errorMessage)
Sentry.captureException(errorMessage)
throw errors.VENDOR_DOWN
Sentry.captureException(errorMessage, {
tags: {
section: 'getContractStartDate',
},
extra: {
pointId: pointId,
},
})
throw new Error(errors.VENDOR_DOWN)
})
const result = await xml2js.parseStringPromise(response.body, {
......@@ -51,7 +58,7 @@ async function getContractStartDate(url, apiAuthKey, userLogin, pointId) {
'error',
`Enedis issue ${result.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${result.Envelope.Body.Fault.faultstring}`
)
throw errors.NOT_EXISTING_DIRECTORY
throw new Error(errors.NOT_EXISTING_DIRECTORY)
}
}
......
......@@ -38,10 +38,19 @@ async function terminateContract(
serviceId
),
}).catch(err => {
log('error', 'commanderArretServiceSouscritMesures')
log('error', err)
Sentry.captureException('commanderArretServiceSouscritMesures', err)
throw errors.VENDOR_DOWN
const errorMessage = 'Error while terminating contract : ' + err
log('error', errorMessage)
Sentry.captureException(errorMessage, {
tags: {
section: 'terminateContract',
},
extra: {
contractId: contractId,
pointId: pointId,
serviceId: serviceId,
},
})
throw new Error(errors.VENDOR_DOWN)
})
const parsedReply = await xml2js.parseStringPromise(response.body, {
......@@ -64,8 +73,15 @@ async function terminateContract(
'Error while parsing user contract termination: ' + error
log('error', errorMessage)
log('error', `Enedis issue ${JSON.stringify(parsedReply.Envelope.Body)}`)
Sentry.captureException(errorMessage)
throw errors.VENDOR_DOWN
Sentry.captureException(errorMessage, {
tags: {
section: 'terminateContract',
},
extra: {
pointId: pointId,
},
})
throw new Error(errors.VENDOR_DOWN)
}
}
......
......@@ -31,10 +31,18 @@ async function verifyContract(url, apiAuthKey, appLogin, contractId, pointId) {
headers: sgeHeaders,
xml: rechercherServicesSouscritsMesures(appLogin, contractId, pointId),
}).catch(err => {
log('error', 'rechercherServicesSouscritsMesures')
log('error', err)
Sentry.captureException('rechercherServicesSouscritsMesures', err)
throw errors.CAPTCHA_RESOLUTION_FAILED
const errorMessage = 'Error while verifying contract : ' + err
log('error', errorMessage)
Sentry.captureException(errorMessage, {
tags: {
section: 'verifyContract',
},
extra: {
contractId: contractId,
pointId: pointId,
},
})
throw new Error(errors.CAPTCHA_RESOLUTION_FAILED)
})
const parsedReply = await xml2js.parseStringPromise(response.body, {
......@@ -66,7 +74,11 @@ async function verifyContract(url, apiAuthKey, appLogin, contractId, pointId) {
} catch (error) {
const errorMessage = 'Error while parsing user contract: ' + error
log('error', errorMessage)
Sentry.captureException(errorMessage)
Sentry.captureException(errorMessage, {
tags: {
section: 'verifyContract',
},
})
if (parsedReply.Envelope.Body.Fault) {
log(
'error',
......@@ -77,7 +89,7 @@ async function verifyContract(url, apiAuthKey, appLogin, contractId, pointId) {
'error',
'if an error is thrown here, it probably means that the contract has already been open today and that enedis cannot open a second one. Wait until tomorow to try again'
)
throw errors.CAPTCHA_RESOLUTION_FAILED
throw new Error(errors.CAPTCHA_RESOLUTION_FAILED)
}
}
......
......@@ -32,8 +32,15 @@ async function findUserAddress(url, apiAuthKey, userLogin, pointId) {
}).catch(err => {
const errorMessage = 'Error while fetching user : ' + err
log('error', errorMessage)
Sentry.captureException(errorMessage)
throw errors.VENDOR_DOWN
Sentry.captureException(errorMessage, {
tags: {
section: 'findUserAddress',
},
extra: {
pointId: pointId,
},
})
throw new Error(errors.VENDOR_DOWN)
})
const result = await xml2js.parseStringPromise(response.body, {
......@@ -51,8 +58,12 @@ async function findUserAddress(url, apiAuthKey, userLogin, pointId) {
'error',
`Enedis issue ${result.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${result.Envelope.Body.Fault.faultstring}`
)
Sentry.captureException(errorMessage)
throw errors.VENDOR_DOWN
Sentry.captureException(errorMessage, {
tags: {
section: 'findUserAddress',
},
})
throw new Error(errors.VENDOR_DOWN)
}
}
......
......@@ -44,10 +44,19 @@ async function findUserPdl(
escalierEtEtageEtAppartement
),
}).catch(err => {
log('error', 'rechercherPointResponse')
log('error', err)
Sentry.captureException('rechercherPointResponse', err)
throw errors.VENDOR_DOWN
const errorMessage = 'Error while finding user pdl : ' + err
log('error', errorMessage)
Sentry.captureException(errorMessage, {
tags: {
section: 'findUserPdl',
},
extra: {
address: address,
postalCode: postalCode,
escalierEtEtageEtAppartement: escalierEtEtageEtAppartement,
},
})
throw new Error(errors.VENDOR_DOWN)
})
const parsedReply = await xml2js.parseStringPromise(response.body, {
......
......@@ -28,8 +28,8 @@ async function verifyUserIdentity(
isAlternateStart = false,
inseeCode = ''
) {
// If first start get InseeCode
log('debug', 'verifyUserIdentity')
// If first start get InseeCode
if (!isAlternateStart) {
inseeCode = await getInseeCode(fields.postalCode, fields.city)
}
......@@ -124,7 +124,9 @@ async function verifyUserIdentity(
}
if (!pdl) {
Sentry.captureException('Second chance failed, no pdl found')
Sentry.captureException('Second chance failed, no pdl found', {
tags: { section: 'verifyUserIdentity' },
})
}
}
......@@ -132,11 +134,15 @@ async function verifyUserIdentity(
log('error', 'PointId does not match')
if (isAlternateStart) {
Sentry.captureException('PointId does not match: Alternate start')
throw errors.TERMS_VERSION_MISMATCH
Sentry.captureException('PointId does not match: Alternate start', {
tags: { section: 'verifyUserIdentity' },
})
throw new Error(errors.TERMS_VERSION_MISMATCH)
} else {
Sentry.captureException('PointId does not match')
throw errors.LOGIN_FAILED
Sentry.captureException('PointId does not match', {
tags: { section: 'verifyUserIdentity' },
})
throw new Error(errors.LOGIN_FAILED)
}
}
......
// @ts-check
const { log } = require('cozy-konnector-libs')
const moment = require('moment')
const Sentry = require('@sentry/node')
/**
* Return User PDL
......@@ -210,7 +211,16 @@ function parsePointId(pointId) {
} else if (strPointId.length === 13) {
return `0${strPointId}`
} else {
throw new Error(`PointId ${pointId} is malformed`)
const errorMessage = 'PointId is malformed'
Sentry.captureException(errorMessage, {
tags: {
section: 'parsePointId',
},
extra: {
pointId: pointId,
},
})
throw new Error(errorMessage)
}
}
......
......@@ -90,6 +90,11 @@ Sentry.init({
* @param {{secret: fields}} cozyParameters
*/
async function start(fields, cozyParameters) {
const transaction = Sentry.startTransaction({
op: 'konnector',
name: 'SGE Konnector',
})
transaction.startChild({ op: 'Konnector starting' })
try {
log('info', 'Konnector configuration ...')
log('info', `isManual execution: ${manualExecution}`)
......@@ -100,10 +105,6 @@ async function start(fields, cozyParameters) {
'NO_DATA is enabled, konnector will stop after verifyUserIdentity()'
)
}
const transaction = Sentry.startTransaction({
op: 'konnector',
name: 'SGE Konnector',
})
const pointId = parsePointId(parseInt(fields.pointId))
let baseUrl = fields.wso2BaseUrl
......@@ -133,8 +134,10 @@ async function start(fields, cozyParameters) {
) {
const errorMessage = 'Missing configuration secrets'
log('error', errorMessage)
Sentry.captureException(errorMessage)
throw errors.VENDOR_DOWN
Sentry.captureException(errorMessage, {
tags: { section: 'start' },
})
throw new Error(errors.VENDOR_DOWN)
}
/**
......@@ -245,8 +248,10 @@ async function start(fields, cozyParameters) {
if (!userConsent) {
const errorMessage = 'No user consent found'
log('error', errorMessage)
Sentry.captureException(errorMessage)
throw errors.VENDOR_DOWN
Sentry.captureException(errorMessage, {
tags: { section: 'start' },
})
throw new Error(errors.VENDOR_DOWN)
}
const consentEndDate = Date.parse(userConsent.endDate)
......@@ -276,7 +281,16 @@ async function start(fields, cozyParameters) {
transaction.finish()
log('info', 'Konnector success')
} catch (error) {
log('debug', 'error catched in start()', error)
const errorMessage = `SGE konnector encountered an error. Response data: ${JSON.stringify(
error.message
)}`
Sentry.captureMessage(errorMessage, {
tags: {
section: 'start',
},
})
transaction.setStatus(Tracing.spanStatusfromHttpCode(409))
transaction.finish()
await Sentry.flush()
throw error
}
......@@ -320,14 +334,18 @@ async function deleteConsent(
} else {
const errorMessage = `No service id retrieved from BO`
log('error', errorMessage)
Sentry.captureException(errorMessage)
throw errors.VENDOR_DOWN
Sentry.captureException(errorMessage, {
tags: { section: 'start' },
})
throw new Error(errors.VENDOR_DOWN)
}
if (isConsentExpired) {
Sentry.captureException('Consent expired')
throw errors.USER_ACTION_NEEDED_OAUTH_OUTDATED
Sentry.captureException('Consent expired', {
tags: { section: 'start' },
})
throw new Error(errors.USER_ACTION_NEEDED_OAUTH_OUTDATED)
}
throw errors.TERMS_VERSION_MISMATCH
throw new Error(errors.TERMS_VERSION_MISMATCH)
}
/**
......@@ -400,7 +418,9 @@ async function getData(url, apiAuthKey, userLogin, pointId) {
}).catch(err => {
log('error', 'consultationMesuresDetaillees')
log('error', err)
Sentry.captureException('consultationMesuresDetaillees:', err)
Sentry.captureException(`consultationMesuresDetaillees: ${err}`, {
tags: { section: 'getData' },
})
return err
})
......@@ -443,7 +463,9 @@ async function getMaxPowerData(url, apiAuthKey, userLogin, pointId) {
}).catch(err => {
log('error', 'getMaxPowerData')
log('error', err)
Sentry.captureException('getMaxPowerDate')
Sentry.captureException(`getMaxPowerData: ${err}`, {
tags: { section: 'getMaxPowerData' },
})
return err
})
......@@ -496,7 +518,7 @@ async function getDataHalfHour(url, apiAuthKey, userLogin, pointId) {
// If manual execution, retrieve only 1 week otherwise retrieve 4 weeks
const MAX_HISTO = manualExecution ? 1 : 4
for (var i = 0; i < MAX_HISTO; i++) {
for (let i = 0; i < MAX_HISTO; i++) {
log('info', 'launch process with history')
const incrementedStartDateString = moment(startLoadDate)
.subtract(7 * i, 'day')
......@@ -519,7 +541,12 @@ async function getDataHalfHour(url, apiAuthKey, userLogin, pointId) {
}).catch(err => {
log('error', 'consultationMesuresDetaillees half-hour')
log('error', err)
Sentry.captureException('consultationMesuresDetaillees half-hour')
Sentry.captureException(
`consultationMesuresDetaillees half-hour: ${err}`,
{
tags: { section: 'getDataHalfHour' },
}
)
return err
})
......@@ -565,7 +592,9 @@ function processData(doctype = 'com.grandlyon.enedis.day') {
} catch (e) {
if (doctype === 'com.grandlyon.enedis.minute') {
const errorMessage = `No half-hour activated. Issue: ${result.Envelope.Body.Fault.faultstring}`
Sentry.captureMessage(errorMessage)
Sentry.captureMessage(errorMessage, {
tags: { section: 'processData' },
})
log('warn', errorMessage)
} else {
log('warn', `Unknown error ${e}`)
......
......@@ -12,10 +12,30 @@ const moment = require('moment')
require('moment-timezone')
const { isLocal, isDev } = require('./helpers/env')
const Sentry = require('@sentry/node')
const { version } = require('../package.json')
moment.locale('fr') // set the language
moment.tz.setDefault('Europe/Paris') // set the timezone
/**
* Sentry
*/
Sentry.init({
dsn: 'https://18747a93401447f2a81b83cd8c4bbbdf@grandlyon.errors.cozycloud.cc/5',
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: isLocal() ? 0 : 1.0,
release: version,
environment: isDev() ? 'development' : 'production',
debug: isDev(),
integrations: [
// enable HTTP calls tracing
new Sentry.Integrations.Http({ tracing: true }),
],
})
async function onDeleteAccount() {
try {
log('info', 'Deleting account ...')
......@@ -69,8 +89,7 @@ async function onDeleteAccount() {
} else {
const errorMessage = `No service id retrieved from BO`
log('error', errorMessage)
Sentry.captureException(errorMessage)
throw errors.VENDOR_DOWN
throw new Error(errorMessage)
}
}
......@@ -79,8 +98,7 @@ async function onDeleteAccount() {
const errorMessage =
'No account revision was found, something went wrong during the deletion of said account'
log('error', errorMessage)
Sentry.captureException(errorMessage)
throw errors.VENDOR_DOWN
throw new Error(errorMessage)
}
} catch (error) {
log('debug', 'error catched in onDeleteAccount()', error)
......@@ -98,8 +116,10 @@ onDeleteAccount().then(
err => {
const errorMessage = `onDeleteAccount: An error occurred during script: ${err.message}`
log('error', errorMessage)
Sentry.captureException(errorMessage)
throw errors.VENDOR_DOWN
Sentry.captureException(errorMessage, {
tags: { section: 'onDeleteAccount' },
})
throw new Error(errors.VENDOR_DOWN)
}
)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment