chore(platform): replace runtime console diagnostics
What changed: - Replaced platform-service runtime console diagnostics with structured stderr logging helpers. - Preserved push notification, AI diagnostics, auto-trigger, and diagnostics repository error handling semantics. Warning impact: - Platform runtime no-console warnings: 12 -> 0. - Workspace lint: 12 -> 0 warnings. Verification: - pnpm --filter @lysnrai/platform-service build - pnpm --filter @lysnrai/platform-service test - pnpm --filter @lysnrai/platform-service exec eslint <runtime files> --ext .ts - pnpm lint
This commit is contained in:
parent
2c9dc1870d
commit
663dcdecab
@ -32,6 +32,22 @@ interface PushPayload {
|
|||||||
badge?: number;
|
badge?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function logPushWarning(message: string, extra?: Record<string, unknown>): void {
|
||||||
|
process.stderr.write(JSON.stringify({ level: 'warn', module: 'push', message, ...extra }) + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logPushError(message: string, error: unknown, extra?: Record<string, unknown>): void {
|
||||||
|
process.stderr.write(
|
||||||
|
JSON.stringify({
|
||||||
|
level: 'error',
|
||||||
|
module: 'push',
|
||||||
|
message,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
...extra,
|
||||||
|
}) + '\n'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store or update device token for push notifications
|
* Store or update device token for push notifications
|
||||||
*/
|
*/
|
||||||
@ -130,7 +146,7 @@ export async function sendFCM(
|
|||||||
// Get FCM server key from environment
|
// Get FCM server key from environment
|
||||||
const fcmKey = process.env.FCM_SERVER_KEY;
|
const fcmKey = process.env.FCM_SERVER_KEY;
|
||||||
if (!fcmKey) {
|
if (!fcmKey) {
|
||||||
console.warn('[Push] FCM_SERVER_KEY not configured');
|
logPushWarning('FCM_SERVER_KEY not configured');
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,11 +180,11 @@ export async function sendFCM(
|
|||||||
results.success.push(token);
|
results.success.push(token);
|
||||||
} else {
|
} else {
|
||||||
const error = await response.text();
|
const error = await response.text();
|
||||||
console.error(`[Push] FCM failed for token ${token.substring(0, 16)}...:`, error);
|
logPushError('FCM send failed', error, { tokenPrefix: token.substring(0, 16) });
|
||||||
results.failed.push(token);
|
results.failed.push(token);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[Push] FCM error for token ${token.substring(0, 16)}...:`, err);
|
logPushError('FCM send error', err, { tokenPrefix: token.substring(0, 16) });
|
||||||
results.failed.push(token);
|
results.failed.push(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,7 +210,7 @@ export async function sendAPNS(
|
|||||||
const apnsPrivateKey = process.env.APNS_PRIVATE_KEY;
|
const apnsPrivateKey = process.env.APNS_PRIVATE_KEY;
|
||||||
|
|
||||||
if (!apnsKeyId || !apnsTeamId || !apnsBundleId || !apnsPrivateKey) {
|
if (!apnsKeyId || !apnsTeamId || !apnsBundleId || !apnsPrivateKey) {
|
||||||
console.warn('[Push] APNS credentials not fully configured');
|
logPushWarning('APNS credentials not fully configured');
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +257,10 @@ export async function sendAPNS(
|
|||||||
results.success.push(token);
|
results.success.push(token);
|
||||||
} else {
|
} else {
|
||||||
const error = await response.text();
|
const error = await response.text();
|
||||||
console.error(`[Push] APNS failed for token ${token.substring(0, 16)}...:`, error);
|
logPushError('APNS send failed', error, {
|
||||||
|
status: response.status,
|
||||||
|
tokenPrefix: token.substring(0, 16),
|
||||||
|
});
|
||||||
results.failed.push(token);
|
results.failed.push(token);
|
||||||
|
|
||||||
// Handle invalid token (410 Gone)
|
// Handle invalid token (410 Gone)
|
||||||
@ -250,7 +269,7 @@ export async function sendAPNS(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[Push] APNS error for token ${token.substring(0, 16)}...:`, err);
|
logPushError('APNS send error', err, { tokenPrefix: token.substring(0, 16) });
|
||||||
results.failed.push(token);
|
results.failed.push(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import { config } from '../../lib/config.js';
|
import { config } from '../../lib/config.js';
|
||||||
import type { FastifyBaseLogger } from 'fastify';
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Azure OpenAI Embedding Client
|
// Azure OpenAI Embedding Client
|
||||||
@ -11,6 +10,17 @@ const EMBEDDING_DIMENSIONS = 1536;
|
|||||||
const MAX_BATCH_SIZE = 100; // Azure OpenAI limit
|
const MAX_BATCH_SIZE = 100; // Azure OpenAI limit
|
||||||
const MAX_TOKENS_PER_REQUEST = 8192;
|
const MAX_TOKENS_PER_REQUEST = 8192;
|
||||||
|
|
||||||
|
function logEmbeddingError(message: string, error: unknown): void {
|
||||||
|
process.stderr.write(
|
||||||
|
JSON.stringify({
|
||||||
|
level: 'error',
|
||||||
|
module: 'ai-diagnostics.embeddings',
|
||||||
|
message,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
}) + '\n'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
interface EmbeddingResponse {
|
interface EmbeddingResponse {
|
||||||
object: 'list';
|
object: 'list';
|
||||||
data: Array<{
|
data: Array<{
|
||||||
@ -93,7 +103,7 @@ export async function generateEmbedding(
|
|||||||
model: data.model,
|
model: data.model,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to generate embedding:', error);
|
logEmbeddingError('Failed to generate embedding', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +184,7 @@ export async function generateEmbeddingsBatch(
|
|||||||
await new Promise(resolve => setTimeout(resolve, 100));
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to generate batch embeddings:', error);
|
logEmbeddingError('Failed to generate batch embeddings', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,17 @@ interface RootCauseAnalysisPrompt {
|
|||||||
analysisType: 'root_cause' | 'pattern' | 'comparison' | 'trend';
|
analysisType: 'root_cause' | 'pattern' | 'comparison' | 'trend';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function logAnalyzerError(message: string, error: unknown): void {
|
||||||
|
process.stderr.write(
|
||||||
|
JSON.stringify({
|
||||||
|
level: 'error',
|
||||||
|
module: 'ai-diagnostics.llm-analyzer',
|
||||||
|
message,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
}) + '\n'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const ROOT_CAUSE_ANALYSIS_PROMPT_TEMPLATE = `You are an expert software engineer diagnosing production errors. Analyze this error cluster and provide root cause insights.
|
const ROOT_CAUSE_ANALYSIS_PROMPT_TEMPLATE = `You are an expert software engineer diagnosing production errors. Analyze this error cluster and provide root cause insights.
|
||||||
|
|
||||||
## Error Cluster
|
## Error Cluster
|
||||||
@ -206,7 +217,7 @@ async function callLLM(
|
|||||||
completionTokens: data.usage?.completion_tokens || 0,
|
completionTokens: data.usage?.completion_tokens || 0,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('LLM call failed:', error);
|
logAnalyzerError('LLM call failed', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,17 @@ import type { DebugSessionDoc } from './types.js';
|
|||||||
import { createSession } from './repository.js';
|
import { createSession } from './repository.js';
|
||||||
import { getRegisteredContainer } from '@bytelyst/cosmos';
|
import { getRegisteredContainer } from '@bytelyst/cosmos';
|
||||||
|
|
||||||
|
function logTriggerError(message: string, error: unknown): void {
|
||||||
|
process.stderr.write(
|
||||||
|
JSON.stringify({
|
||||||
|
level: 'error',
|
||||||
|
module: 'diagnostics.auto-triggers',
|
||||||
|
message,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
}) + '\n'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
// Trigger Configuration Types
|
// Trigger Configuration Types
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
@ -399,7 +410,7 @@ async function sendTriggerNotifications(
|
|||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Log but don't fail
|
// Log but don't fail
|
||||||
console.error('Failed to send Slack notification:', err);
|
logTriggerError('Failed to send Slack notification', err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,7 +438,7 @@ async function sendTriggerNotifications(
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to send Teams notification:', err);
|
logTriggerError('Failed to send Teams notification', err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,12 @@ function screenshotsCollection() {
|
|||||||
return getCollection<DebugScreenshotDoc>('debug_screenshots', '/sessionId');
|
return getCollection<DebugScreenshotDoc>('debug_screenshots', '/sessionId');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function logDiagnosticsWarning(message: string, extra?: Record<string, unknown>): void {
|
||||||
|
process.stderr.write(
|
||||||
|
JSON.stringify({ level: 'warn', module: 'diagnostics.repository', message, ...extra }) + '\n'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
// Helper: Build composite partition key
|
// Helper: Build composite partition key
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
@ -320,9 +326,10 @@ export async function updateSessionStats(
|
|||||||
retries++;
|
retries++;
|
||||||
if (retries >= MAX_RETRIES) {
|
if (retries >= MAX_RETRIES) {
|
||||||
// Log warning but don't fail the ingest - data integrity > stats accuracy
|
// Log warning but don't fail the ingest - data integrity > stats accuracy
|
||||||
console.warn(
|
logDiagnosticsWarning('Failed to update session stats after max retries', {
|
||||||
`[diagnostics] Failed to update session stats after ${MAX_RETRIES} retries for session ${sessionId}`
|
retries: MAX_RETRIES,
|
||||||
);
|
sessionId,
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Small delay before retry
|
// Small delay before retry
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user