feat(api): assign and echo request ids
This commit is contained in:
@@ -64,6 +64,7 @@ Deno.test('ApiServer serves health metrics and authenticated model listings', as
|
|||||||
assertEquals(healthResponse.status, 200);
|
assertEquals(healthResponse.status, 200);
|
||||||
assertEquals(healthBody.status, 'ok');
|
assertEquals(healthBody.status, 'ok');
|
||||||
assertEquals(healthBody.models, 1);
|
assertEquals(healthBody.models, 1);
|
||||||
|
assertEquals(typeof healthResponse.headers.get('x-request-id'), 'string');
|
||||||
|
|
||||||
const metricsResponse = await fetch(`http://127.0.0.1:${port}/metrics`);
|
const metricsResponse = await fetch(`http://127.0.0.1:${port}/metrics`);
|
||||||
const metricsBody = await metricsResponse.text();
|
const metricsBody = await metricsResponse.text();
|
||||||
@@ -79,12 +80,14 @@ Deno.test('ApiServer serves health metrics and authenticated model listings', as
|
|||||||
const authenticatedModels = await fetch(`http://127.0.0.1:${port}/v1/models`, {
|
const authenticatedModels = await fetch(`http://127.0.0.1:${port}/v1/models`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer valid-key',
|
Authorization: 'Bearer valid-key',
|
||||||
|
'X-Request-Id': 'req-test-models',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const authenticatedBody = await authenticatedModels.json();
|
const authenticatedBody = await authenticatedModels.json();
|
||||||
assertEquals(authenticatedModels.status, 200);
|
assertEquals(authenticatedModels.status, 200);
|
||||||
assertEquals(authenticatedBody.object, 'list');
|
assertEquals(authenticatedBody.object, 'list');
|
||||||
assertEquals(authenticatedBody.data[0].id, 'meta-llama/Llama-3.1-8B-Instruct');
|
assertEquals(authenticatedBody.data[0].id, 'meta-llama/Llama-3.1-8B-Instruct');
|
||||||
|
assertEquals(authenticatedModels.headers.get('x-request-id'), 'req-test-models');
|
||||||
|
|
||||||
const metricsAfterRequests = await fetch(`http://127.0.0.1:${port}/metrics`);
|
const metricsAfterRequests = await fetch(`http://127.0.0.1:${port}/metrics`);
|
||||||
const metricsAfterRequestsBody = await metricsAfterRequests.text();
|
const metricsAfterRequestsBody = await metricsAfterRequests.text();
|
||||||
|
|||||||
+16
-1
@@ -123,6 +123,7 @@ export class ApiServer {
|
|||||||
res: http.ServerResponse,
|
res: http.ServerResponse,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
const requestId = this.ensureRequestId(req, res);
|
||||||
|
|
||||||
// Set CORS headers if enabled
|
// Set CORS headers if enabled
|
||||||
if (this.config.cors) {
|
if (this.config.cors) {
|
||||||
@@ -177,7 +178,7 @@ export class ApiServer {
|
|||||||
// Log request
|
// Log request
|
||||||
const duration = Date.now() - startTime;
|
const duration = Date.now() - startTime;
|
||||||
this.recordRequest(path, res.statusCode);
|
this.recordRequest(path, res.statusCode);
|
||||||
logger.dim(`${req.method} ${path} - ${res.statusCode} (${duration}ms)`);
|
logger.dim(`[${requestId}] ${req.method} ${path} - ${res.statusCode} (${duration}ms)`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -405,6 +406,20 @@ export class ApiServer {
|
|||||||
metric.set(path, (metric.get(path) || 0) + 1);
|
metric.set(path, (metric.get(path) || 0) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ensureRequestId(req: http.IncomingMessage, res: http.ServerResponse): string {
|
||||||
|
const existing = typeof req.headers['x-request-id'] === 'string'
|
||||||
|
? req.headers['x-request-id']
|
||||||
|
: undefined;
|
||||||
|
const requestId = existing || this.generateRequestId();
|
||||||
|
req.headers['x-request-id'] = requestId;
|
||||||
|
res.setHeader('X-Request-Id', requestId);
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateRequestId(): string {
|
||||||
|
return `req-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
||||||
|
}
|
||||||
|
|
||||||
private escapeMetricLabel(value: string): string {
|
private escapeMetricLabel(value: string): string {
|
||||||
return value.replaceAll('\\', '\\\\').replaceAll('"', '\\"');
|
return value.replaceAll('\\', '\\\\').replaceAll('"', '\\"');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user