Skip to content

Commit fb9e45c

Browse files
committed
feat: finish transition to s3
1 parent 09953a7 commit fb9e45c

File tree

15 files changed

+231
-217
lines changed

15 files changed

+231
-217
lines changed

packages/api/serverless.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ custom:
2222
endpointType: regional
2323
apiType: http
2424
logRetentionInDays: 14
25-
bucketName: ${self:service}-storage-${sls:stage} # TODO: make this a unique name
25+
bucketName: ${self:service}-traces-${sls:stage}${param:TRACER_TOKEN}
2626

2727
package:
2828
individually: true
@@ -120,7 +120,7 @@ functions:
120120
events:
121121
- sqs:
122122
arn: !GetAtt Queue.Arn
123-
batchSize: 100
123+
batchSize: 300
124124
maximumBatchingWindow: 30
125125

126126
main:

packages/api/src/events/collector.js

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,50 +33,35 @@ export const handler = async ({ Records }) => {
3333
}
3434

3535
// Check transactions cache to see if there's any transactions we can flush
36+
const hourlyStats = [];
3637
for (const [transactionId, spans] of Object.entries(transactionCache)) {
3738
const invocationEndedSpan = spans.find(
3839
(span) =>
3940
span.type === "function" && span.ended && !span.id.includes("_started"),
4041
);
4142

4243
if (!invocationEndedSpan) {
43-
console.log(
44-
`No invocation ended span found for transaction ${spans[0].transactionId}`,
45-
);
46-
4744
// TODO: if we are close to running out of time, we should flush the transaction cache anyway
48-
4945
continue;
50-
} else {
51-
console.log(
52-
"Flushing transaction cache for",
53-
invocationEndedSpan.transactionId,
54-
);
5546
}
5647

5748
// save function invocation details
5849
await saveInvocation(invocationEndedSpan, spans);
5950

60-
// const duration = invocationEndedSpan.ended - invocationEndedSpan.started;
61-
await saveHourlyStat(
51+
const duration = invocationEndedSpan.ended - invocationEndedSpan.started;
52+
hourlyStats.push(["global", "invocations", 1, "sum"]);
53+
hourlyStats.push([
6254
invocationEndedSpan.region,
6355
invocationEndedSpan.name + ".invocations",
6456
1,
65-
);
66-
// await saveHourlyStat(
67-
// invocationEndedSpan.region,
68-
// invocationEndedSpan.name + ".duration",
69-
// duration,
70-
// );
71-
await saveHourlyStat("global", "invocations", 1);
72-
if (invocationEndedSpan.error) {
73-
await saveHourlyStat(
74-
invocationEndedSpan.region,
75-
invocationEndedSpan.name + ".errors",
76-
1,
77-
);
78-
await saveHourlyStat("global", "errors", 1);
79-
}
57+
"sum",
58+
]);
59+
hourlyStats.push([
60+
invocationEndedSpan.region,
61+
invocationEndedSpan.name + ".duration",
62+
duration,
63+
"avg",
64+
]);
8065

8166
// save error
8267
if (invocationEndedSpan.error) {
@@ -98,14 +83,45 @@ export const handler = async ({ Records }) => {
9883
region: invocationEndedSpan.region,
9984
},
10085
);
101-
await saveHourlyStat(
86+
87+
hourlyStats.push([
88+
invocationEndedSpan.region,
89+
invocationEndedSpan.name + ".errors",
90+
1,
91+
"sum",
92+
]);
93+
94+
hourlyStats.push(["global", "errors", 1, "sum"]);
95+
hourlyStats.push([
10296
invocationEndedSpan.region,
10397
invocationEndedSpan.name + ".error." + errorKey,
10498
1,
105-
);
99+
"sum",
100+
]);
106101
}
107102

108103
// Delete the transaction from the cache
109104
delete transactionCache[transactionId];
110105
}
106+
107+
// Save hourly stats
108+
const statsToSave = hourlyStats.reduce((acc, [region, name, value, type]) => {
109+
const key = `${region}#${name}`;
110+
if (!acc[key]) {
111+
acc[key] = [region, name, value, 0];
112+
} else if (type === "sum") {
113+
acc[key][2] += value;
114+
} else if (type === "avg") {
115+
acc[key][2] += value;
116+
acc[key][3] += 1;
117+
}
118+
return acc;
119+
}, []);
120+
for (const [region, name, value, count] of statsToSave) {
121+
await saveHourlyStat({
122+
region,
123+
name,
124+
value: count > 0 ? value / count : value,
125+
});
126+
}
111127
};

