Skip to content

Commit c83dd9c

Browse files
CCM-17047: Add client , campaign and supplier name to Grafana dashboard (#543)
* emit metrics for supplier-allocator * ensure that clientId and campaignId is never undefined when emiting metric * use distinct the name for the new metric * get unit tests to pass * add a dummy supplier * remove comments * rename metric key variable in function * expose groupId in allocate-handler lambda. Expose groupId and correct metrics in upsert-handler lambda. Add extra information in README * correct check file format * correct markdown errors * correct markdown errors * update lock file * fix lint and unit test errors * fix audit errors * Revert "fix audit errors" This reverts commit 2155558. * address PR review comments * add new line in group-id.ts * update package-lock file * fix linting and pact test error * fix failing pact test * fix build?
1 parent 7b4c191 commit c83dd9c

10 files changed

Lines changed: 288 additions & 159 deletions

File tree

.env.template

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
ENVIRONMENT=$ENV_NAME
2-
API_KEY=
3-
HEADERAUTH=
41
PR_NUMBER=prxx # remove if needs to run against main
5-
NHSD_APIM_TOKEN=
6-
PROXY_NAME=
2+
GITHUB_TOKEN= # Your github Personal Access Token (PAT)
3+
4+
5+
# The variables below are used for End to End tests
6+
PROXY_NAME= # information about the proxy name can be found in the tests/e2e-tests/README.md
7+
8+
9+
710
# * nhs-notify-supplier--internal-dev--nhs-notify-supplier
811
# * nhs-notify-supplier--internal-dev--nhs-notify-supplier-PR-XX
912
# * nhs-notify-supplier--ref--nhs-notify-supplier -- ref env

README.md

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
<!-- vale off -->
12
# NHS Notify Supplier API
23

34
[![1. CI/CD pull request](https://github.com/NHSDigital/nhs-notify-supplier-api/actions/workflows/cicd-1-pull-request.yaml/badge.svg)](https://github.com/NHSDigital/nhs-notify-supplier-api/actions/workflows/cicd-1-pull-request.yaml)
@@ -75,9 +76,49 @@ New developers of the NHS Notify Supplier API should understand the below.
7576

7677
#### Prerequisites and Configuration
7778

78-
- Utilised the devcontainer, for pre reqs and configuration.
79-
- You should open in a devcontainer or a Github workspaces.
80-
- By default it will run `make config` when the container is first setup
79+
- Create the file `~/.aws/config` with the following contents:
80+
81+
```dsconfig
82+
[profile ]
83+
region = eu-west-2
84+
output = json
85+
86+
[profile supplier-dev]
87+
sso_start_url = https://d-9c67018f89.awsapps.com/start#/
88+
sso_region = eu-west-2
89+
sso_account_id = 820178564574
90+
sso_role_name = nhs-notify-bc-developer
91+
region = eu-west-2
92+
output = json
93+
94+
[profile supplier-nonprod]
95+
sso_start_url = https://d-9c67018f89.awsapps.com/start#/
96+
sso_region = eu-west-2
97+
sso_account_id = 885964308133
98+
sso_role_name = nhs-notify-bc-developer
99+
region = eu-west-2
100+
output = json
101+
```
102+
103+
- In your `~/.bashrc` or `~/.zshrc` add the export `export AWS_PROFILE=supplier-dev`, or whichever profile you need
104+
- In the project's root directory create an `.env` file based on the `.env.template` file and fill variables as needed.
105+
- Create the file `~/.npmrc` with the contents:
106+
107+
```dsconfig
108+
# Authenticate to GitHub Packages for github.com
109+
//npm.pkg.github.com/:_authToken=<Insert your Github PAT (Personal Access Token)>
110+
111+
112+
# Package is scoped under @org, set registry for that scope
113+
@nhsdigital:registry=https://npm.pkg.github.com
114+
```
115+
116+
- Install `node` (to run `npm install` and build the project)
117+
- Install `aws cli` to be able to connect to AWS (needed for some tests)
118+
- If AWS CLI calls are blocked by a firewall (e.g. Zscaler), you need to add the custom certificates in the location `/scripts/devcontainer/custom-ca-certs`
119+
- Install `docker` or `Rancher` for containerisation
120+
- You should open in a devcontainer or a Github workspaces. (In VSCode -> Open Command Palet -> "Dev containers: rebuild without cache and reopen in container")
121+
- By default it will run `make config` when the container is first setup
81122

82123
##### SDKs
83124

@@ -151,3 +192,5 @@ Import the files into postman
151192
Select a target environment in postman
152193
Run the collection
153194
The collections must be kept in sync manually
195+
196+
<!-- vale on -->

internal/helpers/src/group-id.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function formatGroupId(
2+
clientId: string,
3+
campaignId = "unknown",
4+
safeTemplateId = "unknown",
5+
): string {
6+
return `${clientId}_${campaignId}_${safeTemplateId}`;
7+
}

internal/helpers/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ export { default as $Environment } from "./environment";
99
export * from "./id-ref";
1010
export * from "./logger";
1111
export * from "./metrics";
12+
export { default as formatGroupId } from "./group-id";

lambdas/supplier-allocator/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@
2626
"typecheck": "tsc --noEmit"
2727
},
2828
"version": "0.0.1"
29-
}
29+
}

