feat(api): add sentry capture
This commit is contained in:
parent
455be06a95
commit
8a1bbbc67b
@ -10,6 +10,7 @@
|
|||||||
"@boring.tools/logger": "workspace:*",
|
"@boring.tools/logger": "workspace:*",
|
||||||
"@boring.tools/schema": "workspace:*",
|
"@boring.tools/schema": "workspace:*",
|
||||||
"@hono/clerk-auth": "^2.0.0",
|
"@hono/clerk-auth": "^2.0.0",
|
||||||
|
"@hono/sentry": "^1.2.0",
|
||||||
"@hono/zod-openapi": "^0.16.2",
|
"@hono/zod-openapi": "^0.16.2",
|
||||||
"@scalar/hono-api-reference": "^0.5.149",
|
"@scalar/hono-api-reference": "^0.5.149",
|
||||||
"hono": "^4.6.3",
|
"hono": "^4.6.3",
|
||||||
|
@ -43,7 +43,6 @@ export const func = async ({ userId, id }: { userId: string; id: string }) => {
|
|||||||
if (!result) {
|
if (!result) {
|
||||||
throw new HTTPException(404, { message: 'Not found' })
|
throw new HTTPException(404, { message: 'Not found' })
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { logger } from '@boring.tools/logger'
|
|
||||||
import { OpenAPIHono } from '@hono/zod-openapi'
|
import { OpenAPIHono } from '@hono/zod-openapi'
|
||||||
import { HTTPException } from 'hono/http-exception'
|
|
||||||
import type { Variables } from '..'
|
import type { Variables } from '..'
|
||||||
import { verifyAuthentication } from '../utils/authentication'
|
import { verifyAuthentication } from '../utils/authentication'
|
||||||
|
import { type ContextModule, captureSentry } from '../utils/sentry'
|
||||||
import ById from './byId'
|
import ById from './byId'
|
||||||
import Create from './create'
|
import Create from './create'
|
||||||
import Delete from './delete'
|
import Delete from './delete'
|
||||||
@ -11,7 +10,9 @@ import Update from './update'
|
|||||||
|
|
||||||
const app = new OpenAPIHono<{ Variables: Variables }>()
|
const app = new OpenAPIHono<{ Variables: Variables }>()
|
||||||
|
|
||||||
const changelog_logger = logger.child({ name: 'changelog' })
|
const module: ContextModule = {
|
||||||
|
name: 'changelog',
|
||||||
|
}
|
||||||
|
|
||||||
app.openapi(ById.route, async (c) => {
|
app.openapi(ById.route, async (c) => {
|
||||||
const userId = verifyAuthentication(c)
|
const userId = verifyAuthentication(c)
|
||||||
@ -20,11 +21,14 @@ app.openapi(ById.route, async (c) => {
|
|||||||
const result = await ById.func({ userId, id })
|
const result = await ById.func({ userId, id })
|
||||||
return c.json(result, 200)
|
return c.json(result, 200)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
changelog_logger.error(error)
|
return captureSentry({
|
||||||
if (error instanceof HTTPException) {
|
c,
|
||||||
return c.json({ message: error.message }, error.status)
|
error,
|
||||||
}
|
module,
|
||||||
return c.json({ message: 'An unexpected error occurred' }, 500)
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -34,11 +38,14 @@ app.openapi(List.route, async (c) => {
|
|||||||
const result = await List.func({ userId })
|
const result = await List.func({ userId })
|
||||||
return c.json(result, 200)
|
return c.json(result, 200)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
changelog_logger.error(error)
|
return captureSentry({
|
||||||
if (error instanceof HTTPException) {
|
c,
|
||||||
return c.json({ message: error.message }, error.status)
|
error,
|
||||||
}
|
module,
|
||||||
return c.json({ message: 'An unexpected error occurred' }, 500)
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -52,11 +59,14 @@ app.openapi(Create.route, async (c) => {
|
|||||||
})
|
})
|
||||||
return c.json(result, 201)
|
return c.json(result, 201)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
changelog_logger.error(error)
|
return captureSentry({
|
||||||
if (error instanceof HTTPException) {
|
c,
|
||||||
return c.json({ message: error.message }, error.status)
|
error,
|
||||||
}
|
module,
|
||||||
return c.json({ message: 'An unexpected error occurred' }, 500)
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -73,11 +83,14 @@ app.openapi(Delete.route, async (c) => {
|
|||||||
|
|
||||||
return c.json({ message: 'Changelog removed' })
|
return c.json({ message: 'Changelog removed' })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
changelog_logger.error(error)
|
return captureSentry({
|
||||||
if (error instanceof HTTPException) {
|
c,
|
||||||
return c.json({ message: error.message }, error.status)
|
error,
|
||||||
}
|
module,
|
||||||
return c.json({ message: 'An unexpected error occurred' }, 500)
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -103,11 +116,14 @@ app.openapi(Update.route, async (c) => {
|
|||||||
|
|
||||||
return c.json(result)
|
return c.json(result)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
changelog_logger.error(error)
|
return captureSentry({
|
||||||
if (error instanceof HTTPException) {
|
c,
|
||||||
return c.json({ message: error.message }, error.status)
|
error,
|
||||||
}
|
module,
|
||||||
return c.json({ message: 'An unexpected error occurred' }, 500)
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { logger } from '@boring.tools/logger'
|
|
||||||
import { OpenAPIHono } from '@hono/zod-openapi'
|
import { OpenAPIHono } from '@hono/zod-openapi'
|
||||||
import { HTTPException } from 'hono/http-exception'
|
|
||||||
import type { Variables } from '../..'
|
import type { Variables } from '../..'
|
||||||
import { verifyAuthentication } from '../../utils/authentication'
|
import { verifyAuthentication } from '../../utils/authentication'
|
||||||
|
import { type ContextModule, captureSentry } from '../../utils/sentry'
|
||||||
import { byId, byIdFunc } from './byId'
|
import { byId, byIdFunc } from './byId'
|
||||||
import { create, createFunc } from './create'
|
import { create, createFunc } from './create'
|
||||||
import { remove, removeFunc } from './delete'
|
import { remove, removeFunc } from './delete'
|
||||||
@ -10,7 +9,10 @@ import { update, updateFunc } from './update'
|
|||||||
|
|
||||||
const app = new OpenAPIHono<{ Variables: Variables }>()
|
const app = new OpenAPIHono<{ Variables: Variables }>()
|
||||||
|
|
||||||
const version_logger = logger.child({ name: 'changelog_version' })
|
const module: ContextModule = {
|
||||||
|
name: 'changelog',
|
||||||
|
sub_module: 'version',
|
||||||
|
}
|
||||||
|
|
||||||
app.openapi(create, async (c) => {
|
app.openapi(create, async (c) => {
|
||||||
const userId = verifyAuthentication(c)
|
const userId = verifyAuthentication(c)
|
||||||
@ -24,11 +26,14 @@ app.openapi(create, async (c) => {
|
|||||||
|
|
||||||
return c.json(result, 201)
|
return c.json(result, 201)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
version_logger.error(error)
|
return captureSentry({
|
||||||
if (error instanceof HTTPException) {
|
c,
|
||||||
return c.json({ message: error.message }, error.status)
|
error,
|
||||||
}
|
module,
|
||||||
return c.json({ message: 'An unexpected error occurred' }, 500)
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -56,11 +61,14 @@ app.openapi(byId, async (c) => {
|
|||||||
200,
|
200,
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
version_logger.error(error)
|
return captureSentry({
|
||||||
if (error instanceof HTTPException) {
|
c,
|
||||||
return c.json({ message: error.message }, error.status)
|
error,
|
||||||
}
|
module,
|
||||||
return c.json({ message: 'An unexpected error occurred' }, 500)
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -81,17 +89,20 @@ app.openapi(update, async (c) => {
|
|||||||
|
|
||||||
return c.json(result)
|
return c.json(result)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
version_logger.error(error)
|
return captureSentry({
|
||||||
if (error instanceof HTTPException) {
|
c,
|
||||||
return c.json({ message: error.message }, error.status)
|
error,
|
||||||
}
|
module,
|
||||||
return c.json({ message: 'An unexpected error occurred' }, 500)
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
app.openapi(remove, async (c) => {
|
app.openapi(remove, async (c) => {
|
||||||
|
const userId = verifyAuthentication(c)
|
||||||
try {
|
try {
|
||||||
const userId = verifyAuthentication(c)
|
|
||||||
const id = c.req.param('id')
|
const id = c.req.param('id')
|
||||||
const result = await removeFunc({ userId, id })
|
const result = await removeFunc({ userId, id })
|
||||||
|
|
||||||
@ -101,11 +112,14 @@ app.openapi(remove, async (c) => {
|
|||||||
|
|
||||||
return c.json({ message: 'Version removed' })
|
return c.json({ message: 'Version removed' })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
version_logger.error(error)
|
return captureSentry({
|
||||||
if (error instanceof HTTPException) {
|
c,
|
||||||
return c.json({ message: error.message }, error.status)
|
error,
|
||||||
}
|
module,
|
||||||
return c.json({ message: 'An unexpected error occurred' }, 500)
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import type { UserOutput } from '@boring.tools/schema'
|
import type { UserOutput } from '@boring.tools/schema'
|
||||||
|
import { sentry } from '@hono/sentry'
|
||||||
import { OpenAPIHono, type z } from '@hono/zod-openapi'
|
import { OpenAPIHono, type z } from '@hono/zod-openapi'
|
||||||
import { apiReference } from '@scalar/hono-api-reference'
|
import { apiReference } from '@scalar/hono-api-reference'
|
||||||
import { cors } from 'hono/cors'
|
import { cors } from 'hono/cors'
|
||||||
@ -18,6 +19,12 @@ export type Variables = {
|
|||||||
|
|
||||||
export const app = new OpenAPIHono<{ Variables: Variables }>()
|
export const app = new OpenAPIHono<{ Variables: Variables }>()
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
'*',
|
||||||
|
sentry({
|
||||||
|
dsn: 'https://1d7428bbab0a305078cf4aa380721aa2@o4508167321354240.ingest.de.sentry.io/4508167323648080',
|
||||||
|
}),
|
||||||
|
)
|
||||||
app.use('*', cors())
|
app.use('*', cors())
|
||||||
app.use('/v1/*', authentication)
|
app.use('/v1/*', authentication)
|
||||||
|
|
||||||
|
@ -1,23 +1,29 @@
|
|||||||
import { logger } from '@boring.tools/logger'
|
import { logger } from '@boring.tools/logger'
|
||||||
import { OpenAPIHono } from '@hono/zod-openapi'
|
import { OpenAPIHono } from '@hono/zod-openapi'
|
||||||
import { HTTPException } from 'hono/http-exception'
|
|
||||||
import { Webhook } from 'svix'
|
import { Webhook } from 'svix'
|
||||||
import type { Variables } from '..'
|
import type { Variables } from '..'
|
||||||
|
import { type ContextModule, captureSentry } from '../utils/sentry'
|
||||||
import get from './get'
|
import get from './get'
|
||||||
import webhook from './webhook'
|
import webhook from './webhook'
|
||||||
|
|
||||||
const app = new OpenAPIHono<{ Variables: Variables }>()
|
const app = new OpenAPIHono<{ Variables: Variables }>()
|
||||||
|
|
||||||
|
const module: ContextModule = {
|
||||||
|
name: 'user',
|
||||||
|
}
|
||||||
|
|
||||||
app.openapi(get.route, async (c) => {
|
app.openapi(get.route, async (c) => {
|
||||||
|
const user = c.get('user')
|
||||||
try {
|
try {
|
||||||
const user = c.get('user')
|
|
||||||
const result = await get.func({ user })
|
const result = await get.func({ user })
|
||||||
return c.json(result, 201)
|
return c.json(result, 201)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof HTTPException) {
|
return captureSentry({
|
||||||
return c.json({ message: error.message }, error.status)
|
c,
|
||||||
}
|
error,
|
||||||
return c.json({ message: 'An unexpected error occurred' }, 500)
|
module,
|
||||||
|
user,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -31,11 +37,11 @@ app.openapi(webhook.route, async (c) => {
|
|||||||
logger.info('Clerk Webhook', result)
|
logger.info('Clerk Webhook', result)
|
||||||
return c.json(result, 200)
|
return c.json(result, 200)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Clert Webhook', error)
|
return captureSentry({
|
||||||
if (error instanceof HTTPException) {
|
c,
|
||||||
return c.json({ message: error.message }, error.status)
|
error,
|
||||||
}
|
module,
|
||||||
return c.json({ message: 'An unexpected error occurred' }, 500)
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
37
apps/api/src/utils/sentry.ts
Normal file
37
apps/api/src/utils/sentry.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { logger } from '@boring.tools/logger'
|
||||||
|
import type { Context } from 'hono'
|
||||||
|
import { HTTPException } from 'hono/http-exception'
|
||||||
|
|
||||||
|
export type ContextModule = {
|
||||||
|
name: string
|
||||||
|
sub_module?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContextUser = {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const route_logger = logger.child({ name: 'hono' })
|
||||||
|
|
||||||
|
export const captureSentry = ({
|
||||||
|
c,
|
||||||
|
user,
|
||||||
|
module,
|
||||||
|
error,
|
||||||
|
}: {
|
||||||
|
c: Context
|
||||||
|
user?: ContextUser
|
||||||
|
module: ContextModule
|
||||||
|
error: unknown
|
||||||
|
}) => {
|
||||||
|
route_logger.error(error)
|
||||||
|
|
||||||
|
c.get('sentry').setContext('module', module)
|
||||||
|
c.get('sentry').setContext('user', user)
|
||||||
|
c.get('sentry').captureException(error)
|
||||||
|
|
||||||
|
if (error instanceof HTTPException) {
|
||||||
|
return c.json({ message: error.message }, error.status)
|
||||||
|
}
|
||||||
|
return c.json({ message: 'An unexpected error occurred' }, 500)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user