Skip to content

Commit bda0959

Browse files
committed
add and refactor logs for health dashboard
1 parent bb537fe commit bda0959

File tree

22 files changed

+366
-201
lines changed

22 files changed

+366
-201
lines changed

app/auth/authenticate.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'
2+
import { defaultFieldResolver } from 'graphql'
13
import jwt from 'jsonwebtoken'
24
import jwksClient from 'jwks-rsa'
3-
import { defaultFieldResolver } from 'graphql'
4-
import { MapperKind, getDirective, mapSchema } from '@graphql-tools/utils'
5+
import { FCP_REQUEST_AUTHENTICATION_001 } from '../logger/codes.js'
56

6-
import { logger } from '../utils/logger.js'
77
import { Unauthorized } from '../errors/graphql.js'
88
import { AuthRole } from '../graphql/resolvers/authenticate.js'
9+
import { logger } from '../logger/logger.js'
910

1011
export async function getJwtPublicKey (kid) {
1112
const client = jwksClient({
@@ -25,9 +26,11 @@ export async function getAuth (request, getJwtPublicKeyFunc = getJwtPublicKey) {
2526
const decodedToken = jwt.decode(token, { complete: true })
2627
const header = decodedToken.header
2728
const signingKey = await getJwtPublicKeyFunc(header.kid)
28-
return jwt.verify(token, signingKey)
29+
const verified = jwt.verify(token, signingKey)
30+
logger.health('#authenticate - JWT verified', { code: FCP_REQUEST_AUTHENTICATION_001 })
31+
return verified
2932
} catch (error) {
30-
logger.error('#authenticate - Error verifying jwt', { error })
33+
logger.error('#authenticate - Error verifying jwt', { error, code: FCP_REQUEST_AUTHENTICATION_001 })
3134
return {}
3235
}
3336
}

app/data-sources/authenticate/AuthenticateDatabase.js

+35-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { Sequelize, DataTypes } from 'sequelize'
2-
import { logger } from '../../utils/logger.js'
1+
import { DataTypes, Sequelize } from 'sequelize'
2+
import { AUTHENTICATE_DATABASE_ALL_001 } from '../../logger/codes.js'
3+
import { logger } from '../../logger/logger.js'
34

45
const dbOptions = {
56
database: process.env.AUTHENTICATE_DB_SCHEMA,
@@ -34,22 +35,41 @@ export class AuthenticateDatabase {
3435
Updated: DataTypes.DATE
3536
})
3637

38+
async healthCheck () {
39+
try {
40+
await this.dbRead.authenticate()
41+
logger.health('#authenticate - database authenticated', { code: AUTHENTICATE_DATABASE_ALL_001 })
42+
} catch (error) {
43+
logger.error('Authenticate database error', { error, code: AUTHENTICATE_DATABASE_ALL_001 })
44+
throw error
45+
}
46+
}
47+
3748
async getAuthenticateQuestionsAnswersByCRN (crn, employeeId) {
38-
await this.dbAuditWrite.query(`
49+
try {
50+
logger.silly('Creating audit record in authenticate database', { employeeId, crn })
51+
await this.dbAuditWrite.query(`
3952
INSERT INTO Audits ([Date], [User], [Action], [Value])
4053
VALUES(?, ?, ?, ?);
4154
`, {
42-
replacements: [new Date().toISOString(), employeeId, 'Search', crn]
43-
})
44-
45-
const answers = await this.Answer.findOne({
46-
attributes: ['CRN', 'Date', 'Event', 'Location', 'Updated'],
47-
where: {
48-
CRN: crn
49-
}
50-
})
51-
52-
logger.info(`getAuthenticateQuestionsAnswersByCRN: got answers for ${crn}`)
53-
return answers
55+
replacements: [new Date().toISOString(), employeeId, 'Search', crn]
56+
})
57+
logger.debug('Created audit record in authenticate database', { employeeId, crn })
58+
59+
logger.silly('Getting authenticate questions answers by CRN', { crn, employeeId })
60+
const answers = await this.Answer.findOne({
61+
attributes: ['CRN', 'Date', 'Event', 'Location', 'Updated'],
62+
where: {
63+
CRN: crn
64+
}
65+
})
66+
logger.debug('Got authenticate questions answers by CRN', { crn, answers })
67+
68+
logger.health('#authenticate - answers retrieved', { code: AUTHENTICATE_DATABASE_ALL_001 })
69+
return answers
70+
} catch (error) {
71+
logger.error('Authenticate database error', { error, code: AUTHENTICATE_DATABASE_ALL_001 })
72+
throw error
73+
}
5474
}
5575
}

app/data-sources/entra-id/EntraIdApi.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { RESTDataSource } from '@apollo/datasource-rest'
22
import { DefaultAzureCredential } from '@azure/identity'
3-
import { logger } from '../../utils/logger.js'
3+
import { ENTRA_REQUEST_EMPLOYEE_LOOKUP_001 } from '../../logger/codes.js'
4+
import { logger } from '../../logger/logger.js'
45

56
const credential = new DefaultAzureCredential()
67

@@ -24,17 +25,19 @@ export class EntraIdApi extends RESTDataSource {
2425
}
2526
}
2627
)
27-
2828
employeeId = response.employeeId
29-
} catch (err) {
30-
logger.error(err)
29+
} catch (error) {
30+
logger.error('Could not get the employee ID for the user', { entraIdUserObjectId, error, code: ENTRA_REQUEST_EMPLOYEE_LOOKUP_001 })
3131
throw new Error(`Could not get the employee ID for the user: ${entraIdUserObjectId}`)
3232
}
3333

3434
if (!employeeId) {
35+
logger.error('Missing employee ID for user', { entraIdUserObjectId, code: ENTRA_REQUEST_EMPLOYEE_LOOKUP_001 })
3536
throw new Error(`Missing employee ID for user: ${entraIdUserObjectId}`)
3637
}
3738

39+
logger.health('Successful get employee ID for user', { code: ENTRA_REQUEST_EMPLOYEE_LOOKUP_001 })
40+
3841
return employeeId
3942
}
4043
}

app/data-sources/rural-payments-portal/RuralPaymentsSession.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { HttpsProxyAgent } from 'https-proxy-agent'
88
import qs from 'qs'
99
import { CookieJar } from 'tough-cookie'
1010
import { URL } from 'url'
11-
import { logger } from '../../utils/logger.js'
11+
import { logger } from '../../logger/logger.js'
1212

1313
const defaultHeaders = {
1414
'Accept-Encoding': 'gzip, deflate, br',
@@ -26,7 +26,7 @@ const apiCredentials = {
2626
password: process.env.RURAL_PAYMENTS_PORTAL_PASSWORD
2727
}
2828

29-
logger.debug('#RuralPaymentsSession - Set api credentials', { apiCredentials })
29+
logger.verbose('#RuralPaymentsSession - Set api credentials', { apiCredentials })
3030

3131
export class RuralPaymentsSession extends RESTDataSource {
3232
baseURL = process.env.RURAL_PAYMENTS_PORTAL_API_URL
@@ -85,7 +85,7 @@ export class RuralPaymentsSession extends RESTDataSource {
8585
async handleRedirects (response) {
8686
if ([301, 302, 303].includes(response?.status)) {
8787
const redirectUrl = new URL(response.headers.get('location'))
88-
logger.debug('#RuralPaymentsSession - handle redirect', {
88+
logger.verbose('#RuralPaymentsSession - handle redirect', {
8989
status: response?.status,
9090
redirect: redirectUrl.pathname
9191
})
@@ -107,7 +107,7 @@ export class RuralPaymentsSession extends RESTDataSource {
107107
}
108108

109109
async fetch (path, incomingRequest) {
110-
logger.debug('#RuralPaymentsSession - new request ', {
110+
logger.verbose('#RuralPaymentsSession - new request ', {
111111
path,
112112
method: incomingRequest.method,
113113
cookies: this.jar
@@ -116,7 +116,7 @@ export class RuralPaymentsSession extends RESTDataSource {
116116
.join(', ')
117117
})
118118
const result = await super.fetch(path, incomingRequest)
119-
logger.debug('#RuralPaymentsSession - response ', {
119+
logger.verbose('#RuralPaymentsSession - response ', {
120120
path,
121121
status: result.response?.status,
122122
body: result.response.parsedBody,

app/data-sources/rural-payments/RuralPayments.js

+44-20
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { RESTDataSource } from '@apollo/datasource-rest'
2-
import { StatusCodes } from 'http-status-codes'
2+
import { GraphQLError } from 'graphql'
3+
import StatusCodes from 'http-status-codes'
34
import fetch from 'node-fetch'
45
import qs from 'qs'
5-
import { logger } from '../../utils/logger.js'
6+
import { APIM_REQUEST_ACCESS_TOKEN_001, APIM_REQUEST_RURAL_PAYMENTS_REQUEST_001, RURALPAYMENTS_REQUEST_ALL_001 } from '../../logger/codes.js'
7+
import { logger } from '../../logger/logger.js'
68

79
const defaultHeaders = {
810
'Ocp-Apim-Subscription-Key': process.env.RP_INTERNAL_APIM_SUBSCRIPTION_KEY
@@ -20,33 +22,56 @@ export class RuralPayments extends RESTDataSource {
2022
}
2123

2224
async fetch (path, incomingRequest) {
23-
logger.debug('#RuralPayments - new request', {
25+
logger.verbose('#RuralPayments - new request', {
2426
path,
2527
method: incomingRequest.method
2628
})
2729

2830
const doRequest = async (count = 1) => {
2931
try {
32+
const requestStart = Date.now()
3033
const result = await super.fetch(path, incomingRequest)
31-
logger.debug('#RuralPayments - response ', {
34+
const requestEnd = (Date.now() - requestStart)
35+
logger.verbose('#RuralPayments - response ', {
3236
path,
33-
status: result.response?.status,
34-
body: result.response?.parsedBody
37+
status: result.response?.status
38+
})
39+
logger.health('#RuralPayments - request success', {
40+
code: RURALPAYMENTS_REQUEST_ALL_001,
41+
requestTimeMs: requestEnd
42+
})
43+
logger.health('#APIM - request success', {
44+
code: APIM_REQUEST_RURAL_PAYMENTS_REQUEST_001
3545
})
3646
return result
3747
} catch (error) {
3848
// Handle occasionally 500 error produced by APIM
39-
// TODO: Once APIM has been fixed remove retry logic
49+
// TODO: Once APIM has been fixed, remove retry logic
4050
if (error?.extensions?.response?.status === StatusCodes.INTERNAL_SERVER_ERROR && count < maximumRetries) {
41-
logger.error(`#RuralPayments - Error, Retrying request (${count})`, {
51+
logger.warn(`#RuralPayments - Error, Retrying request (${count})`, { error })
52+
return doRequest(count + 1)
53+
}
54+
// if response is text, then the error is from RoralPayments
55+
if (error?.extensions?.response?.headers?.get('Content-Type')?.includes('text/html')) {
56+
logger.error('#RuralPayments - error', {
57+
error,
4258
path,
4359
method: incomingRequest.method,
4460
count,
45-
error
61+
response: error?.extensions?.response,
62+
code: RURALPAYMENTS_REQUEST_ALL_001
63+
})
64+
} else {
65+
// if response is json, then the error is from APIM
66+
logger.error('#APIM - error', {
67+
error,
68+
path,
69+
method: incomingRequest.method,
70+
count,
71+
response: error?.extensions?.response,
72+
code: APIM_REQUEST_RURAL_PAYMENTS_REQUEST_001
4673
})
47-
return doRequest(count + 1)
4874
}
49-
logger.error('#RuralPayments - Error fetching data', { error })
5075
throw error
5176
}
5277
}
@@ -59,19 +84,17 @@ export class RuralPayments extends RESTDataSource {
5984
if (response.ok) {
6085
return
6186
}
62-
logger.error('#RuralPayments - error', {
63-
status: response?.status,
64-
url: response?.url,
65-
error: response?.error
87+
88+
throw new GraphQLError(`${options.response.status}: ${options.response.statusText}`, {
89+
extensions: options
6690
})
67-
throw await this.errorFromResponse(options)
6891
}
6992

7093
async willSendRequest (_path, request) {
7194
if (!this.apimAccessToken) {
72-
logger.debug('Getting APIM access token')
95+
logger.verbose('Getting APIM access token')
7396
await this.getApimAccessToken()
74-
logger.debug('APIM access token', {
97+
logger.verbose('APIM access token', {
7598
apimAccessToken: this.apimAccessToken
7699
})
77100
}
@@ -105,7 +128,7 @@ export class RuralPayments extends RESTDataSource {
105128
}
106129

107130
try {
108-
logger.debug(
131+
logger.verbose(
109132
`Token request url: ${process.env.RP_INTERNAL_APIM_ACCESS_TOKEN_URL}${process.env.RP_INTERNAL_APIM_TENANT_ID}/oauth2/v2.0/token`
110133
)
111134
const response = await fetch(
@@ -123,9 +146,10 @@ export class RuralPayments extends RESTDataSource {
123146
throw new Error('No access token returned')
124147
}
125148

149+
logger.health('Successfully got APIM access token', { code: APIM_REQUEST_ACCESS_TOKEN_001 })
126150
this.apimAccessToken = data.access_token
127151
} catch (error) {
128-
logger.error('Error getting APIM access token', { error })
152+
logger.error('Error getting APIM access token', { error, code: APIM_REQUEST_ACCESS_TOKEN_001 })
129153
throw error
130154
}
131155
}

app/data-sources/rural-payments/RuralPaymentsBusiness.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import { logger, sampleResponse } from '../../utils/logger.js'
1+
import { logger } from '../../logger/logger.js'
2+
import { sampleResponse } from '../../logger/utils.js'
23
import { RuralPayments } from './RuralPayments.js'
34

45
export class RuralPaymentsBusiness extends RuralPayments {
56
async getOrganisationById (id) {
6-
logger.debug('Getting organisation by ID', { id })
7+
logger.verbose('Getting organisation by ID', { id })
78
try {
89
const organisationResponse = await this.get(`organisation/${id}`)
910

10-
logger.debug('Organisation by ID', { organisationResponse })
11+
logger.verbose('Organisation by ID', { organisationResponse })
1112
return organisationResponse._data
1213
} catch (error) {
1314
logger.error('Error getting organisation by ID', { id, error })
@@ -16,7 +17,7 @@ export class RuralPaymentsBusiness extends RuralPayments {
1617
}
1718

1819
async getOrganisationBySBI (sbi) {
19-
logger.debug('Getting organisation by SBI', { sbi })
20+
logger.verbose('Getting organisation by SBI', { sbi })
2021
const body = JSON.stringify({
2122
searchFieldType: 'SBI',
2223
primarySearchPhrase: sbi,

0 commit comments

Comments
 (0)