feat: add lab SQLite migrate, LiteLLM env, and OTEL/Grafana stack
sonar / sonar (push) Skipped
sonar / sonar (pull_request) Failing after 40s
sonar / sonar (push) Skipped
sonar / sonar (pull_request) Failing after 40s
Enable local workshop readiness with executable SQLite migrations, OpenTelemetry hello signals, and a provisioned Grafana demo dashboard over Tempo/Loki/Prometheus. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import { metrics, trace } from "@opentelemetry/api";
|
||||
import { logs } from "@opentelemetry/api-logs";
|
||||
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
|
||||
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
|
||||
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
||||
import { resourceFromAttributes } from "@opentelemetry/resources";
|
||||
import {
|
||||
LoggerProvider,
|
||||
SimpleLogRecordProcessor,
|
||||
} from "@opentelemetry/sdk-logs";
|
||||
import {
|
||||
MeterProvider,
|
||||
PeriodicExportingMetricReader,
|
||||
} from "@opentelemetry/sdk-metrics";
|
||||
import {
|
||||
NodeTracerProvider,
|
||||
SimpleSpanProcessor,
|
||||
} from "@opentelemetry/sdk-trace-node";
|
||||
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
||||
|
||||
export type Telemetry = {
|
||||
tracer: ReturnType<typeof trace.getTracer>;
|
||||
meter: ReturnType<typeof metrics.getMeter>;
|
||||
logger: ReturnType<typeof logs.getLogger>;
|
||||
shutdown: () => Promise<void>;
|
||||
};
|
||||
|
||||
function otlpBaseUrl(): string {
|
||||
return (
|
||||
process.env.OTEL_EXPORTER_OTLP_ENDPOINT?.replace(/\/$/, "") ??
|
||||
"http://localhost:4318"
|
||||
);
|
||||
}
|
||||
|
||||
export function startTelemetry(
|
||||
serviceName = process.env.OTEL_SERVICE_NAME ?? "ticketlab",
|
||||
): Telemetry {
|
||||
const resource = resourceFromAttributes({
|
||||
[ATTR_SERVICE_NAME]: serviceName,
|
||||
});
|
||||
const base = otlpBaseUrl();
|
||||
|
||||
const tracerProvider = new NodeTracerProvider({
|
||||
resource,
|
||||
spanProcessors: [
|
||||
new SimpleSpanProcessor(
|
||||
new OTLPTraceExporter({ url: `${base}/v1/traces` }),
|
||||
),
|
||||
],
|
||||
});
|
||||
tracerProvider.register();
|
||||
|
||||
const meterProvider = new MeterProvider({
|
||||
resource,
|
||||
readers: [
|
||||
new PeriodicExportingMetricReader({
|
||||
exporter: new OTLPMetricExporter({ url: `${base}/v1/metrics` }),
|
||||
exportIntervalMillis: 500,
|
||||
}),
|
||||
],
|
||||
});
|
||||
metrics.setGlobalMeterProvider(meterProvider);
|
||||
|
||||
const loggerProvider = new LoggerProvider({
|
||||
resource,
|
||||
processors: [
|
||||
new SimpleLogRecordProcessor({
|
||||
exporter: new OTLPLogExporter({ url: `${base}/v1/logs` }),
|
||||
}),
|
||||
],
|
||||
});
|
||||
logs.setGlobalLoggerProvider(loggerProvider);
|
||||
|
||||
return {
|
||||
tracer: trace.getTracer(serviceName),
|
||||
meter: metrics.getMeter(serviceName),
|
||||
logger: logs.getLogger(serviceName),
|
||||
shutdown: async () => {
|
||||
await Promise.all([
|
||||
tracerProvider.forceFlush(),
|
||||
meterProvider.forceFlush(),
|
||||
loggerProvider.forceFlush(),
|
||||
]);
|
||||
await Promise.all([
|
||||
tracerProvider.shutdown(),
|
||||
meterProvider.shutdown(),
|
||||
loggerProvider.shutdown(),
|
||||
]);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export { SeverityNumber } from "@opentelemetry/api-logs";
|
||||
Reference in New Issue
Block a user