2
0

🔊 Add prisma metrics to prometheus endpoint (#1420)

This commit is contained in:
Baptiste Arnaud
2024-04-06 15:08:57 +02:00
committed by GitHub
parent d96f384e02
commit 6e0388c501
9 changed files with 92 additions and 75 deletions

View File

@ -4,6 +4,7 @@ import { whatsAppRuntime } from './runtimes/whatsapp'
import { prometheus } from '@hono/prometheus' import { prometheus } from '@hono/prometheus'
import { sentry } from '@hono/sentry' import { sentry } from '@hono/sentry'
import { env } from '@typebot.io/env' import { env } from '@typebot.io/env'
import prisma from '@typebot.io/lib/prisma'
const app = new Hono() const app = new Hono()
@ -12,16 +13,21 @@ app.use(
sentry({ sentry({
environment: env.NODE_ENV, environment: env.NODE_ENV,
dsn: env.NEXT_PUBLIC_SENTRY_DSN, dsn: env.NEXT_PUBLIC_SENTRY_DSN,
release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-chat-api',
}) })
) )
const { printMetrics, registerMetrics } = prometheus() const { printMetrics, registerMetrics } = prometheus()
app.use('*', registerMetrics) app.use('*', registerMetrics)
app.get('/metrics', printMetrics) app.get('/metrics', async (c) => {
const honoMetrics = await (await printMetrics(c)).text()
const prismaMetrics = await prisma.$metrics.prometheus()
return c.text(`${honoMetrics}\n\n${prismaMetrics}`, 200)
})
app.get('/ping', (c) => c.json({ status: 'ok' }, 200)) app.get('/ping', (c) => c.json({ status: 'ok' }, 200))
app.route('/', webRuntime) app.route('/', webRuntime)
app.route('/', whatsAppRuntime) app.route('/', whatsAppRuntime)
export default { export default {

View File

@ -1,4 +1,5 @@
import prisma from '@typebot.io/lib/prisma' import prisma from '@typebot.io/lib/prisma'
import { Prisma } from '@typebot.io/prisma'
import { SessionState } from '@typebot.io/schemas' import { SessionState } from '@typebot.io/schemas'
type Props = { type Props = {
@ -6,7 +7,10 @@ type Props = {
state: SessionState state: SessionState
} }
export const createSession = async ({ id, state }: Props) => export const createSession = ({
id,
state,
}: Props): Prisma.PrismaPromise<any> =>
prisma.chatSession.create({ prisma.chatSession.create({
data: { data: {
id, id,

View File

@ -1,4 +1,5 @@
import prisma from '@typebot.io/lib/prisma' import prisma from '@typebot.io/lib/prisma'
import { Prisma } from '@typebot.io/prisma'
import { SessionState } from '@typebot.io/schemas' import { SessionState } from '@typebot.io/schemas'
type Props = { type Props = {
@ -6,7 +7,10 @@ type Props = {
state: SessionState state: SessionState
} }
export const updateSession = async ({ id, state }: Props) => export const updateSession = ({
id,
state,
}: Props): Prisma.PrismaPromise<any> =>
prisma.chatSession.updateMany({ prisma.chatSession.updateMany({
where: { id }, where: { id },
data: { data: {

View File

@ -1,4 +1,5 @@
import prisma from '@typebot.io/lib/prisma' import prisma from '@typebot.io/lib/prisma'
import { Prisma } from '@typebot.io/prisma'
import { TypebotInSession } from '@typebot.io/schemas' import { TypebotInSession } from '@typebot.io/schemas'
import { filterVariablesWithValues } from '@typebot.io/variables/filterVariablesWithValues' import { filterVariablesWithValues } from '@typebot.io/variables/filterVariablesWithValues'
@ -8,37 +9,27 @@ type Props = {
hasStarted: boolean hasStarted: boolean
isCompleted: boolean isCompleted: boolean
} }
export const upsertResult = async ({ export const upsertResult = ({
resultId, resultId,
typebot, typebot,
hasStarted, hasStarted,
isCompleted, isCompleted,
}: Props) => { }: Props): Prisma.PrismaPromise<any> => {
const existingResult = await prisma.result.findUnique({ const variablesWithValue = filterVariablesWithValues(typebot.variables)
return prisma.result.upsert({
where: { id: resultId }, where: { id: resultId },
update: {
isCompleted: isCompleted ? true : undefined,
hasStarted,
variables: variablesWithValue,
},
create: {
id: resultId,
typebotId: typebot.id,
isCompleted: isCompleted ? true : false,
hasStarted,
variables: variablesWithValue,
},
select: { id: true }, select: { id: true },
}) })
const variablesWithValue = filterVariablesWithValues(typebot.variables)
if (existingResult) {
return prisma.result.updateMany({
where: { id: resultId },
data: {
isCompleted: isCompleted ? true : undefined,
hasStarted,
variables: variablesWithValue,
},
})
}
return prisma.result.createMany({
data: [
{
id: resultId,
typebotId: typebot.id,
isCompleted: isCompleted ? true : false,
hasStarted,
variables: variablesWithValue,
},
],
})
} }

View File

@ -7,7 +7,8 @@ import { createSession } from './queries/createSession'
import { deleteSession } from './queries/deleteSession' import { deleteSession } from './queries/deleteSession'
import * as Sentry from '@sentry/nextjs' import * as Sentry from '@sentry/nextjs'
import { saveVisitedEdges } from './queries/saveVisitedEdges' import { saveVisitedEdges } from './queries/saveVisitedEdges'
import { VisitedEdge } from '@typebot.io/prisma' import { Prisma, VisitedEdge } from '@typebot.io/prisma'
import prisma from '@typebot.io/lib/prisma'
type Props = { type Props = {
session: Pick<ChatSession, 'state'> & { id?: string } session: Pick<ChatSession, 'state'> & { id?: string }
@ -36,11 +37,13 @@ export const saveStateToDatabase = async ({
!input && !containsSetVariableClientSideAction && !hasCustomEmbedBubble !input && !containsSetVariableClientSideAction && !hasCustomEmbedBubble
) )
const queries: Prisma.PrismaPromise<any>[] = []
const resultId = state.typebotsQueue[0].resultId const resultId = state.typebotsQueue[0].resultId
if (id) { if (id) {
if (isCompleted && resultId) await deleteSession(id) if (isCompleted && resultId) queries.push(deleteSession(id))
else await updateSession({ id, state }) else queries.push(updateSession({ id, state }))
} }
const session = const session =
@ -48,18 +51,23 @@ export const saveStateToDatabase = async ({
? { state, id } ? { state, id }
: await createSession({ id, state }) : await createSession({ id, state })
if (!resultId) return session if (!resultId) {
if (queries.length > 0) await prisma.$transaction(queries)
return session
}
const answers = state.typebotsQueue[0].answers const answers = state.typebotsQueue[0].answers
await upsertResult({ queries.push(
resultId, upsertResult({
typebot: state.typebotsQueue[0].typebot, resultId,
isCompleted: Boolean( typebot: state.typebotsQueue[0].typebot,
!input && !containsSetVariableClientSideAction && answers.length > 0 isCompleted: Boolean(
), !input && !containsSetVariableClientSideAction && answers.length > 0
hasStarted: answers.length > 0, ),
}) hasStarted: answers.length > 0,
})
)
if (logs && logs.length > 0) if (logs && logs.length > 0)
try { try {
@ -75,7 +83,9 @@ export const saveStateToDatabase = async ({
Sentry.captureException(e) Sentry.captureException(e)
} }
if (visitedEdges.length > 0) await saveVisitedEdges(visitedEdges) if (visitedEdges.length > 0) queries.push(saveVisitedEdges(visitedEdges))
await prisma.$transaction(queries)
return session return session
} }

View File

@ -1,5 +1,6 @@
generator client { generator client {
provider = "prisma-client-js" provider = "prisma-client-js"
previewFeatures = ["metrics"]
} }
datasource db { datasource db {

View File

@ -14,12 +14,12 @@
"db:migrate": "pnpm migrate:deploy" "db:migrate": "pnpm migrate:deploy"
}, },
"dependencies": { "dependencies": {
"@prisma/client": "5.8.0" "@prisma/client": "5.12.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "20.4.2", "@types/node": "20.4.2",
"dotenv-cli": "7.2.1", "dotenv-cli": "7.2.1",
"prisma": "5.8.0", "prisma": "5.12.1",
"@typebot.io/tsconfig": "workspace:*", "@typebot.io/tsconfig": "workspace:*",
"tsx": "3.12.7", "tsx": "3.12.7",
"typescript": "5.3.2" "typescript": "5.3.2"

View File

@ -1,5 +1,6 @@
generator client { generator client {
provider = "prisma-client-js" provider = "prisma-client-js"
previewFeatures = ["metrics"]
} }
datasource db { datasource db {

56
pnpm-lock.yaml generated
View File

@ -1751,8 +1751,8 @@ importers:
packages/prisma: packages/prisma:
dependencies: dependencies:
'@prisma/client': '@prisma/client':
specifier: 5.8.0 specifier: 5.12.1
version: 5.8.0(prisma@5.8.0) version: 5.12.1(prisma@5.12.1)
devDependencies: devDependencies:
'@typebot.io/tsconfig': '@typebot.io/tsconfig':
specifier: workspace:* specifier: workspace:*
@ -1764,8 +1764,8 @@ importers:
specifier: 7.2.1 specifier: 7.2.1
version: 7.2.1 version: 7.2.1
prisma: prisma:
specifier: 5.8.0 specifier: 5.12.1
version: 5.8.0 version: 5.12.1
tsx: tsx:
specifier: 3.12.7 specifier: 3.12.7
version: 3.12.7 version: 3.12.7
@ -7848,8 +7848,8 @@ packages:
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
dev: false dev: false
/@prisma/client@5.8.0(prisma@5.8.0): /@prisma/client@5.12.1(prisma@5.12.1):
resolution: {integrity: sha512-QxO6C4MaA/ysTIbC+EcAH1aX/YkpymhXtO6zPdk+FvA7+59tNibIYpd+7koPdViLg2iKES4ojsxWNUGNJaEcbA==} resolution: {integrity: sha512-6/JnizEdlSBxDIdiLbrBdMW5NqDxOmhXAJaNXiPpgzAPr/nLZResT6MMpbOHLo5yAbQ1Vv5UU8PTPRzb0WIxdA==}
engines: {node: '>=16.13'} engines: {node: '>=16.13'}
requiresBuild: true requiresBuild: true
peerDependencies: peerDependencies:
@ -7858,35 +7858,35 @@ packages:
prisma: prisma:
optional: true optional: true
dependencies: dependencies:
prisma: 5.8.0 prisma: 5.12.1
dev: false dev: false
/@prisma/debug@5.8.0: /@prisma/debug@5.12.1:
resolution: {integrity: sha512-ZqPpkvbovu/kQJ1bvy57NO4dw97fpQGcbQSCtsqlwSE1UNKJP75R3BKxdznk8ZPMY+GJdMRetWNv4oAvSbWn8Q==} resolution: {integrity: sha512-kd/wNsR0klrv79o1ITsbWxYyh4QWuBidvxsXSParPsYSu0ircUmNk3q4ojsgNc3/81b0ozg76iastOG43tbf8A==}
/@prisma/engines-version@5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848: /@prisma/engines-version@5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab:
resolution: {integrity: sha512-cXcoVweYbnv8xRfkWq9oj8BECOdzHUazrSpYCa0ehp5TNz4l5Spa8jbq/VROCTzj3ZncH5D9Q2TmySYTOUeKlw==} resolution: {integrity: sha512-6yvO8s80Tym61aB4QNtYZfWVmE3pwqe807jEtzm8C5VDe7nw8O1FGX3TXUaXmWV0fQTIAfRbeL2Gwrndabp/0g==}
/@prisma/engines@5.8.0: /@prisma/engines@5.12.1:
resolution: {integrity: sha512-Qhqm9WWLujNEC13AuZlUO14SQ15tNLe5puaz+tOk7UqINqJ3PtqMmuSuzomiw2diGVqZ+HYiSQzlR3+pPucVHA==} resolution: {integrity: sha512-HQDdglLw2bZR/TXD2Y+YfDMvi5Q8H+acbswqOsWyq9pPjBLYJ6gzM+ptlTU/AV6tl0XSZLU1/7F4qaWa8bqpJA==}
requiresBuild: true requiresBuild: true
dependencies: dependencies:
'@prisma/debug': 5.8.0 '@prisma/debug': 5.12.1
'@prisma/engines-version': 5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848 '@prisma/engines-version': 5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab
'@prisma/fetch-engine': 5.8.0 '@prisma/fetch-engine': 5.12.1
'@prisma/get-platform': 5.8.0 '@prisma/get-platform': 5.12.1
/@prisma/fetch-engine@5.8.0: /@prisma/fetch-engine@5.12.1:
resolution: {integrity: sha512-1CAuE+JoYsPNggMEn6qk0zos06Uc9bYZBJ0VBPHD6R7REL05614koAbOCmn52IaYz3nobb7f25hqW6AY7rLkIw==} resolution: {integrity: sha512-qSs3KcX1HKcea1A+hlJVK/ljj0PNIUHDxAayGMvgJBqmaN32P9tCidlKz1EGv6WoRFICYnk3Dd/YFLBwnFIozA==}
dependencies: dependencies:
'@prisma/debug': 5.8.0 '@prisma/debug': 5.12.1
'@prisma/engines-version': 5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848 '@prisma/engines-version': 5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab
'@prisma/get-platform': 5.8.0 '@prisma/get-platform': 5.12.1
/@prisma/get-platform@5.8.0: /@prisma/get-platform@5.12.1:
resolution: {integrity: sha512-Nk3rhTFZ1LYkFZJnpSvQcLPCaBWgJQfteHII6UEENOOkYlmP0k3FuswND54tzzEr4qs39wOdV9pbXKX9U2lv7A==} resolution: {integrity: sha512-pgIR+pSvhYHiUcqXVEZS31NrFOTENC9yFUdEAcx7cdQBoZPmHVjtjN4Ss6NzVDMYPrKJJ51U14EhEoeuBlMioQ==}
dependencies: dependencies:
'@prisma/debug': 5.8.0 '@prisma/debug': 5.12.1
/@radix-ui/colors@1.0.1: /@radix-ui/colors@1.0.1:
resolution: {integrity: sha512-xySw8f0ZVsAEP+e7iLl3EvcBXX7gsIlC1Zso/sPBW9gIWerBTgz6axrjU+MZ39wD+WFi5h5zdWpsg3+hwt2Qsg==} resolution: {integrity: sha512-xySw8f0ZVsAEP+e7iLl3EvcBXX7gsIlC1Zso/sPBW9gIWerBTgz6axrjU+MZ39wD+WFi5h5zdWpsg3+hwt2Qsg==}
@ -19692,13 +19692,13 @@ packages:
react: 18.2.0 react: 18.2.0
dev: false dev: false
/prisma@5.8.0: /prisma@5.12.1:
resolution: {integrity: sha512-hDKoEqPt2qEUTH5yGO3l27CBnPtwvte0CGMKrpCr9+/A919JghfqJ3qgCGgMbOwdkXUOzdho0RH9tyUF3UhpMw==} resolution: {integrity: sha512-SkMnb6wyIxTv9ACqiHBI2u9gD6y98qXRoCoLEnZsF6yee5Qg828G+ARrESN+lQHdw4maSZFFSBPPDpvSiVTo0Q==}
engines: {node: '>=16.13'} engines: {node: '>=16.13'}
hasBin: true hasBin: true
requiresBuild: true requiresBuild: true
dependencies: dependencies:
'@prisma/engines': 5.8.0 '@prisma/engines': 5.12.1
/prismjs@1.29.0: /prismjs@1.29.0:
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}