packages/api/src/lib/spans.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const getGroupingKey = (span, extended = false) => {
22
const items = [
3-
span.spanType,
3+
span.type,
44
span.service,
55

66
span.info?.resourceName,

packages/api/src/lib/spans.test.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const traces = [
44
{
55
service: "dynamodb",
66
ended: 1726249792234,
7-
spanType: "http",
7+
type: "http",
88
started: 1726249792231,
99
id: "ba2eec85-d01a-9b91-4a2f-44508e0407cc",
1010
reporterAwsRequestId: "1c065edb-2a94-4a07-9f1b-e31014df95ac",
@@ -37,7 +37,7 @@ const traces = [
3737
{
3838
service: "dynamodb",
3939
ended: 1726249792239,
40-
spanType: "http",
40+
type: "http",
4141
started: 1726249792236,
4242
id: "46d07ca2-adcb-0061-74aa-b9c8ea79196e",
4343
reporterAwsRequestId: "1c065edb-2a94-4a07-9f1b-e31014df95ac",
@@ -70,7 +70,7 @@ const traces = [
7070
{
7171
service: "dynamodb",
7272
ended: 1726249792244,
73-
spanType: "http",
73+
type: "http",
7474
started: 1726249792240,
7575
id: "ed4d0e6e-a004-265f-c6bb-1e9c21e3b3d0",
7676
reporterAwsRequestId: "1c065edb-2a94-4a07-9f1b-e31014df95ac",
@@ -103,7 +103,7 @@ const traces = [
103103
{
104104
service: "dynamodb",
105105
ended: 1726249792249,
106-
spanType: "http",
106+
type: "http",
107107
started: 1726249792246,
108108
id: "97210e79-03dc-2a30-8479-af7db8ba5f15",
109109
reporterAwsRequestId: "1c065edb-2a94-4a07-9f1b-e31014df95ac",
@@ -144,7 +144,7 @@ const traces2 = [
144144
name: "thumbnails-tokens-production-usage--report",
145145
ended: 1726304700362,
146146
envs: '{"AWS_LAMBDA_FUNCTION_VERSION":"$LATEST","TRACER_ORIGINAL_HANDLER":"src/functions/usage/report/handler.handler","REPORTS_BUCKET":"thumbnails-tokens-production-reports","AWS_SESSION_TOKEN":"IQoJb3JpZ2luX2VjEKn//////////wEaCWV1LXdlc3QtMSJGMEQCIF+ibaB9vrPCvEriTOXk2m6w62wbUcYucW0zE6VzXeFNAiBB7hYqK4ci/WlY6uxgI1+vFyMRed0OuFHBHbr7OoNXWCqyAwjS//////////8BEAMaDDY3Mjg5NTAyNzQxMyIMBN+KMPccXfO8bTSvKoYD4WalkWegJA8Kp6DBvM/xkNyhHfmCx331sVO2p9kXTPiS/XFcGerMpBmjh/Mqvh/BhQVCKylER37QPa1/LtCfjDPvQNHPOhQFL27XvaOSk3/qjfcXnuEeYxtnQz+HVUcGR98bU67Rh496R6/nODfjy5uZBqzgr9gIOX1VeNWnVhYVmZL2NszvkzuUDbBh2mQmAGDkHoZcc8dHq+/AZEKRsdBKin9rftOwL6asATAOUIUTPS+yFmvYrsRTxaOSMCz0g8JZT17pPkN9+e1BUYHsKAa78t+vV3D6bMOOJumwD2HsdTNT/KWA64Jcm81CyxbL8EWbvj6kFzpbhJySsSMVFwFzMN0D231xftsW2jMArsP87EtCfyn6AvLPnZ8bG3yzDHldGQZOmO0UqYea6OZr0IMmZZpqUvShuTnDUChLQvvIuyxHxBvmpsegUzb7H5/SdhziWWUmak7ysY37ra4/65DPNz4y129iJQRyXo2y+YFkkpGJsUakcT/z57bTzJc9MIJHvlk2MJChlbcGOp4BiyIow2gkPoH85+KS9o1p/OgP0vOHRr51zDx5Ru52s3CpjHjk/NDH79amegKwRrilnyK5rFk6MmCo0pQf2tbmPmGlaNWgMnb1XCZ1LyeEwA80mon1SE7EHAtlYS9mqnAiuIzFPFIhhBmRNZ/o7IDihnnd/GKbNHdyPP35XnCbAgsigf7cvg5QDD00RY+qZsoJfKi19VYYYHdwPwDBa5o=","LAMBDA_TASK_ROOT":"/var/task","AWS_LAMBDA_LOG_GROUP_NAME":"/aws/lambda/thumbnails-tokens-production-usage--report","LD_LIBRARY_PATH":"/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib","AWS_LAMBDA_LOG_STREAM_NAME":"2024/09/14/[$LATEST]607ff0a879de44ecbc3da9de116c9da0","AWS_LAMBDA_RUNTIME_API":"127.0.0.1:9001","AWS_EXECUTION_ENV":"AWS_Lambda_nodejs16.x","AWS_XRAY_DAEMON_ADDRESS":"169.254.79.129:2000","AWS_LAMBDA_FUNCTION_NAME":"thumbnails-tokens-production-usage--report","PATH":"/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin","TABLE_NAME":"thumbnails-tokens-production","AWS_DEFAULT_REGION":"eu-west-1","SERVICE":"thumbnails-tokens","PWD":"/var/task","AWS_SECRET_ACCESS_KEY":"****","LAMBDA_RUNTIME_DIR":"/var/runtime","LANG":"en_US.UTF-8","AWS_LAMBDA_INITIALIZATION_TYPE":"on-demand","AWS_REGION":"eu-west-1","TZ":":UTC","NODE_PATH":"/opt/nodejs/node16/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules:/var/runtime:/var/task"}...[too long]',
147-
spanType: "function",
147+
type: "function",
148148
started: 1726304700096,
149149
id: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",
150150
event:
@@ -171,7 +171,7 @@ const traces2 = [
171171
instances: 1,
172172
service: "dynamodb",
173173
ended: 1726304700148,
174-
spanType: "http",
174+
type: "http",
175175
started: 1726304700102,
176176
id: "1480dcfa-5f14-639b-cf58-4b3c8b43123e",
177177
reporterAwsRequestId: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",
@@ -211,7 +211,7 @@ const traces2 = [
211211
instances: 1,
212212
service: "dynamodb",
213213
ended: 1726304700170,
214-
spanType: "http",
214+
type: "http",
215215
started: 1726304700151,
216216
id: "96984001-1f79-3297-75c8-822a85efcd5c",
217217
reporterAwsRequestId: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",
@@ -251,7 +251,7 @@ const traces2 = [
251251
instances: 1,
252252
service: "dynamodb",
253253
ended: 1726304700192,
254-
spanType: "http",
254+
type: "http",
255255
started: 1726304700172,
256256
id: "bd2d2343-3b92-1013-52e2-738d9f44f7de",
257257
reporterAwsRequestId: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",
@@ -291,7 +291,7 @@ const traces2 = [
291291
instances: 1,
292292
service: "dynamodb",
293293
ended: 1726304700212,
294-
spanType: "http",
294+
type: "http",
295295
started: 1726304700194,
296296
id: "6b355f3f-cecd-6e42-56cf-e1d7d6be0a2d",
297297
reporterAwsRequestId: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",
@@ -331,7 +331,7 @@ const traces2 = [
331331
instances: 1,
332332
service: "dynamodb",
333333
ended: 1726304700234,
334-
spanType: "http",
334+
type: "http",
335335
started: 1726304700216,
336336
id: "5dba5c19-eddf-e7fe-4ab9-de380db43710",
337337
reporterAwsRequestId: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",
@@ -371,7 +371,7 @@ const traces2 = [
371371
instances: 1,
372372
service: "dynamodb",
373373
ended: 1726304700254,
374-
spanType: "http",
374+
type: "http",
375375
started: 1726304700236,
376376
id: "323cafc2-9788-49f7-ba40-0b16df8e3e3e",
377377
reporterAwsRequestId: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",
@@ -411,7 +411,7 @@ const traces2 = [
411411
instances: 1,
412412
service: "dynamodb",
413413
ended: 1726304700276,
414-
spanType: "http",
414+
type: "http",
415415
started: 1726304700257,
416416
id: "08408ef2-0364-f8f1-9ac5-05839bbcc565",
417417
reporterAwsRequestId: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",
@@ -451,7 +451,7 @@ const traces2 = [
451451
instances: 1,
452452
service: "dynamodb",
453453
ended: 1726304700300,
454-
spanType: "http",
454+
type: "http",
455455
started: 1726304700278,
456456
id: "3edfc450-ccbf-642d-e795-0219dcd7efad",
457457
reporterAwsRequestId: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",
@@ -491,7 +491,7 @@ const traces2 = [
491491
instances: 1,
492492
service: "dynamodb",
493493
ended: 1726304700320,
494-
spanType: "http",
494+
type: "http",
495495
started: 1726304700302,
496496
id: "0e31cde8-18a7-f93d-f2cd-1a8237d0447c",
497497
reporterAwsRequestId: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",
@@ -531,7 +531,7 @@ const traces2 = [
531531
instances: 1,
532532
service: "dynamodb",
533533
ended: 1726304700339,
534-
spanType: "http",
534+
type: "http",
535535
started: 1726304700322,
536536
id: "04f4c32d-3867-eb14-c388-09354caab4d0",
537537
reporterAwsRequestId: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",
@@ -571,7 +571,7 @@ const traces2 = [
571571
instances: 1,
572572
service: "dynamodb",
573573
ended: 1726304700361,
574-
spanType: "http",
574+
type: "http",
575575
started: 1726304700341,
576576
id: "a46580cc-7b7c-6ffc-3f0d-b868661c49cc",
577577
reporterAwsRequestId: "9fd58ff6-dfae-4176-b4bd-d0ca0ca1b0e7",

packages/api/src/lib/storage.js

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
1+
import {
2+
GetObjectCommand,
3+
ListObjectsV2Command,
4+
PutObjectCommand,
5+
S3Client,
6+
} from "@aws-sdk/client-s3";
27

38
const s3 = new S3Client();
49

@@ -17,3 +22,61 @@ export const store = async (key, data) => {
1722

1823
return s3.send(new PutObjectCommand(params));
1924
};
25+
26+
export const listByPrefix = async (prefix) => {
27+
const output = [];
28+
let pageToken = undefined;
29+
30+
do {
31+
const params = {
32+
Bucket: process.env.STORAGE_BUCKET_NAME,
33+
Prefix: prefix,
34+
ContinuationToken: pageToken,
35+
};
36+
37+
const command = new ListObjectsV2Command(params);
38+
const { Contents, NextContinuationToken } = await s3.send(command);
39+
40+
output.push(...(Contents?.map((item) => item.Key) || []));
41+
pageToken = NextContinuationToken;
42+
} while (pageToken && output.length < 10000);
43+
44+
return output;
45+
};
46+
47+
export const list = async (startDate, endDate, prefix) => {
48+
// Get a list of all days between startDate and endDate
49+
const start = new Date(startDate);
50+
const end = new Date(endDate);
51+
const dateList = [];
52+
const currentDate = new Date(start);
53+
while (currentDate <= end) {
54+
dateList.push(currentDate.toISOString().split("T")[0]);
55+
currentDate.setDate(currentDate.getDate() + 1);
56+
}
57+
58+
// Get all keys for each date, and flatten the array
59+
const allKeys = await Promise.all(
60+
dateList.map((date) => listByPrefix(`${date}/${prefix}`)),
61+
);
62+
63+
return allKeys.flat();
64+
};
65+
66+
export const get = async (key) => {
67+
const params = {
68+
Bucket: process.env.STORAGE_BUCKET_NAME,
69+
Key: key,
70+
};
71+
72+
const { Body } = await s3.send(new GetObjectCommand(params));
73+
const string = await Body?.transformToString();
74+
return string && JSON.parse(string);
75+
};
76+
77+
export const listAndRead = async (startDate, endDate, prefix) => {
78+
const keys = await list(startDate, endDate, prefix);
79+
const data = await Promise.all(keys.map(async (key) => get(key)));
80+
81+
return data;
82+
};

0 commit comments

Comments
 (0)