Skip to content

Commit 807e00d

Browse files
authored
feat(servers): add logging for create, delete, and list server requests (#300)
1 parent 6987ae5 commit 807e00d

3 files changed

Lines changed: 108 additions & 1 deletion

File tree

packages/entrypoints/src/http/routes/servers/createServer.ts

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Request, Response } from 'express';
22
import { BackgroundTaskQueue, Region, Variant } from '@tf2qs/core';
33
import { CreateServerForClientTaskData } from '@tf2qs/providers';
4+
import { logger } from '@tf2qs/telemetry';
45

56
export function createCreateServerHandler(backgroundTaskQueue: BackgroundTaskQueue) {
67
/**
@@ -37,6 +38,11 @@ export function createCreateServerHandler(backgroundTaskQueue: BackgroundTaskQue
3738
return async (req: Request, res: Response): Promise<void> => {
3839
const clientId = req.auth?.payload.azp || req.auth?.payload.sub;
3940
if (!clientId) {
41+
logger.emit({
42+
severityText: 'WARN',
43+
body: 'Create server request with no client ID in token',
44+
attributes: { path: req.path, method: req.method },
45+
});
4046
res.status(401).json({ error: 'Unauthorized', message: 'No client ID found in token' });
4147
return;
4248
}
@@ -48,32 +54,74 @@ export function createCreateServerHandler(backgroundTaskQueue: BackgroundTaskQue
4854
firstMap?: unknown;
4955
};
5056

57+
logger.emit({
58+
severityText: 'INFO',
59+
body: 'Create server request received',
60+
attributes: {
61+
clientId: clientId as string,
62+
region: region as string,
63+
variantName: variantName as string,
64+
firstMap: firstMap as string | undefined,
65+
hasExtraEnvs: String(extraEnvs !== undefined),
66+
},
67+
});
68+
5169
if (!region || typeof region !== 'string') {
70+
logger.emit({
71+
severityText: 'WARN',
72+
body: 'Create server validation failed: invalid region',
73+
attributes: { clientId: String(clientId), region: String(region), reason: 'not a string or missing' },
74+
});
5275
res.status(400).json({ error: 'Bad Request', message: 'region is required and must be a string' });
5376
return;
5477
}
5578
if (!Object.values(Region).includes(region as Region)) {
79+
logger.emit({
80+
severityText: 'WARN',
81+
body: 'Create server validation failed: unknown region',
82+
attributes: { clientId: String(clientId), region: String(region), reason: 'not a valid Region enum value' },
83+
});
5684
res.status(400).json({ error: 'Bad Request', message: 'region is not a valid region' });
5785
return;
5886
}
5987
if (!variantName || typeof variantName !== 'string') {
88+
logger.emit({
89+
severityText: 'WARN',
90+
body: 'Create server validation failed: invalid variantName',
91+
attributes: { clientId: String(clientId), region: String(region), variantName: String(variantName), reason: 'not a string or missing' },
92+
});
6093
res.status(400).json({ error: 'Bad Request', message: 'variantName is required and must be a string' });
6194
return;
6295
}
6396
if (firstMap !== undefined && (typeof firstMap !== 'string' || !/^\w+$/.test(firstMap))) {
97+
logger.emit({
98+
severityText: 'WARN',
99+
body: 'Create server validation failed: invalid map',
100+
attributes: { clientId: String(clientId), region: String(region), variantName: String(variantName), firstMap: String(firstMap), reason: 'map name contains invalid characters' },
101+
});
64102
res.status(400).json({ error: 'Bad Request', message: 'Invalid map' });
65103
return;
66104
}
67105

68106
let sanitizedExtraEnvs: Record<string, string> | undefined;
69107
if (extraEnvs !== undefined) {
70108
if (typeof extraEnvs !== 'object' || Array.isArray(extraEnvs) || extraEnvs === null) {
109+
logger.emit({
110+
severityText: 'WARN',
111+
body: 'Create server validation failed: invalid extraEnvs type',
112+
attributes: { clientId: String(clientId), region: String(region), variantName: String(variantName), reason: 'not a key-value object' },
113+
});
71114
res.status(400).json({ error: 'Bad Request', message: 'extraEnvs must be a key-value object if provided' });
72115
return;
73116
}
74117
const result: Record<string, string> = {};
75118
for (const [key, value] of Object.entries(extraEnvs as Record<string, unknown>)) {
76119
if (typeof value !== 'string') {
120+
logger.emit({
121+
severityText: 'WARN',
122+
body: 'Create server validation failed: extraEnvs non-string value',
123+
attributes: { clientId: String(clientId), region: String(region), variantName: String(variantName), extraEnvKey: key },
124+
});
77125
res.status(400).json({ error: 'Bad Request', message: 'extraEnvs values must be strings' });
78126
return;
79127
}
@@ -87,11 +135,23 @@ export function createCreateServerHandler(backgroundTaskQueue: BackgroundTaskQue
87135
variantName: variantName as Variant,
88136
clientId: clientId as string,
89137
extraEnvs: sanitizedExtraEnvs,
90-
firstMap:firstMap as string | undefined,
138+
firstMap: firstMap as string | undefined,
91139
};
92140

93141
const taskId = await backgroundTaskQueue.enqueue('create-server-for-client', taskData, undefined, undefined, { ownerId: clientId as string });
94142

143+
logger.emit({
144+
severityText: 'INFO',
145+
body: 'Create server task enqueued',
146+
attributes: {
147+
clientId: clientId as string,
148+
region: region as string,
149+
variantName: variantName as string,
150+
taskId,
151+
firstMap: firstMap as string | undefined,
152+
},
153+
});
154+
95155
res.status(202).json({ taskId });
96156
};
97157
}

packages/entrypoints/src/http/routes/servers/deleteServer.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Request, Response } from 'express';
22
import { BackgroundTaskQueue, ServerRepository } from '@tf2qs/core';
3+
import { logger } from '@tf2qs/telemetry';
34

45
export function createDeleteServerHandler(backgroundTaskQueue: BackgroundTaskQueue, serverRepository: ServerRepository) {
56
/**
@@ -39,25 +40,52 @@ export function createDeleteServerHandler(backgroundTaskQueue: BackgroundTaskQue
3940
return async (req: Request, res: Response): Promise<void> => {
4041
const clientId = req.auth?.payload.azp || req.auth?.payload.sub;
4142
if (!clientId) {
43+
logger.emit({
44+
severityText: 'WARN',
45+
body: 'Delete server request with no client ID in token',
46+
attributes: { path: req.path, method: req.method },
47+
});
4248
res.status(401).json({ error: 'Unauthorized', message: 'No client ID found in token' });
4349
return;
4450
}
4551

4652
const { serverId } = req.params;
4753

54+
logger.emit({
55+
severityText: 'INFO',
56+
body: 'Delete server request received',
57+
attributes: { clientId: clientId as string, serverId },
58+
});
59+
4860
const server = await serverRepository.findById(serverId);
4961
if (!server) {
62+
logger.emit({
63+
severityText: 'WARN',
64+
body: 'Delete server failed: server not found',
65+
attributes: { clientId: clientId as string, serverId },
66+
});
5067
res.status(404).json({ error: 'Not Found', message: `Server ${serverId} not found` });
5168
return;
5269
}
5370

5471
if (server.createdBy !== clientId) {
72+
logger.emit({
73+
severityText: 'WARN',
74+
body: 'Delete server forbidden: client does not own server',
75+
attributes: { clientId: clientId as string, serverId, serverOwner: server.createdBy },
76+
});
5577
res.status(403).json({ error: 'Forbidden', message: 'You do not have permission to delete this server' });
5678
return;
5779
}
5880

5981
const taskId = await backgroundTaskQueue.enqueue('delete-server', { serverId }, undefined, undefined, { ownerId: clientId as string });
6082

83+
logger.emit({
84+
severityText: 'INFO',
85+
body: 'Delete server task enqueued',
86+
attributes: { clientId: clientId as string, serverId, taskId, region: server.region },
87+
});
88+
6189
res.status(202).json({ taskId });
6290
};
6391
}

packages/entrypoints/src/http/routes/servers/listServers.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Request, Response } from 'express';
22
import { GetUserServers } from '@tf2qs/core';
3+
import { logger } from '@tf2qs/telemetry';
34

45
export function createListServersHandler(getUserServers: GetUserServers) {
56
/**
@@ -27,11 +28,29 @@ export function createListServersHandler(getUserServers: GetUserServers) {
2728
return async (req: Request, res: Response): Promise<void> => {
2829
const clientId = req.auth?.payload.azp || req.auth?.payload.sub;
2930
if (!clientId) {
31+
logger.emit({
32+
severityText: 'WARN',
33+
body: 'List servers request with no client ID in token',
34+
attributes: { path: req.path, method: req.method },
35+
});
3036
res.status(401).json({ error: 'Unauthorized', message: 'No client ID found in token' });
3137
return;
3238
}
3339

40+
logger.emit({
41+
severityText: 'INFO',
42+
body: 'List servers request received',
43+
attributes: { clientId: clientId as string },
44+
});
45+
3446
const servers = await getUserServers.execute({ userId: clientId as string });
47+
48+
logger.emit({
49+
severityText: 'INFO',
50+
body: 'List servers response',
51+
attributes: { clientId: clientId as string, serverCount: servers.length },
52+
});
53+
3554
res.json(servers);
3655
};
3756
}

0 commit comments

Comments
 (0)