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
13 changes: 12 additions & 1 deletion web/actions/compose.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,6 +5,7 @@ import { db } from "@/db";
import { services } from "@/db/schema";
import { requireDeveloperRole } from "@/lib/auth";
import { parseComposeYaml } from "@/lib/compose-parser";
import { reportServerError } from "@/lib/server-errors";
import {
addServiceVolume,
createService,
Expand DownExpand Up@@ -144,6 +145,9 @@ export async function importCompose(
volume.containerPath,
);
} catch (e) {
reportServerError(e, "compose-import.volume.add", {
tags: { serviceId: result.id },
});
warnings.push({
service: finalName,
field: "volumes",
Expand DownExpand Up@@ -182,9 +186,16 @@ export async function importCompose(
for (const serviceId of createdServiceIds) {
try {
await db.delete(services).where(eq(services.id, serviceId));
} catch {}
} catch (cleanupError) {
reportServerError(cleanupError, "compose-import.cleanup", {
tags: { serviceId },
});
}
}

reportServerError(error, "compose-import.create", {
tags: { projectId, environmentId },
});
return {
success: false,
created: [],
Expand Down
4 changes: 4 additions & 0 deletions web/actions/projects.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,6 +54,7 @@ import {
cleanupRegistryArtifactsForService,
prepareRegistryArtifactCleanup,
} from "@/lib/registry-retention";
import { reportServerError } from "@/lib/server-errors";
import {
deletePreviewService,
deletePreviewsForBaseService,
Expand DownExpand Up@@ -1748,6 +1749,9 @@ export async function abortRollout(serviceId: string) {
try {
await inngest.send(inngestEvents.rolloutCancelled.create({ rolloutId }));
} catch (error) {
reportServerError(error, "rollout.cancellation.dispatch", {
tags: { rolloutId, serviceId },
});
console.error(
`[rollout:${rolloutId}] failed to send cancellation:`,
error,
Expand Down
2 changes: 2 additions & 0 deletions web/app/api/builds/[buildId]/logs/route.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
import { type NextRequest, NextResponse } from "next/server";
import { invalidLogQueryResponse, normalizeLogSearch } from "@/lib/log-query";
import { reportServerError } from "@/lib/server-errors";
import { isLoggingEnabled, queryLogsByBuild } from "@/lib/victoria-logs";

export async function GET(
Expand DownExpand Up@@ -28,6 +29,7 @@ export async function GET(

return NextResponse.json({ logs });
} catch (error) {
reportServerError(error, "logs.build.query", { tags: { buildId } });
console.error("Failed to fetch build logs:", error);
return NextResponse.json(
{ message: "Failed to query build logs" },
Expand Down
4 changes: 4 additions & 0 deletions web/app/api/deployments/[id]/logs/route.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,6 +5,7 @@ import {
normalizeLogCursor,
parseLogLimit,
} from "@/lib/log-query";
import { reportServerError } from "@/lib/server-errors";
import { isLoggingEnabled, queryLogsByDeployment } from "@/lib/victoria-logs";

export async function GET(
Expand DownExpand Up@@ -50,6 +51,9 @@ export async function GET(
hasMore: result.hasMore,
});
} catch (error) {
reportServerError(error, "logs.deployment.query", {
tags: { deploymentId },
});
console.error("[logs:deployment] failed to query logs:", error);
return Response.json(
{ message: "Failed to query deployment logs" },
Expand Down
4 changes: 4 additions & 0 deletions web/app/api/github/repos/route.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@ import { db } from "@/db";
import { githubInstallations } from "@/db/schema";
import { eq } from "drizzle-orm";
import { getInstallationRepositories } from "@/lib/github";
import { reportServerError } from "@/lib/server-errors";

export async function GET() {
const session = await auth.api.getSession({
Expand DownExpand Up@@ -48,6 +49,9 @@ export async function GET() {
});
}
} catch (error) {
reportServerError(error, "github.repositories.list", {
tags: { installationId: installation.installationId },
});
console.error(
`[github:repos] failed to fetch repos for installation ${installation.installationId}:`,
error,
Expand Down
8 changes: 8 additions & 0 deletions web/app/api/github/setup/route.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,6 +5,7 @@ import { type NextRequest, NextResponse } from "next/server";
import { db } from "@/db";
import { githubInstallations } from "@/db/schema";
import { requireRequestDeveloperRole } from "@/lib/api-auth";
import { reportServerError } from "@/lib/server-errors";

async function getInstallationDetails(installationId: number): Promise<{
account: { login: string; type: "User" | "Organization" };
Expand DownExpand Up@@ -40,6 +41,13 @@ async function getInstallationDetails(installationId: number): Promise<{
);

if (!response.ok) {
reportServerError(
new Error(
`GitHub installation lookup failed with status ${response.status}`,
),
"github.installation.get",
{ tags: { installationId } },
);
console.error(
`[github:setup] failed to get installation ${installationId}:`,
await response.text(),
Expand Down
2 changes: 2 additions & 0 deletions web/app/api/inngest/route.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ import {
rolloutWorkflow,
scheduledBackupsCheck,
scheduledDeploymentsCheck,
sentryFailureWorkflow,
serviceDeletionWorkflow,
serviceCommandRetention,
serviceCronDispatcher,
Expand DownExpand Up@@ -52,6 +53,7 @@ export const { GET, POST, PUT } = serve({
agentUpgradeTimeoutCheck,
registryArtifactRetention,
migrationWorkflow,
sentryFailureWorkflow,
backupWorkflow,
restoreWorkflow,
onRestoreFailed,
Expand Down
2 changes: 2 additions & 0 deletions web/app/api/rollouts/[rolloutId]/logs/route.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
import { type NextRequest, NextResponse } from "next/server";
import { invalidLogQueryResponse, normalizeLogSearch } from "@/lib/log-query";
import { reportServerError } from "@/lib/server-errors";
import { isLoggingEnabled, queryLogsByRollout } from "@/lib/victoria-logs";

export async function GET(
Expand DownExpand Up@@ -29,6 +30,7 @@ export async function GET(

return NextResponse.json({ logs });
} catch (error) {
reportServerError(error, "logs.rollout.query", { tags: { rolloutId } });
console.error("Failed to fetch rollout logs:", error);
return NextResponse.json(
{ message: "Failed to query rollout logs" },
Expand Down
2 changes: 2 additions & 0 deletions web/app/api/servers/[id]/logs/route.ts
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
import { headers } from "next/headers";
import { auth } from "@/lib/auth";
import { invalidLogQueryResponse, parseLogListParams } from "@/lib/log-query";
import { reportServerError } from "@/lib/server-errors";
import { isLoggingEnabled, queryLogsByServer } from "@/lib/victoria-logs";

export async function GET(
Expand DownExpand Up@@ -46,6 +47,7 @@ export async function GET(
hasMore: result.hasMore,
});
} catch (error) {
reportServerError(error, "logs.server.query", { tags: { serverId } });
console.error("[logs:server] failed to query logs:", error);
return Response.json(
{ message: "Failed to query server logs" },
Expand Down
2 changes: 2 additions & 0 deletions web/app/api/servers/[id]/metrics/route.ts
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
import { headers } from "next/headers";
import { getServerDetails } from "@/db/queries";
import { auth } from "@/lib/auth";
import { reportServerError } from "@/lib/server-errors";
import {
emptyHistory,
getMetricWindow,
Expand DownExpand Up@@ -61,6 +62,7 @@ export async function GET(
range,
});
} catch (error) {
reportServerError(error, "metrics.server.query", { tags: { serverId } });
console.error("[metrics:server] failed to query metrics:", error);
return Response.json({
current: null,
Expand Down
3 changes: 3 additions & 0 deletions web/app/api/services/[id]/backups/route.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
import { desc, eq } from "drizzle-orm";
import { db } from "@/db";
import { volumeBackups, servers } from "@/db/schema";
import { reportServerError } from "@/lib/server-errors";

export async function GET(
request: NextRequest,
Expand All@@ -28,6 +29,8 @@ export async function GET(

return NextResponse.json({ backups });
} catch (error) {
const { id: serviceId } = await params;
reportServerError(error, "backups.list", { tags: { serviceId } });
console.error("[api:backups] failed to fetch backups:", error);
return NextResponse.json(
{ error: "Failed to fetch backups" },
Expand Down
7 changes: 7 additions & 0 deletions web/app/api/services/[id]/github/commits/route.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,7 @@ import { db } from "@/db";
import { githubRepos, services } from "@/db/schema";
import { requireRequestDeveloperRole } from "@/lib/api-auth";
import { listGitHubCommits } from "@/lib/github";
import { reportServerError } from "@/lib/server-errors";

export async function GET(
request: Request,
Expand DownExpand Up@@ -41,6 +42,12 @@ export async function GET(
);
return Response.json({ branch, commits });
} catch (error) {
reportServerError(error, "github.commits.list", {
tags: {
installationId: result.githubRepo.installationId,
serviceId,
},
});
return Response.json(
{
message:
Expand Down
2 changes: 2 additions & 0 deletions web/app/api/services/[id]/logs/route.ts
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
import { headers } from "next/headers";
import { auth } from "@/lib/auth";
import { invalidLogQueryResponse, parseLogListParams } from "@/lib/log-query";
import { reportServerError } from "@/lib/server-errors";
import {
isLoggingEnabled,
type LogType,
Expand DownExpand Up@@ -79,6 +80,7 @@ export async function GET(
hasMore: result.hasMore,
});
} catch (error) {
reportServerError(error, "logs.service.query", { tags: { serviceId } });
console.error("[logs:service] failed to query logs:", error);
return Response.json(
{ message: "Failed to query service logs" },
Expand Down
4 changes: 4 additions & 0 deletions web/app/api/services/[id]/metrics/route.ts
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
import { headers } from "next/headers";
import { getService } from "@/db/queries";
import { auth } from "@/lib/auth";
import { reportServerError } from "@/lib/server-errors";
import {
createEmptyServiceMetrics,
isMetricsEnabled,
Expand DownExpand Up@@ -45,6 +46,9 @@ export async function GET(
try {
return Response.json(await queryServiceMetrics({ serviceId, range }));
} catch (error) {
reportServerError(error, "metrics.service.query", {
tags: { serviceId },
});
console.error("[metrics:service] failed to query service metrics:", error);
return Response.json(
{ message: "Service metrics unavailable" },
Expand Down
2 changes: 2 additions & 0 deletions web/app/api/services/[id]/requests/route.ts
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
import { headers } from "next/headers";
import { auth } from "@/lib/auth";
import { invalidLogQueryResponse, parseLogListParams } from "@/lib/log-query";
import { reportServerError } from "@/lib/server-errors";
import { isLoggingEnabled, queryLogsByService } from "@/lib/victoria-logs";

export async function GET(
Expand DownExpand Up@@ -50,6 +51,7 @@ export async function GET(
hasMore: result.hasMore,
});
} catch (error) {
reportServerError(error, "logs.requests.query", { tags: { serviceId } });
console.error("[logs:requests] failed to query HTTP logs:", error);
return Response.json(
{ message: "Failed to query request logs" },
Expand Down
4 changes: 4 additions & 0 deletions web/app/api/services/[id]/secrets/[secretId]/reveal/route.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@ import { secrets } from "@/db/schema";
import { requireRequestDeveloperRole } from "@/lib/api-auth";
import { decryptSecret } from "@/lib/crypto";
import { EncryptionKeyUnavailableError } from "@/lib/kms";
import { reportServerError } from "@/lib/server-errors";

export async function POST(
request: Request,
Expand DownExpand Up@@ -40,6 +41,9 @@ export async function POST(
},
});
} catch (error) {
reportServerError(error, "secrets.reveal", {
tags: { serviceId, secretId },
});
if (error instanceof EncryptionKeyUnavailableError) {
console.error("Secret encryption key unavailable:", error);
return Response.json(
Expand Down
6 changes: 6 additions & 0 deletions web/app/api/v1/agent/backup/failed/route.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,6 +6,7 @@ import { volumeBackups } from "@/db/schema";
import { verifyAgentRequest } from "@/lib/agent-auth";
import { inngest } from "@/lib/inngest/client";
import { inngestEvents } from "@/lib/inngest/events";
import { reportOperationFailure } from "@/lib/server-errors";

export async function POST(request: NextRequest) {
const body = await request.text();
Expand DownExpand Up@@ -49,6 +50,11 @@ export async function POST(request: NextRequest) {
return NextResponse.json({ ok: true });
}

reportOperationFailure("backup.failed", {
occurrenceId: backupId,
reason: "agent_reported_failure",
tags: { backupId, serviceId: backup.serviceId, serverId },
});
revalidatePath("/dashboard/projects");

await inngest.send(
Expand Down
27 changes: 27 additions & 0 deletions web/app/api/v1/agent/builds/[id]/route.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ import { cloneUrlForRevisionSource } from "@/lib/build-revision-source";
import { inngest } from "@/lib/inngest/client";
import { inngestEvents } from "@/lib/inngest/events";
import { parseServiceRevisionSpec } from "@/lib/service-revision-changes";
import { reportOperationFailure, reportServerError } from "@/lib/server-errors";
import {
DEFAULT_BUILD_TIMEOUT_MINUTES,
SETTING_KEYS,
Expand DownExpand Up@@ -68,6 +69,16 @@ export async function POST(
{ status: 409 },
);
}
reportOperationFailure("build.failed", {
occurrenceId: buildId,
reason: "claim_failed",
tags: {
buildId,
serviceId: build.serviceId,
revisionId: build.serviceRevisionId,
serverId,
},
});
await inngest.send(
inngestEvents.buildCompleted.create(
{
Expand DownExpand Up@@ -115,6 +126,14 @@ export async function POST(
try {
specification = parseServiceRevisionSpec(revision.specification);
} catch (error) {
reportServerError(error, "agent.build.claim.parse-revision", {
tags: {
buildId,
serviceId: build.serviceId,
revisionId: build.serviceRevisionId,
serverId,
},
});
console.error("[build:get] invalid service revision:", error);
return failClaim("Invalid build service revision");
}
Expand All@@ -130,6 +149,14 @@ export async function POST(
try {
cloneUrl = await cloneUrlForRevisionSource(specification.source);
} catch (error) {
reportServerError(error, "agent.build.claim.github-token", {
tags: {
buildId,
serviceId: build.serviceId,
revisionId: build.serviceRevisionId,
serverId,
},
});
console.error("[build:get] failed to get installation token:", error);
return failClaim("Failed to get GitHub installation token");
}
Expand Down
Loading
Loading