Files
sim/apps/sim/instrumentation-server.ts
Waleed Latif 8c268e23dd chore(biome): removed prettier, added biome (#407)
* chore: replace prettier with biome and add linting

* chore: update devcontainer settings to use biome for linting and remove eslint, prettier

* chore: update docker-compose to use Postgres 17-alpine and standardize quotes

* chore: fixed more BUT disabled most rules due to limit

* added additional rules, fixed linting & ts errors

* added additional rules

* rebased & linted

* fixed oauth

* updated biome & minor modifications

---------

Co-authored-by: Aditya Tripathi <aditya@climactic.co>
2025-05-24 03:11:38 -07:00

144 lines
4.5 KiB
TypeScript

/**
* Sim Studio Telemetry - Server-side Instrumentation
*
* This file contains all server-side instrumentation logic.
*/
import { createLogger } from '@/lib/logs/console-logger'
import { env } from './lib/env.ts'
const Sentry =
process.env.NODE_ENV === 'production'
? require('@sentry/nextjs')
: { captureRequestError: () => {} }
const logger = createLogger('OtelInstrumentation')
const DEFAULT_TELEMETRY_CONFIG = {
endpoint: env.TELEMETRY_ENDPOINT || 'https://telemetry.simstudio.ai/v1/traces',
serviceName: 'sim-studio',
serviceVersion: '0.1.0',
serverSide: { enabled: true },
batchSettings: {
maxQueueSize: 100,
maxExportBatchSize: 10,
scheduledDelayMillis: 5000,
exportTimeoutMillis: 30000,
},
}
// Initialize OpenTelemetry
async function initializeOpenTelemetry() {
try {
if (env.NEXT_TELEMETRY_DISABLED === '1') {
logger.info('OpenTelemetry telemetry disabled via environment variable')
return
}
let telemetryConfig
try {
// Use dynamic import for ES modules
telemetryConfig = (await import('./telemetry.config.ts')).default
} catch (_e) {
telemetryConfig = DEFAULT_TELEMETRY_CONFIG
}
if (telemetryConfig.serverSide?.enabled === false) {
logger.info('Server-side OpenTelemetry instrumentation is disabled in config')
return
}
// Dynamic imports for server-side libraries
const { NodeSDK } = await import('@opentelemetry/sdk-node')
const { resourceFromAttributes } = await import('@opentelemetry/resources')
const { SemanticResourceAttributes } = await import('@opentelemetry/semantic-conventions')
const { BatchSpanProcessor } = await import('@opentelemetry/sdk-trace-node')
const { OTLPTraceExporter } = await import('@opentelemetry/exporter-trace-otlp-http')
const exporter = new OTLPTraceExporter({
url: telemetryConfig.endpoint,
})
const spanProcessor = new BatchSpanProcessor(exporter, {
maxQueueSize:
telemetryConfig.batchSettings?.maxQueueSize ||
DEFAULT_TELEMETRY_CONFIG.batchSettings.maxQueueSize,
maxExportBatchSize:
telemetryConfig.batchSettings?.maxExportBatchSize ||
DEFAULT_TELEMETRY_CONFIG.batchSettings.maxExportBatchSize,
scheduledDelayMillis:
telemetryConfig.batchSettings?.scheduledDelayMillis ||
DEFAULT_TELEMETRY_CONFIG.batchSettings.scheduledDelayMillis,
exportTimeoutMillis:
telemetryConfig.batchSettings?.exportTimeoutMillis ||
DEFAULT_TELEMETRY_CONFIG.batchSettings.exportTimeoutMillis,
})
const configResource = resourceFromAttributes({
[SemanticResourceAttributes.SERVICE_NAME]: telemetryConfig.serviceName,
[SemanticResourceAttributes.SERVICE_VERSION]: telemetryConfig.serviceVersion,
[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: env.NODE_ENV,
})
const sdk = new NodeSDK({
resource: configResource,
spanProcessors: [spanProcessor],
})
sdk.start()
const shutdownHandler = async () => {
await sdk
.shutdown()
.then(() => logger.info('OpenTelemetry SDK shut down successfully'))
.catch((err) => logger.error('Error shutting down OpenTelemetry SDK', err))
}
process.on('SIGTERM', shutdownHandler)
process.on('SIGINT', shutdownHandler)
logger.info('OpenTelemetry instrumentation initialized for server-side telemetry')
} catch (error) {
logger.error('Failed to initialize OpenTelemetry instrumentation', error)
}
}
async function initializeSentry() {
if (env.NODE_ENV !== 'production') return
try {
const Sentry = await import('@sentry/nextjs')
// Skip initialization if Sentry appears to be already configured
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore accessing internal API
if ((Sentry as any).Hub?.current?.getClient()) {
logger.debug('Sentry already initialized, skipping duplicate init')
return
}
Sentry.init({
dsn: env.NEXT_PUBLIC_SENTRY_DSN || undefined,
enabled: true,
environment: env.NODE_ENV || 'development',
tracesSampleRate: 0.2,
beforeSend(event) {
if (event.request && typeof event.request === 'object') {
;(event.request as any).ip = null
}
return event
},
})
logger.info('Sentry initialized (server-side)')
} catch (error) {
logger.error('Failed to initialize Sentry', error as Error)
}
}
export async function register() {
await initializeSentry()
await initializeOpenTelemetry()
}
export const onRequestError = Sentry.captureRequestError