Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions charts/lobu/templates/gateway-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ spec:
optional: true

{{- if .Values.tempo.enabled }}
# Tempo distributed tracing endpoint
- name: TEMPO_ENDPOINT
# OpenTelemetry OTLP endpoint for distributed tracing
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://{{ .Release.Name }}-tempo:4318/v1/traces"
{{- end }}

Expand Down
5 changes: 3 additions & 2 deletions charts/lobu/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,10 @@ grafana:
namespace: "monitoring" # Namespace where Grafana is installed
lokiUrl: "http://loki:3100" # URL to Loki service

# Grafana Tempo for distributed tracing (waterfall view)
# Grafana Tempo for distributed tracing
# When enabled, sets OTEL_EXPORTER_OTLP_ENDPOINT automatically for gateway and workers
tempo:
enabled: false # Enable for Chrome DevTools-style trace visualization
enabled: false
# Tempo subchart configuration
tempo:
# Use local filesystem storage for simplicity (switch to S3/GCS in production)
Expand Down
14 changes: 13 additions & 1 deletion config/biome.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"!**/node_modules/**",
"!**/.astro/**",
"!**/tmp/**",
"!**/provision-careops-watchers*"
"!**/provision-careops-watchers*",
"!**/*.css"
]
},
"formatter": {
Expand Down Expand Up @@ -98,6 +99,17 @@
}
}
},
"css": {
"parser": {
"cssModules": true
},
"formatter": {
"enabled": false
},
"linter": {
"enabled": false
}
},
"javascript": {
"formatter": {
"jsxQuoteStyle": "double",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"docker:build": "docker build -f docker/Dockerfile.gateway -t lobu-gateway . && docker build -f docker/Dockerfile.worker -t lobu-worker .",
"k8s:deploy": "helm upgrade --install lobu charts/lobu --dependency-update",
"k8s:uninstall": "helm uninstall lobu",
"publish:packages": "cd packages/core && npm publish --access public && cd ../gateway && npm publish --access public && cd ../worker && npm publish --access public && cd ../cli && npm publish --access public",
"publish:packages": "cd packages/core && pnpm publish --access public --no-git-checks && cd ../gateway && pnpm publish --access public --no-git-checks && cd ../worker && pnpm publish --access public --no-git-checks && cd ../cli && pnpm publish --access public --no-git-checks",
"stage:publish": "node scripts/stage-publish-package.mjs",
"slack:manifest:print": "bun run scripts/slack-manifest.ts print",
"slack:manifest:validate": "bun run scripts/slack-manifest.ts validate",
Expand Down
37 changes: 37 additions & 0 deletions packages/cli/src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,43 @@ export async function initCommand(
}
// "none" — no env var needed, gateway defaults to filesystem memory

// Observability — OTEL tracing endpoint
const { otelEndpoint } = await inquirer.prompt([
{
type: "input",
name: "otelEndpoint",
message:
"OpenTelemetry collector endpoint? (leave empty to disable tracing)",
default: "",
},
]);

if (otelEndpoint) {
envSecrets.push({
envVar: "OTEL_EXPORTER_OTLP_ENDPOINT",
value: otelEndpoint,
});
}

// Observability — Sentry error reporting
const { enableSentry } = await inquirer.prompt([
{
type: "confirm",
name: "enableSentry",
message:
"Help improve Lobu by sharing anonymous error reports with Sentry?",
default: true,
},
]);

if (enableSentry) {
envSecrets.push({
envVar: "SENTRY_DSN",
value:
"https://c5910e58d1a134d64ff93a95a9c535bb@o4507291398897664.ingest.us.sentry.io/4511097466781696",
});
}

// Compute network domains from selected policy
let allowedDomains: string;
let disallowedDomains: string;
Expand Down
45 changes: 22 additions & 23 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,26 @@ export type {
StoredConnection,
} from "./agent-store";
export { findTemplateAgentId } from "./agent-store";
// Agent Settings API response types (for UI consumers)
export type {
AgentConfigResponse,
AgentInfo,
CatalogProvider,
Connection,
McpConfig,
ModelOption,
ModelSelectionState,
PermissionGrant,
PrefillMcp,
PrefillSkill,
ProviderInfo,
ProviderState,
ProviderStatus,
Schedule,
SettingsSnapshot,
Skill,
SkillMcpServerInfo,
} from "./api-types";
export type { CommandContext, CommandDefinition } from "./command-registry";
// Command registry
export { CommandRegistry } from "./command-registry";
Expand All @@ -33,7 +53,7 @@ export * from "./logger";
export type { ActionButton, ModuleSessionContext } from "./modules";
export * from "./modules";
export type { OtelConfig, Span, Tracer } from "./otel";
// OpenTelemetry tracing (Tempo integration)
// OpenTelemetry tracing
export {
createChildSpan,
createRootSpan,
Expand Down Expand Up @@ -80,13 +100,13 @@ export type {
InstructionContext,
InstructionProvider,
LogLevel,
McpOAuthConfig,
McpServerConfig,
NetworkConfig,
NixConfig,
RegistryEntry,
SessionContext,
SkillConfig,
McpOAuthConfig,
SkillMcpServer,
SkillsConfig,
SuggestedPrompt,
Expand All @@ -96,27 +116,6 @@ export type {
UserSuggestion,
} from "./types";

// Agent Settings API response types (for UI consumers)
export type {
AgentConfigResponse,
AgentInfo,
CatalogProvider,
Connection,
McpConfig,
ModelOption,
ModelSelectionState,
PermissionGrant,
PrefillMcp,
PrefillSkill,
ProviderInfo,
ProviderState,
ProviderStatus,
Schedule,
SettingsSnapshot,
Skill,
SkillMcpServerInfo,
} from "./api-types";

// Utilities
export * from "./utils/encryption";
export * from "./utils/env";
Expand Down
21 changes: 11 additions & 10 deletions packages/core/src/otel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* OpenTelemetry tracing setup for distributed tracing with Grafana Tempo.
* Provides Chrome DevTools-style waterfall visualization in Grafana.
* OpenTelemetry tracing setup for distributed tracing.
* Ships traces via OTLP HTTP to any compatible collector (Tempo, Jaeger, Datadog, etc.).
*/

import type { Span, Tracer } from "@opentelemetry/api";
Expand All @@ -25,7 +25,7 @@ let tracer: Tracer | null = null;
export interface OtelConfig {
serviceName: string;
serviceVersion?: string;
tempoEndpoint?: string; // e.g., "http://tempo:4318/v1/traces"
otlpEndpoint?: string; // e.g., "http://collector:4318/v1/traces"
enabled?: boolean;
}

Expand All @@ -36,17 +36,19 @@ export interface OtelConfig {
* @example
* initTracing({
* serviceName: "lobu-gateway",
* tempoEndpoint: "http://lobu-tempo:4318/v1/traces",
* otlpEndpoint: "http://collector:4318/v1/traces",
* });
*/
export function initTracing(config: OtelConfig): void {
if (provider) {
return; // Already initialized
}

const enabled = config.enabled ?? !!config.tempoEndpoint;
const enabled = config.enabled ?? !!config.otlpEndpoint;
if (!enabled) {
logger.debug("Tracing disabled (no TEMPO_ENDPOINT configured)");
logger.debug(
"Tracing disabled (no OTEL_EXPORTER_OTLP_ENDPOINT configured)"
);
return;
}

Expand All @@ -57,9 +59,8 @@ export function initTracing(config: OtelConfig): void {

provider = new NodeTracerProvider({ resource });

// Configure OTLP exporter to send traces to Tempo
const exporter = new OTLPTraceExporter({
url: config.tempoEndpoint,
url: config.otlpEndpoint,
timeoutMillis: 30000, // 30 second timeout for reliability
});

Expand All @@ -70,7 +71,7 @@ export function initTracing(config: OtelConfig): void {
tracer = trace.getTracer(config.serviceName, config.serviceVersion);

logger.info(
`Tracing initialized: ${config.serviceName} -> ${config.tempoEndpoint}`
`Tracing initialized: ${config.serviceName} -> ${config.otlpEndpoint}`
);
}

Expand Down Expand Up @@ -301,6 +302,6 @@ export function getTraceparent(span: Span | null): string | null {
return `00-${ctx.traceId}-${ctx.spanId}-01`;
}

export type { Span, Tracer };
// Re-export OpenTelemetry types for convenience
export { SpanKind, SpanStatusCode };
export type { Span, Tracer };
18 changes: 10 additions & 8 deletions packages/core/src/sentry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,21 @@ function getLogger(): Logger {
let sentryInstance: typeof import("@sentry/node") | null = null;

/**
* Initialize Sentry with configuration from environment variables
* Falls back to hardcoded DSN if SENTRY_DSN is not provided
* Uses dynamic import to avoid module resolution issues in dev mode
* Initialize Sentry with configuration from environment variables.
* Only initializes if SENTRY_DSN is set — no implicit error reporting.
* Uses dynamic import to avoid module resolution issues in dev mode.
*/
export async function initSentry() {
const sentryDsn = process.env.SENTRY_DSN;
if (!sentryDsn) {
getLogger().debug("Sentry disabled (no SENTRY_DSN configured)");
return;
}

try {
const Sentry = await import("@sentry/node");
sentryInstance = Sentry;

const sentryDsn =
process.env.SENTRY_DSN ||
"https://c5910e58d1a134d64ff93a95a9c535bb@o4507291398897664.ingest.us.sentry.io/4511097466781696";

Sentry.init({
dsn: sentryDsn,
sendDefaultPii: true,
Expand All @@ -39,7 +41,7 @@ export async function initSentry() {
getLogger().debug("Sentry monitoring initialized");
} catch (error) {
getLogger().warn(
"⚠️ Sentry initialization failed (continuing without monitoring):",
"Sentry initialization failed (continuing without monitoring):",
error
);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/gateway/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ async function main() {
initTracing({
serviceName: "lobu-gateway",
serviceVersion: process.env.npm_package_version || "2.0.0",
tempoEndpoint: process.env.TEMPO_ENDPOINT,
enabled: !!process.env.TEMPO_ENDPOINT,
otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
enabled: !!process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
});

const config = buildGatewayConfig();
Expand Down
Loading
Loading