Add Homepage dashboard + dual-export OpenCode traces
Homepage as the front door: single page at framework:7575 with one tile per service, live widgets where the upstream supports it (Ollama loaded models, container state via docker.sock, etc.), bookmarks for reference docs. Config files are pyinfra-managed — source of truth lives in compose/homepage/, sync by editing there and re-running ./run.sh. OpenCode plugin now dual-exports spans to Phoenix and OpenLIT in parallel. Phoenix remains the per-trace waterfall view; OpenLIT picks up the same data for fleet-level metrics. Each destination has its own batch processor so a hiccup at one doesn't block the other. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -40,8 +40,17 @@ export const PhoenixBridge = async ({ project, directory, worktree }) => {
|
||||
// Phoenix 15.x serves OTLP/HTTP at /v1/traces on the same port as the UI
|
||||
// (6006). Earlier versions used a separate 4318 — override here if you
|
||||
// ever pin Phoenix < 15.0.
|
||||
const endpoint =
|
||||
const phoenixEndpoint =
|
||||
process.env.PHOENIX_OTLP_ENDPOINT || "http://framework:6006/v1/traces";
|
||||
// OpenLIT's OTLP/HTTP receiver, host-mapped to 4328 in
|
||||
// pyinfra/framework/compose/openlit.yml. Set OPENLIT_OTLP_ENDPOINT to
|
||||
// an empty string (or "off") to disable the secondary export.
|
||||
const openlitEndpointRaw =
|
||||
process.env.OPENLIT_OTLP_ENDPOINT === undefined
|
||||
? "http://framework:4328/v1/traces"
|
||||
: process.env.OPENLIT_OTLP_ENDPOINT;
|
||||
const openlitEndpoint =
|
||||
openlitEndpointRaw && openlitEndpointRaw !== "off" ? openlitEndpointRaw : null;
|
||||
const serviceName = process.env.PHOENIX_SERVICE_NAME || "opencode";
|
||||
// NodeSDK's `serviceName` constructor option is ignored in some
|
||||
// versions; setting OTEL_SERVICE_NAME forces the resource attribute
|
||||
@@ -49,7 +58,9 @@ export const PhoenixBridge = async ({ project, directory, worktree }) => {
|
||||
if (!process.env.OTEL_SERVICE_NAME) {
|
||||
process.env.OTEL_SERVICE_NAME = serviceName;
|
||||
}
|
||||
log(`endpoint=${endpoint} serviceName=${serviceName}`);
|
||||
log(
|
||||
`phoenix=${phoenixEndpoint} openlit=${openlitEndpoint || "off"} serviceName=${serviceName}`,
|
||||
);
|
||||
|
||||
// Dynamic imports so a missing dep produces a warning, not a freeze.
|
||||
let NodeSDK,
|
||||
@@ -105,13 +116,18 @@ export const PhoenixBridge = async ({ project, directory, worktree }) => {
|
||||
|
||||
// NodeSDK accepts `serviceName` directly, sidestepping the Resource API
|
||||
// (which broke between @opentelemetry/resources v1.x and v2.x).
|
||||
// SimpleSpanProcessor (vs BatchSpanProcessor) exports each span
|
||||
// immediately — easier to debug while we sort out the pipeline.
|
||||
const exporter = new OTLPTraceExporter({ url: endpoint });
|
||||
const sdk = new NodeSDK({
|
||||
serviceName,
|
||||
spanProcessors: [new SimpleSpanProcessor(exporter)],
|
||||
});
|
||||
// BatchSpanProcessor batches spans and flushes every ~5s — fine in
|
||||
// steady state. Each destination gets its own processor + exporter so
|
||||
// a hiccup at one (e.g. OpenLIT down) doesn't block the other.
|
||||
const spanProcessors = [
|
||||
new BatchSpanProcessor(new OTLPTraceExporter({ url: phoenixEndpoint })),
|
||||
];
|
||||
if (openlitEndpoint) {
|
||||
spanProcessors.push(
|
||||
new BatchSpanProcessor(new OTLPTraceExporter({ url: openlitEndpoint })),
|
||||
);
|
||||
}
|
||||
const sdk = new NodeSDK({ serviceName, spanProcessors });
|
||||
sdk.start();
|
||||
log("sdk.start() returned");
|
||||
|
||||
|
||||
@@ -75,12 +75,17 @@ The plugin uses `@opentelemetry/exporter-trace-otlp-proto` (not `-http`)
|
||||
because Phoenix's OTLP receiver only speaks protobuf — the JSON variant
|
||||
returns 415.
|
||||
|
||||
Spans are dual-exported: Phoenix (per-trace waterfall) and OpenLIT (fleet
|
||||
metrics). Each destination has its own batch processor so a hiccup at
|
||||
one doesn't block the other.
|
||||
|
||||
Defaults can be overridden via env vars (set before launching opencode):
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `PHOENIX_OTLP_ENDPOINT` | `http://framework:6006/v1/traces` | OTLP/HTTP target |
|
||||
| `PHOENIX_SERVICE_NAME` | `opencode` | Phoenix project name |
|
||||
| `PHOENIX_OTLP_ENDPOINT` | `http://framework:6006/v1/traces` | Phoenix HTTP target |
|
||||
| `OPENLIT_OTLP_ENDPOINT` | `http://framework:4328/v1/traces` | OpenLIT HTTP target. Set to `off` to disable. |
|
||||
| `PHOENIX_SERVICE_NAME` | `opencode` | Service / project name (both backends) |
|
||||
| `PHOENIX_OTEL_DEBUG` | unset | `1` to surface OTel internal logs |
|
||||
|
||||
### Verifying
|
||||
|
||||
Reference in New Issue
Block a user