Skip to content

Add prisma debug logs #2458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
204 changes: 135 additions & 69 deletions apps/web/lib/api/links/create-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { recordLink } from "@/lib/tinybird";
import { ProcessedLinkProps } from "@/lib/types";
import { propagateWebhookTriggerChanges } from "@/lib/webhook/update-webhook";
import { prisma } from "@dub/prisma";
import { Prisma } from "@dub/prisma/client";
import { Prisma, PrismaClient } from "@dub/prisma/client";
import {
APP_DOMAIN_WITH_NGROK,
R2_URL,
Expand All @@ -23,6 +23,11 @@ import { includeTags } from "./include-tags";
import { updateLinksUsage } from "./update-links-usage";
import { transformLink } from "./utils";

// Debug-enabled Prisma client for link operations (temporary for testing)
const debugPrisma = new PrismaClient({
log: ["query", "info", "warn", "error"],
});

export async function createLink(link: ProcessedLinkProps) {
let {
key,
Expand Down Expand Up @@ -51,87 +56,148 @@ export async function createLink(link: ProcessedLinkProps) {
key,
});

const response = await prisma.link.create({
data: {
...rest,
id: createId({ prefix: "link_" }),
key,
shortLink: linkConstructorSimple({ domain: link.domain, key }),
title: truncate(title, 120),
description: truncate(description, 240),
// if it's an uploaded image, make this null first because we'll update it later
image: proxy && image && isNotHostedImage(image) ? null : image,
utm_source,
utm_medium,
utm_campaign,
utm_term,
utm_content,
expiresAt: expiresAt ? new Date(expiresAt) : null,
geo: geo || Prisma.JsonNull,

testVariants: testVariants || Prisma.JsonNull,
testCompletedAt: testCompletedAt ? new Date(testCompletedAt) : null,
testStartedAt: testStartedAt ? new Date(testStartedAt) : null,

// Associate tags by tagNames
...(tagNames?.length &&
link.projectId && {
tags: {
create: tagNames.map((tagName, idx) => ({
tag: {
connect: {
name_projectId: {
name: tagName,
projectId: link.projectId as string,
process.env.DEBUG = "prisma:client,prisma:engine";

const response = await debugPrisma.link
.create({
data: {
...rest,
id: createId({ prefix: "link_" }),
key,
shortLink: linkConstructorSimple({ domain: link.domain, key }),
title: truncate(title, 120),
description: truncate(description, 240),
// if it's an uploaded image, make this null first because we'll update it later
image: proxy && image && isNotHostedImage(image) ? null : image,
utm_source,
utm_medium,
utm_campaign,
utm_term,
utm_content,
expiresAt: expiresAt ? new Date(expiresAt) : null,
geo: geo || Prisma.JsonNull,

testVariants: testVariants || Prisma.JsonNull,
testCompletedAt: testCompletedAt ? new Date(testCompletedAt) : null,
testStartedAt: testStartedAt ? new Date(testStartedAt) : null,

// Associate tags by tagNames
...(tagNames?.length &&
link.projectId && {
tags: {
create: tagNames.map((tagName, idx) => ({
tag: {
connect: {
name_projectId: {
name: tagName,
projectId: link.projectId as string,
},
},
},
},
createdAt: new Date(new Date().getTime() + idx * 100), // increment by 100ms for correct order
})),
},
}),

// Associate tags by IDs (takes priority over tagNames)
...(combinedTagIds &&
combinedTagIds.length > 0 && {
tags: {
createMany: {
data: combinedTagIds.map((tagId, idx) => ({
tagId,
createdAt: new Date(new Date().getTime() + idx * 100), // increment by 100ms for correct order
})),
},
},
}),
}),

// Webhooks
...(webhookIds &&
webhookIds.length > 0 && {
webhooks: {
createMany: {
data: webhookIds.map((webhookId) => ({
webhookId,
})),
// Associate tags by IDs (takes priority over tagNames)
...(combinedTagIds &&
combinedTagIds.length > 0 && {
tags: {
createMany: {
data: combinedTagIds.map((tagId, idx) => ({
tagId,
createdAt: new Date(new Date().getTime() + idx * 100), // increment by 100ms for correct order
})),
},
},
}),

// Webhooks
...(webhookIds &&
webhookIds.length > 0 && {
webhooks: {
createMany: {
data: webhookIds.map((webhookId) => ({
webhookId,
})),
},
},
}),

// Shared dashboard
...(publicStats && {
dashboard: {
create: {
id: createId({ prefix: "dash_" }),
projectId: link.projectId,
userId: link.userId,
},
},
}),
},
include: {
...includeTags,
webhooks: webhookIds ? true : false,
},
})
.catch((error) => {
// Only log enhanced details for timeout/connection related errors
const isTimeoutError =
error.code === "P1017" || // Connection pool timeout
error.code === "P1001" || // Can't reach database server
error.code === "P1008" || // Operations timed out
error.message?.toLowerCase().includes("timeout") ||
error.message?.toLowerCase().includes("connection") ||
error.message?.toLowerCase().includes("fetch failed");

// Shared dashboard
...(publicStats && {
dashboard: {
create: {
id: createId({ prefix: "dash_" }),
if (isTimeoutError) {
// Enhanced error logging for timeout/connection issues
const errorDetails = {
message: error.message,
name: error.name,
code: error.code,
stack: error.stack,
timestamp: new Date().toISOString(),
operation: "prisma.link.create",
linkData: {
domain: link.domain,
key: key,
projectId: link.projectId,
userId: link.userId,
},
},
}),
},
include: {
...includeTags,
webhooks: webhookIds ? true : false,
},
});
// Capture any additional Prisma/database specific error properties
...(error.meta && { meta: error.meta }),
...(error.clientVersion && { clientVersion: error.clientVersion }),
// Include original error object for full context
originalError: error,
};

console.error(
"TIMEOUT/CONNECTION Error creating link:",
JSON.stringify(errorDetails, null, 2),
);

// Also log a more readable version
console.error(`Link creation TIMEOUT/CONNECTION failure:
Operation: ${errorDetails.operation}
Error: ${errorDetails.name} - ${errorDetails.message}
Code: ${errorDetails.code || "N/A"}
Domain: ${errorDetails.linkData.domain}
Key: ${errorDetails.linkData.key}
ProjectId: ${errorDetails.linkData.projectId}
Timestamp: ${errorDetails.timestamp}
`);
} else {
// Basic logging for other errors
console.error("Error creating link (non-timeout):", {
message: error.message,
code: error.code,
operation: "prisma.link.create",
});
}

throw error;
});

const uploadedImageUrl = `${R2_URL}/images/${response.id}`;

Expand Down