Compare commits
2 Commits
feat/s3-storage
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| eb385707fa | |||
| 0bdae453fc |
@@ -42,6 +42,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Bump k8s-pods image tag (ArgoCD deploys)
|
- name: Bump k8s-pods image tag (ArgoCD deploys)
|
||||||
run: |
|
run: |
|
||||||
|
rm -rf /tmp/kp # dind-builder is a persistent host: clear any stale checkout from a prior run
|
||||||
git clone --depth 1 -b main \
|
git clone --depth 1 -b main \
|
||||||
"https://mcp-bot:${{ secrets.K8S_PODS_TOKEN }}@git.lynkedup.cloud/platform-engineering/k8s-pods.git" /tmp/kp
|
"https://mcp-bot:${{ secrets.K8S_PODS_TOKEN }}@git.lynkedup.cloud/platform-engineering/k8s-pods.git" /tmp/kp
|
||||||
cd /tmp/kp
|
cd /tmp/kp
|
||||||
|
|||||||
@@ -30,7 +30,10 @@
|
|||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rxjs": "^7.8.2",
|
"rxjs": "^7.8.2",
|
||||||
"socket.io": "^4.8.3",
|
"socket.io": "^4.8.3",
|
||||||
"web-push": "^3.6.7"
|
"web-push": "^3.6.7",
|
||||||
|
"@opentelemetry/api": "^1.9.1",
|
||||||
|
"@opentelemetry/sdk-node": "^0.220.0",
|
||||||
|
"@opentelemetry/auto-instrumentations-node": "^0.78.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@insignia/iios-testkit": "workspace:*",
|
"@insignia/iios-testkit": "workspace:*",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import './observability/tracing'; // MUST be first — auto-instrumentation patches modules on require
|
||||||
import 'dotenv/config';
|
import 'dotenv/config';
|
||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { Request, Response, NextFunction } from 'express';
|
import type { Request, Response, NextFunction } from 'express';
|
||||||
|
import { trace } from '@opentelemetry/api';
|
||||||
import { runWithTrace, newTraceId, traceIdFromTraceparent } from './trace-context';
|
import { runWithTrace, newTraceId, traceIdFromTraceparent } from './trace-context';
|
||||||
import { logJson } from './logger';
|
import { logJson } from './logger';
|
||||||
|
|
||||||
@@ -9,8 +10,13 @@ import { logJson } from './logger';
|
|||||||
* the response finishes (method, path, status, ms). Wired via app.use() in main.ts.
|
* the response finishes (method, path, status, ms). Wired via app.use() in main.ts.
|
||||||
*/
|
*/
|
||||||
export function traceMiddleware(req: Request, res: Response, next: NextFunction): void {
|
export function traceMiddleware(req: Request, res: Response, next: NextFunction): void {
|
||||||
|
// Prefer the ACTIVE OpenTelemetry trace id: that is what makes this log line
|
||||||
|
// joinable to its distributed trace in Grafana (Loki -> Tempo). Falls back to
|
||||||
|
// the inbound header, then traceparent, then a generated id, so a correlation
|
||||||
|
// id is always present even when tracing is disabled.
|
||||||
|
const otelTraceId = trace.getActiveSpan()?.spanContext().traceId;
|
||||||
const headerTrace = (req.headers['x-trace-id'] as string | undefined)?.trim();
|
const headerTrace = (req.headers['x-trace-id'] as string | undefined)?.trim();
|
||||||
const traceId = headerTrace || traceIdFromTraceparent(req.headers['traceparent'] as string | undefined) || newTraceId();
|
const traceId = otelTraceId || headerTrace || traceIdFromTraceparent(req.headers['traceparent'] as string | undefined) || newTraceId();
|
||||||
res.setHeader('x-trace-id', traceId);
|
res.setHeader('x-trace-id', traceId);
|
||||||
const startedAt = Date.now();
|
const startedAt = Date.now();
|
||||||
runWithTrace(traceId, () => {
|
runWithTrace(traceId, () => {
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* OpenTelemetry bootstrap. MUST be imported before anything else in main.ts —
|
||||||
|
* auto-instrumentation works by patching modules (http, express, pg, redis, …)
|
||||||
|
* as they are require()d, so any module loaded before this runs is never traced.
|
||||||
|
*
|
||||||
|
* Env-driven on purpose: the OTel SDK reads OTEL_SERVICE_NAME,
|
||||||
|
* OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_PROTOCOL itself, so the
|
||||||
|
* collector target is a deployment concern rather than a code change. When
|
||||||
|
* OTEL_EXPORTER_OTLP_ENDPOINT is unset the SDK never starts, so local dev and
|
||||||
|
* tests run with zero tracing overhead and no exporter errors.
|
||||||
|
*
|
||||||
|
* Traces land in Tempo and are viewable in Grafana. The existing P9 trace
|
||||||
|
* middleware adopts the active OTel trace id, so an `http.request` log line and
|
||||||
|
* its distributed trace share one id (Loki -> Tempo pivot).
|
||||||
|
*/
|
||||||
|
import { NodeSDK } from '@opentelemetry/sdk-node';
|
||||||
|
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
||||||
|
|
||||||
|
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
||||||
|
|
||||||
|
if (endpoint) {
|
||||||
|
const sdk = new NodeSDK({
|
||||||
|
instrumentations: [
|
||||||
|
getNodeAutoInstrumentations({
|
||||||
|
// Noisy and low value: every file read becomes a span.
|
||||||
|
'@opentelemetry/instrumentation-fs': { enabled: false },
|
||||||
|
// k8s probes hit /health constantly; tracing them would swamp Tempo
|
||||||
|
// and bury the real request traces.
|
||||||
|
'@opentelemetry/instrumentation-http': {
|
||||||
|
ignoreIncomingRequestHook: (req) => {
|
||||||
|
const url = req.url ?? '';
|
||||||
|
return ['/health', '/ready', '/healthz', '/readyz', '/metrics'].some((p) =>
|
||||||
|
url.startsWith(p),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
sdk.start();
|
||||||
|
|
||||||
|
const shutdown = (): void => {
|
||||||
|
// Flush buffered spans before exit, else the last requests before a
|
||||||
|
// rollout are lost.
|
||||||
|
void sdk.shutdown().finally(() => process.exit(0));
|
||||||
|
};
|
||||||
|
process.on('SIGTERM', shutdown);
|
||||||
|
process.on('SIGINT', shutdown);
|
||||||
|
}
|
||||||
Generated
+1826
-35
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user