Skip to content

Commit a54c071

Browse files
committed
feat: logging via pino and logtail
1 parent 788a48b commit a54c071

File tree

4 files changed

+188
-9
lines changed

4 files changed

+188
-9
lines changed

web/netlify/functions/update-settings.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import { createClient } from "@supabase/supabase-js";
44
import { Database } from "../../src/types/supabase-notification";
55
import messages from "../../src/consts/eip712-messages";
66
import { EMAIL_REGEX, TELEGRAM_REGEX, ETH_ADDRESS_REGEX, ETH_SIGNATURE_REGEX } from "../../src/consts/index";
7+
import { createLogger, throwNewError } from "../../src/utils/logger";
8+
import dotenv from "dotenv";
9+
10+
dotenv.config();
711

812
type NotificationSettings = {
913
email?: string;
@@ -13,12 +17,15 @@ type NotificationSettings = {
1317
signature: string;
1418
};
1519

20+
const logger = createLogger(process.env.LOGTAIL_TOKEN).child({ function: "update-settings" });
21+
const logAndThrowNewError = (message: string, error?: any) => throwNewError(logger, message, error);
22+
1623
const parse = (inputString: string): NotificationSettings => {
1724
let input;
1825
try {
1926
input = JSON.parse(inputString);
2027
} catch (err) {
21-
throw new Error("Invalid JSON format");
28+
logAndThrowNewError("Invalid JSON format", err);
2229
}
2330

2431
const requiredKeys: (keyof NotificationSettings)[] = ["nonce", "address", "signature"];
@@ -27,37 +34,37 @@ const parse = (inputString: string): NotificationSettings => {
2734

2835
for (const key of requiredKeys) {
2936
if (!receivedKeys.includes(key)) {
30-
throw new Error(`Missing key: ${key}`);
37+
logAndThrowNewError(`Missing key: ${key}`);
3138
}
3239
}
3340

3441
const allExpectedKeys = [...requiredKeys, ...optionalKeys];
3542
for (const key of receivedKeys) {
3643
if (!allExpectedKeys.includes(key as keyof NotificationSettings)) {
37-
throw new Error(`Unexpected key: ${key}`);
44+
logAndThrowNewError(`Unexpected key: ${key}`);
3845
}
3946
}
4047

4148
const email = input.email ? input.email.trim() : "";
4249
if (email && !EMAIL_REGEX.test(email)) {
43-
throw new Error("Invalid email format");
50+
logAndThrowNewError("Invalid email format");
4451
}
4552

4653
const telegram = input.telegram ? input.telegram.trim() : "";
4754
if (telegram && !TELEGRAM_REGEX.test(telegram)) {
48-
throw new Error("Invalid Telegram username format");
55+
logAndThrowNewError("Invalid Telegram username format");
4956
}
5057

5158
if (!/^\d+$/.test(input.nonce)) {
52-
throw new Error("Invalid nonce format. Expected an integer as a string.");
59+
logAndThrowNewError("Invalid nonce format. Expected an integer as a string.");
5360
}
5461

5562
if (!ETH_ADDRESS_REGEX.test(input.address)) {
56-
throw new Error("Invalid Ethereum address format");
63+
logAndThrowNewError("Invalid Ethereum address format");
5764
}
5865

5966
if (!ETH_SIGNATURE_REGEX.test(input.signature)) {
60-
throw new Error("Invalid signature format");
67+
logAndThrowNewError("Invalid signature format");
6168
}
6269

6370
return {
@@ -72,7 +79,7 @@ const parse = (inputString: string): NotificationSettings => {
7279
export const handler: Handler = async (event) => {
7380
try {
7481
if (!event.body) {
75-
throw new Error("No body provided");
82+
logAndThrowNewError("No body provided");
7683
}
7784
const { email, telegram, nonce, address, signature } = parse(event.body);
7885
const lowerCaseAddress = address.toLowerCase() as `0x${string}`;
@@ -85,6 +92,7 @@ export const handler: Handler = async (event) => {
8592
});
8693
if (!isValid) {
8794
// If the recovered address does not match the provided address, return an error
95+
logAndThrowNewError("Signature verification failed");
8896
throw new Error("Signature verification failed");
8997
}
9098

@@ -94,6 +102,7 @@ export const handler: Handler = async (event) => {
94102
if (email === "" && telegram === "") {
95103
const { error } = await supabase.from("users").delete().match({ address: lowerCaseAddress });
96104
if (error) throw error;
105+
logger.info("Record deleted successfully.");
97106
return { statusCode: 200, body: JSON.stringify({ message: "Record deleted successfully." }) };
98107
}
99108

@@ -105,8 +114,12 @@ export const handler: Handler = async (event) => {
105114
if (error) {
106115
throw error;
107116
}
117+
logger.info("Record updated successfully.");
108118
return { statusCode: 200, body: JSON.stringify({ message: "Record updated successfully." }) };
109119
} catch (err) {
120+
logger.error(err);
110121
return { statusCode: 500, body: JSON.stringify({ message: `Error: ${err}` }) };
122+
} finally {
123+
logger.flush();
111124
}
112125
};

web/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
"@filebase/client": "^0.0.5",
7171
"@kleros/kleros-v2-contracts": "workspace:^",
7272
"@kleros/ui-components-library": "^2.6.2",
73+
"@logtail/pino": "^0.4.12",
7374
"@sentry/react": "^7.55.2",
7475
"@sentry/tracing": "^7.55.2",
7576
"@supabase/supabase-js": "^2.33.1",
@@ -87,6 +88,8 @@
8788
"moment": "^2.29.4",
8889
"overlayscrollbars": "^2.3.0",
8990
"overlayscrollbars-react": "^0.5.2",
91+
"pino": "^8.16.0",
92+
"pino-pretty": "^10.2.3",
9093
"react": "^18.2.0",
9194
"react-chartjs-2": "^4.3.1",
9295
"react-dom": "^18.2.0",

web/src/utils/logger.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import pino, { TransportTargetOptions } from "pino";
2+
3+
// Intended for Netlify functions
4+
export const createLogger = (logtailToken?: string): pino.Logger => {
5+
const targets: TransportTargetOptions[] = [
6+
{
7+
target: "pino-pretty",
8+
options: {},
9+
level: "info",
10+
},
11+
];
12+
if (logtailToken) {
13+
targets.push({
14+
target: "@logtail/pino",
15+
options: { sourceToken: logtailToken },
16+
level: "info",
17+
});
18+
}
19+
return pino(
20+
{
21+
level: "info",
22+
timestamp: pino.stdTimeFunctions.isoTime,
23+
},
24+
pino.transport({ targets: targets })
25+
);
26+
};
27+
28+
export const throwNewError = (logger: pino.Logger, message: string, error?: any) => {
29+
if (!error) {
30+
logger.error(message);
31+
throw new Error(message);
32+
}
33+
if (typeof error === "string") {
34+
logger.error(error, message);
35+
throw new Error(message + ": " + error);
36+
} else if (error instanceof Error) {
37+
logger.error(error, message);
38+
throw new Error(message + ": " + error.name + ": " + error.message);
39+
}
40+
};

yarn.lock

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5365,6 +5365,7 @@ __metadata:
53655365
"@kleros/kleros-v2-prettier-config": "workspace:^"
53665366
"@kleros/kleros-v2-tsconfig": "workspace:^"
53675367
"@kleros/ui-components-library": ^2.6.2
5368+
"@logtail/pino": ^0.4.12
53685369
"@netlify/functions": ^1.6.0
53695370
"@parcel/transformer-svg-react": 2.8.3
53705371
"@parcel/watcher": ~2.2.0
@@ -5401,6 +5402,8 @@ __metadata:
54015402
overlayscrollbars: ^2.3.0
54025403
overlayscrollbars-react: ^0.5.2
54035404
parcel: 2.8.3
5405+
pino: ^8.16.0
5406+
pino-pretty: ^10.2.3
54045407
react: ^18.2.0
54055408
react-chartjs-2: ^4.3.1
54065409
react-dom: ^18.2.0
@@ -5663,6 +5666,16 @@ __metadata:
56635666
languageName: node
56645667
linkType: hard
56655668

5669+
"@logtail/core@npm:^0.4.12":
5670+
version: 0.4.12
5671+
resolution: "@logtail/core@npm:0.4.12"
5672+
dependencies:
5673+
"@logtail/tools": ^0.4.12
5674+
"@logtail/types": ^0.4.11
5675+
checksum: 615874d456ed732d650d4a022bd14e2a400198b26dfd07cb512a365e8369a8ab1d48b74657c7bc1a77e03b430778f652d41c84638c3efe9de2ef91cfe6f4dd29
5676+
languageName: node
5677+
linkType: hard
5678+
56665679
"@logtail/node@npm:^0.4.0":
56675680
version: 0.4.0
56685681
resolution: "@logtail/node@npm:0.4.0"
@@ -5678,6 +5691,21 @@ __metadata:
56785691
languageName: node
56795692
linkType: hard
56805693

5694+
"@logtail/node@npm:^0.4.12":
5695+
version: 0.4.12
5696+
resolution: "@logtail/node@npm:0.4.12"
5697+
dependencies:
5698+
"@logtail/core": ^0.4.12
5699+
"@logtail/types": ^0.4.11
5700+
"@msgpack/msgpack": ^2.5.1
5701+
"@types/stack-trace": ^0.0.29
5702+
cross-fetch: ^3.0.4
5703+
minimatch: ^3.0.4
5704+
stack-trace: ^0.0.10
5705+
checksum: d2799eb561e4bdee4fb9875350983cb5f7ede2ab6c368bf3673cbcfdc7df3c16616d6b881edf60dfe64e0bafc6c6a63d96455bb0a4d34328ed3414fd94d47c5f
5706+
languageName: node
5707+
linkType: hard
5708+
56815709
"@logtail/pino@npm:^0.4.0":
56825710
version: 0.4.0
56835711
resolution: "@logtail/pino@npm:0.4.0"
@@ -5691,6 +5719,19 @@ __metadata:
56915719
languageName: node
56925720
linkType: hard
56935721

5722+
"@logtail/pino@npm:^0.4.12":
5723+
version: 0.4.12
5724+
resolution: "@logtail/pino@npm:0.4.12"
5725+
dependencies:
5726+
"@logtail/node": ^0.4.12
5727+
"@logtail/types": ^0.4.11
5728+
pino-abstract-transport: ^1.0.0
5729+
peerDependencies:
5730+
pino: ^7.0.0 || ^8.0.0
5731+
checksum: 1b6ee658ad5e60c65cc0bd50aaf1e99b26150e2b26622a13c09fcb4e15f33dd8979aa58401d06524d82a5ea19511c96871bbdb57aaa4166586dc76159b01110e
5732+
languageName: node
5733+
linkType: hard
5734+
56945735
"@logtail/tools@npm:^0.4.0":
56955736
version: 0.4.0
56965737
resolution: "@logtail/tools@npm:0.4.0"
@@ -5700,6 +5741,15 @@ __metadata:
57005741
languageName: node
57015742
linkType: hard
57025743

5744+
"@logtail/tools@npm:^0.4.12":
5745+
version: 0.4.12
5746+
resolution: "@logtail/tools@npm:0.4.12"
5747+
dependencies:
5748+
"@logtail/types": ^0.4.11
5749+
checksum: b0a8391a763b7f7f7d889446ed857715f158288f615b089f125471582efd8bb2a9525e37bb58f88f166224529ce3bc74799807ff768905e79ac1c92d5877aa1e
5750+
languageName: node
5751+
linkType: hard
5752+
57035753
"@logtail/types@npm:^0.4.0":
57045754
version: 0.4.0
57055755
resolution: "@logtail/types@npm:0.4.0"
@@ -5709,6 +5759,15 @@ __metadata:
57095759
languageName: node
57105760
linkType: hard
57115761

5762+
"@logtail/types@npm:^0.4.11":
5763+
version: 0.4.11
5764+
resolution: "@logtail/types@npm:0.4.11"
5765+
dependencies:
5766+
js: ^0.1.0
5767+
checksum: 0102a079d0ba89efc70770f6d853f0b205784a73abe570ab056f830d4ab031f95a1d80e2a3dfa54ebf53193d20fd9b61d52c2be03032d28572ce9fcb3be89144
5768+
languageName: node
5769+
linkType: hard
5770+
57125771
"@metamask/eth-sig-util@npm:^4.0.0":
57135772
version: 4.0.1
57145773
resolution: "@metamask/eth-sig-util@npm:4.0.1"
@@ -24731,6 +24790,16 @@ __metadata:
2473124790
languageName: node
2473224791
linkType: hard
2473324792

24793+
"pino-abstract-transport@npm:v1.1.0":
24794+
version: 1.1.0
24795+
resolution: "pino-abstract-transport@npm:1.1.0"
24796+
dependencies:
24797+
readable-stream: ^4.0.0
24798+
split2: ^4.0.0
24799+
checksum: cc84caabee5647b5753ae484d5f63a1bca0f6e1791845e2db2b6d830a561c2b5dd1177720f68d78994c8a93aecc69f2729e6ac2bc871a1bf5bb4b0ec17210668
24800+
languageName: node
24801+
linkType: hard
24802+
2473424803
"pino-pretty@npm:^10.0.0":
2473524804
version: 10.0.0
2473624805
resolution: "pino-pretty@npm:10.0.0"
@@ -24755,6 +24824,30 @@ __metadata:
2475524824
languageName: node
2475624825
linkType: hard
2475724826

24827+
"pino-pretty@npm:^10.2.3":
24828+
version: 10.2.3
24829+
resolution: "pino-pretty@npm:10.2.3"
24830+
dependencies:
24831+
colorette: ^2.0.7
24832+
dateformat: ^4.6.3
24833+
fast-copy: ^3.0.0
24834+
fast-safe-stringify: ^2.1.1
24835+
help-me: ^4.0.1
24836+
joycon: ^3.1.1
24837+
minimist: ^1.2.6
24838+
on-exit-leak-free: ^2.1.0
24839+
pino-abstract-transport: ^1.0.0
24840+
pump: ^3.0.0
24841+
readable-stream: ^4.0.0
24842+
secure-json-parse: ^2.4.0
24843+
sonic-boom: ^3.0.0
24844+
strip-json-comments: ^3.1.1
24845+
bin:
24846+
pino-pretty: bin.js
24847+
checksum: 9182886855515000df2ef381762c69fc29dbdd9014a76839cc3d8a7a94ac96d4ce17423adb9ddd61eae78986bb0ff3a1d9e6e7aa55476c096a3dd4a0c89440e8
24848+
languageName: node
24849+
linkType: hard
24850+
2475824851
"pino-std-serializers@npm:^4.0.0":
2475924852
version: 4.0.0
2476024853
resolution: "pino-std-serializers@npm:4.0.0"
@@ -24811,6 +24904,27 @@ __metadata:
2481124904
languageName: node
2481224905
linkType: hard
2481324906

24907+
"pino@npm:^8.16.0":
24908+
version: 8.16.0
24909+
resolution: "pino@npm:8.16.0"
24910+
dependencies:
24911+
atomic-sleep: ^1.0.0
24912+
fast-redact: ^3.1.1
24913+
on-exit-leak-free: ^2.1.0
24914+
pino-abstract-transport: v1.1.0
24915+
pino-std-serializers: ^6.0.0
24916+
process-warning: ^2.0.0
24917+
quick-format-unescaped: ^4.0.3
24918+
real-require: ^0.2.0
24919+
safe-stable-stringify: ^2.3.1
24920+
sonic-boom: ^3.7.0
24921+
thread-stream: ^2.0.0
24922+
bin:
24923+
pino: bin.js
24924+
checksum: c3af0d1d80d0a7ec59530e6c3668895ac813762829ea0b7e316057370f58011d09e128e67289665652904367a1f27f87cca4e564eb3ff2a0d46219f12fcf896e
24925+
languageName: node
24926+
linkType: hard
24927+
2481424928
"pirates@npm:^4.0.1, pirates@npm:^4.0.4":
2481524929
version: 4.0.6
2481624930
resolution: "pirates@npm:4.0.6"
@@ -28387,6 +28501,15 @@ __metadata:
2838728501
languageName: node
2838828502
linkType: hard
2838928503

28504+
"sonic-boom@npm:^3.7.0":
28505+
version: 3.7.0
28506+
resolution: "sonic-boom@npm:3.7.0"
28507+
dependencies:
28508+
atomic-sleep: ^1.0.0
28509+
checksum: 528f0f7f7e09dcdb02ad5985039f66554266cbd8813f9920781607c9248e01f468598c1334eab2cc740c016a63c8b2a20e15c3f618cddb08ea1cfb4a390a796e
28510+
languageName: node
28511+
linkType: hard
28512+
2839028513
"source-list-map@npm:^2.0.0, source-list-map@npm:^2.0.1":
2839128514
version: 2.0.1
2839228515
resolution: "source-list-map@npm:2.0.1"

0 commit comments

Comments
 (0)