Merged in chore/upgrade-sentry (pull request #3191)

feat: upgrade sentry and use metrics

* feat: upgrade sentry and use metrics

* remove ununsed deps

* rename span

* .


Approved-by: Linus Flood
This commit is contained in:
Joakim Jäderberg
2025-11-20 13:24:53 +00:00
parent 5eaaea527f
commit b1d7fbad88
14 changed files with 510 additions and 470 deletions

View File

@@ -0,0 +1,71 @@
import { describe, expect, it } from "vitest"
import { flattenInput } from "./flattenInput"
describe("flattenInput", () => {
it("should return undefined for null input", () => {
expect(flattenInput(null)).toBeUndefined()
})
it("should return undefined for non-object input", () => {
expect(flattenInput("string")).toBeUndefined()
expect(flattenInput(123)).toBeUndefined()
expect(flattenInput(true)).toBeUndefined()
})
it("should return undefined for empty object", () => {
expect(flattenInput({})).toBeUndefined()
})
it("should return undefined for object with no primitive values", () => {
expect(flattenInput({ nested: { deep: "value" } })).toBeUndefined()
expect(flattenInput({ arr: [1, 2, 3] })).toBeUndefined()
expect(flattenInput({ fn: () => {} })).toBeUndefined()
})
it("should flatten object with primitive values", () => {
const input = {
name: "test",
age: 25,
active: true,
}
const result = flattenInput(input)
expect(result).toEqual({
"input.name": "test",
"input.age": 25,
"input.active": true,
})
})
it("should filter out non-primitive values and flatten remaining", () => {
const input = {
name: "test",
count: 42,
nested: { deep: "value" },
valid: false,
array: [1, 2, 3],
}
const result = flattenInput(input)
expect(result).toEqual({
"input.name": "test",
"input.count": 42,
"input.valid": false,
})
})
it("should handle mixed primitive types", () => {
const input = {
str: "hello",
num: 0,
bool: false,
negNum: -5,
}
const result = flattenInput(input)
expect(result).toEqual({
"input.str": "hello",
"input.num": 0,
"input.bool": false,
"input.negNum": -5,
})
})
})

View File

@@ -0,0 +1,29 @@
import { flatten } from "flat"
export function flattenInput(
input: unknown
): Record<string, unknown> | undefined {
if (typeof input !== "object" || input === null) {
return undefined
}
const onlyPrimitives = Object.entries(input).reduce(
(acc, [key, value]) => {
if (
typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean"
) {
acc[key] = value
}
return acc
},
{} as Record<string, unknown>
)
if (onlyPrimitives && Object.keys(onlyPrimitives).length === 0) {
return undefined
}
return flatten({ input: onlyPrimitives })
}

View File

@@ -0,0 +1,28 @@
import * as Sentry from "@sentry/nextjs"
import { middleware } from "../../."
import { flattenInput } from "./flattenInput"
export const durationMiddleware = middleware(
async ({ path, type, next, getRawInput }) => {
const perf = performance.now()
const res = await next()
const duration = performance.now() - perf
const input = await getRawInput()
const primitiveInput = flattenInput(input)
Sentry.metrics.distribution("trpc", duration, {
unit: "milliseconds",
attributes: {
path,
type,
status: res.ok ? "ok" : "error",
error: res.ok ? undefined : res.error.code,
...primitiveInput,
},
})
return res
}
)

View File

@@ -0,0 +1,9 @@
import * as Sentry from "@sentry/nextjs"
import { middleware } from ".."
export const sentryMiddleware = middleware(
Sentry.trpcMiddleware({
attachRpcInput: true,
})
)

View File

@@ -1,10 +1,10 @@
import * as Sentry from "@sentry/nextjs"
import { Lang } from "@scandic-hotels/common/constants/language"
import { logger } from "@scandic-hotels/common/logger"
import { getServiceToken } from "@scandic-hotels/common/tokenManager"
import { env } from "../env/server"
import { durationMiddleware } from "./middlewares/durationMiddleware"
import { sentryMiddleware } from "./middlewares/sentryMiddleware"
import {
badRequestError,
internalServerError,
@@ -12,15 +12,11 @@ import {
unauthorizedError,
} from "./errors"
import { langInput } from "./utils"
import { middleware, procedure } from "."
import { procedure } from "."
const sentryMiddleware = middleware(
Sentry.trpcMiddleware({
attachRpcInput: true,
})
)
export const baseProcedure = procedure.use(sentryMiddleware)
export const baseProcedure = procedure
.use(sentryMiddleware)
.use(durationMiddleware)
export const publicProcedure = baseProcedure