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:
Saravana Achu Mac 2026-05-04 16:48:25 -07:00
parent 2c9dc1870d
commit 663dcdecab
5 changed files with 73 additions and 15 deletions

View File

@ -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);
} }
} }

View File

@ -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;
} }
} }

View File

@ -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;
} }
} }

View File

@ -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);
} }
} }

View File

@ -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