lambdas/supplier-allocator/src/handler/__tests__/allocate-handler.test.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ function createPreparedV1Event(
6969
requestItemId: "requestItem1",
7070
requestItemPlanId: "requestItemPlan1",
7171
clientId: "client1",
72-
campaignId: "campaign1",
73-
templateId: "template1",
72+
campaignId: overrides.campaignId ?? "campaign1",
73+
templateId: overrides.templateId ?? "template1",
7474
url: overrides.url ?? "s3://letterDataBucket/letter1.pdf",
7575
sha256Hash:
7676
"3a7bd3e2360a3d29eea436fcfb7e44c735d117c8f2f1d2d1e4f6e8f7e6e8f7e6",
@@ -230,6 +230,40 @@ describe("createSupplierAllocatorHandler", () => {
230230
});
231231
});
232232

233+
test("parses SNS notification and sends message to SQS queue for v2 event without a campaignId and templateId", async () => {
234+
const preparedEvent = createPreparedV2Event({
235+
campaignId: "",
236+
templateId: "",
237+
});
238+
const evt: SQSEvent = createSQSEvent([
239+
createSqsRecord("msg1", JSON.stringify(preparedEvent)),
240+
]);
241+
242+
setupDefaultMocks();
243+
process.env.UPSERT_LETTERS_QUEUE_URL = "https://sqs.test.queue";
244+
245+
const handler = createSupplierAllocatorHandler(mockedDeps);
246+
const result = await handler(evt, {} as any, {} as any);
247+
248+
expect(result).toBeDefined();
249+
if (!result) throw new Error("expected BatchResponse, got void");
250+
251+
expect(result.batchItemFailures).toHaveLength(0);
252+
253+
expect(mockSqsClient.send).toHaveBeenCalledTimes(1);
254+
const sendCall = (mockSqsClient.send as jest.Mock).mock.calls[0][0];
255+
expect(sendCall).toBeInstanceOf(SendMessageCommand);
256+
257+
const messageBody = JSON.parse(sendCall.input.MessageBody);
258+
expect(messageBody.letterEvent).toEqual(preparedEvent);
259+
expect(messageBody.supplierSpec).toEqual({
260+
supplierId: "supplier1",
261+
specId: "spec1",
262+
priority: 1,
263+
billingId: "billing1",
264+
});
265+
});
266+
233267
test("parses SNS notification and sends message to SQS queue for v1 event", async () => {
234268
const preparedEvent = createPreparedV1Event();
235269

lambdas/supplier-allocator/src/handler/allocate-handler.ts

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ import {
1010
import { LetterRequestPreparedEventV2 } from "@nhsdigital/nhs-notify-event-schemas-letter-rendering";
1111
import z from "zod";
1212
import { Unit } from "aws-embedded-metrics";
13-
import { MetricEntry, MetricStatus, buildEMFObject } from "@internal/helpers";
13+
import {
14+
MetricEntry,
15+
MetricStatus,
16+
buildEMFObject,
17+
formatGroupId,
18+
} from "@internal/helpers";
1419
import {
1520
getSupplierAllocationsForVolumeGroup,
1621
getSupplierDetails,
@@ -144,6 +149,29 @@ function emitMetrics(
144149
}
145150
}
146151

152+
function emitDataMetrics(
153+
letterEvent: PreparedEvents,
154+
supplier: string,
155+
metricKey: string,
156+
deps: Deps,
157+
) {
158+
const namespace = "supplier-allocator";
159+
const { campaignId, clientId, templateId } = letterEvent.data;
160+
const dimensions: Record<string, string> = {
161+
Supplier: supplier,
162+
ClientId: clientId,
163+
CampaignId: campaignId || "unknown",
164+
TemplateId: templateId || "unknown",
165+
GroupId: formatGroupId(clientId, campaignId, templateId),
166+
};
167+
const metric: MetricEntry = {
168+
key: metricKey,
169+
value: 1,
170+
unit: Unit.Count,
171+
};
172+
deps.logger.info(buildEMFObject(namespace, dimensions, metric));
173+
}
174+
147175
export default function createSupplierAllocatorHandler(deps: Deps): SQSHandler {
148176
return async (event: SQSEvent) => {
149177
const batchItemFailures: SQSBatchItemFailure[] = [];
@@ -154,7 +182,9 @@ export default function createSupplierAllocatorHandler(deps: Deps): SQSHandler {
154182
let supplier = "unknown";
155183
let priority = "unknown";
156184
try {
157-
const letterEvent: unknown = JSON.parse(record.body);
185+
const letterEvent: PreparedEvents = JSON.parse(
186+
record.body,
187+
) as PreparedEvents;
158188

159189
deps.logger.info({
160190
description: "Extracted letter event",
@@ -163,8 +193,8 @@ export default function createSupplierAllocatorHandler(deps: Deps): SQSHandler {
163193

164194
validateType(letterEvent);
165195

166-
const supplierSpec = getSupplier(letterEvent as PreparedEvents, deps);
167-
await getSupplierFromConfig(letterEvent as PreparedEvents, deps);
196+
const supplierSpec = getSupplier(letterEvent, deps);
197+
await getSupplierFromConfig(letterEvent, deps);
168198

169199
supplier = supplierSpec.supplierId;
170200
priority = String(supplierSpec.priority);
@@ -199,6 +229,7 @@ export default function createSupplierAllocatorHandler(deps: Deps): SQSHandler {
199229
);
200230

201231
incrementMetric(perAllocationSuccess, supplier, priority);
232+
emitDataMetrics(letterEvent, supplier, "extra_data_dimensions", deps);
202233
} catch (error) {
203234
deps.logger.error({
204235
description: "Error processing allocation of record",

0 commit comments

Comments
 (0)