Created
July 18, 2025 14:32
-
-
Save suissa/1bc49c59ebc18a9a0aceddc1eef5d32a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'; | |
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-websocket'; | |
import WebSocket, { WebSocketServer } from 'ws'; | |
const metricExporter = new OTLPMetricExporter({ | |
url: 'ws://localhost:4318/v1/metrics', | |
}); | |
const meterProvider = new MeterProvider({ | |
readers: [new PeriodicExportingMetricReader({ | |
exporter: metricExporter, | |
exportIntervalMillis: 5000, | |
})], | |
}); | |
const meter = meterProvider.getMeter('websocket-metrics'); | |
const activeConnections = meter.createUpDownCounter('websocket_active_connections', { | |
description: 'Total de conexões WebSocket abertas no momento.', | |
}); | |
const connectionsOpened = meter.createCounter('websocket_connections_opened_total', { | |
description: 'Total acumulado de conexões WebSocket abertas.', | |
}); | |
const connectionsClosed = meter.createCounter('websocket_connections_closed_total', { | |
description: 'Total acumulado de conexões WebSocket fechadas.', | |
}); | |
const connectionDuration = meter.createHistogram('websocket_connection_duration_ms', { | |
description: 'Duração em milissegundos das conexões WebSocket.', | |
}); | |
const messagesSent = meter.createCounter('websocket_messages_sent_total', { | |
description: 'Total acumulado de mensagens WebSocket enviadas.', | |
}); | |
const messagesReceived = meter.createCounter('websocket_messages_received_total', { | |
description: 'Total acumulado de mensagens WebSocket recebidas.', | |
}); | |
const messageSize = meter.createHistogram('websocket_message_size_bytes', { | |
description: 'Tamanho das mensagens WebSocket em bytes.', | |
}); | |
const messageLatency = meter.createHistogram('websocket_message_latency_ms', { | |
description: 'Latência das mensagens (ping/pong) em ms.', | |
}); | |
const messageProcessingTime = meter.createHistogram('websocket_message_processing_time_ms', { | |
description: 'Tempo gasto para processar cada mensagem.', | |
}); | |
const connectionErrors = meter.createCounter('websocket_connection_errors_total', { | |
description: 'Total de erros ocorridos nas conexões WebSocket.', | |
}); | |
const reconnectionsPerClient = meter.createCounter('websocket_reconnections_total', { | |
description: 'Número total de reconexões automáticas feitas por clientes.', | |
}); | |
const messageSendFailures = meter.createCounter('websocket_message_send_failures_total', { | |
description: 'Falhas no envio das mensagens WebSocket.', | |
}); | |
const concurrentClients = meter.createUpDownCounter('websocket_concurrent_clients', { | |
description: 'Número simultâneo de clientes WebSocket.', | |
}); | |
const connectionRejectionRate = meter.createCounter('websocket_connection_rejections_total', { | |
description: 'Número total de conexões recusadas devido à sobrecarga.', | |
}); | |
const wss = new WebSocketServer({ port: 8080 }); | |
wss.on('connection', (ws: WebSocket, req) => { | |
const connectionStart = Date.now(); | |
activeConnections.add(1); | |
concurrentClients.add(1); | |
connectionsOpened.add(1); | |
ws.on('message', async (message: WebSocket.RawData) => { | |
const messageStart = Date.now(); | |
messagesReceived.add(1); | |
messageSize.record(Buffer.byteLength(message)); | |
// Simulando ping/pong latency | |
const latencyStart = Date.now(); | |
ws.ping(); | |
ws.once('pong', () => { | |
const latency = Date.now() - latencyStart; | |
messageLatency.record(latency); | |
}); | |
try { | |
// Simulando processamento | |
await processMessage(message); | |
const processingTime = Date.now() - messageStart; | |
messageProcessingTime.record(processingTime); | |
} catch (error) { | |
messageSendFailures.add(1); | |
} | |
}); | |
ws.on('close', () => { | |
const duration = Date.now() - connectionStart; | |
connectionDuration.record(duration); | |
activeConnections.add(-1); | |
concurrentClients.add(-1); | |
connectionsClosed.add(1); | |
}); | |
ws.on('error', () => { | |
connectionErrors.add(1); | |
}); | |
}); | |
async function processMessage(msg: WebSocket.RawData): Promise<void> { | |
messagesSent.add(1); | |
// Simulando delay no processamento | |
await new Promise(resolve => setTimeout(resolve, Math.random() * 200)); | |
} | |
const MAX_CONNECTIONS = 500; | |
wss.on('headers', (_, request) => { | |
if (wss.clients.size >= MAX_CONNECTIONS) { | |
connectionRejectionRate.add(1); | |
request.destroy(); | |
} | |
}); | |
console.log(`🚀 Servidor WebSocket rodando na porta 8080`); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment