()
| 133 | } |
| 134 | |
| 135 | async function initializeOpenTelemetry() { |
| 136 | try { |
| 137 | if (env.NEXT_TELEMETRY_DISABLED === '1' || process.env.NEXT_TELEMETRY_DISABLED === '1') { |
| 138 | logger.info('OpenTelemetry disabled via NEXT_TELEMETRY_DISABLED=1') |
| 139 | return |
| 140 | } |
| 141 | |
| 142 | let telemetryConfig |
| 143 | try { |
| 144 | telemetryConfig = (await import('./telemetry.config')).default |
| 145 | } catch { |
| 146 | telemetryConfig = DEFAULT_TELEMETRY_CONFIG |
| 147 | } |
| 148 | |
| 149 | // Prefer the OTel spec env var, fall back to legacy TELEMETRY_ENDPOINT. |
| 150 | const resolvedEndpoint = |
| 151 | process.env.OTEL_EXPORTER_OTLP_ENDPOINT || |
| 152 | process.env.TELEMETRY_ENDPOINT || |
| 153 | env.TELEMETRY_ENDPOINT || |
| 154 | telemetryConfig.endpoint |
| 155 | telemetryConfig = { |
| 156 | ...telemetryConfig, |
| 157 | endpoint: resolvedEndpoint, |
| 158 | serviceName: 'mothership', |
| 159 | } |
| 160 | |
| 161 | if (telemetryConfig.serverSide?.enabled === false) { |
| 162 | logger.info('Server-side OpenTelemetry disabled in config') |
| 163 | return |
| 164 | } |
| 165 | |
| 166 | logger.info('OpenTelemetry init', { |
| 167 | endpoint: telemetryConfig.endpoint, |
| 168 | serviceName: telemetryConfig.serviceName, |
| 169 | origin: MOTHERSHIP_ORIGIN, |
| 170 | }) |
| 171 | |
| 172 | const { NodeSDK } = await import('@opentelemetry/sdk-node') |
| 173 | const { defaultResource, resourceFromAttributes } = await import('@opentelemetry/resources') |
| 174 | const { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION, ATTR_DEPLOYMENT_ENVIRONMENT } = await import( |
| 175 | '@opentelemetry/semantic-conventions/incubating' |
| 176 | ) |
| 177 | const { OTLPTraceExporter } = await import('@opentelemetry/exporter-trace-otlp-http') |
| 178 | const { OTLPMetricExporter } = await import('@opentelemetry/exporter-metrics-otlp-http') |
| 179 | const { PeriodicExportingMetricReader } = await import('@opentelemetry/sdk-metrics') |
| 180 | const { BatchSpanProcessor } = await import('@opentelemetry/sdk-trace-node') |
| 181 | const { TraceIdRatioBasedSampler, SamplingDecision } = await import( |
| 182 | '@opentelemetry/sdk-trace-base' |
| 183 | ) |
| 184 | |
| 185 | // Drops Next framework spans, inherits SAMPLED from business |
| 186 | // parents, and re-samples business roots fresh (don't delegate to |
| 187 | // ParentBased — its unsampled-parent path is AlwaysOff by default). |
| 188 | const createBusinessSpanSampler = (rootRatioSampler: Sampler): Sampler => ({ |
| 189 | shouldSample( |
| 190 | context: Context, |
| 191 | traceId: string, |
| 192 | spanName: string, |
no test coverage detected