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:
@@ -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,
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -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 })
|
||||
}
|
||||
28
packages/trpc/lib/middlewares/durationMiddleware/index.ts
Normal file
28
packages/trpc/lib/middlewares/durationMiddleware/index.ts
Normal 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
|
||||
}
|
||||
)
|
||||
9
packages/trpc/lib/middlewares/sentryMiddleware.ts
Normal file
9
packages/trpc/lib/middlewares/sentryMiddleware.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as Sentry from "@sentry/nextjs"
|
||||
|
||||
import { middleware } from ".."
|
||||
|
||||
export const sentryMiddleware = middleware(
|
||||
Sentry.trpcMiddleware({
|
||||
attachRpcInput: true,
|
||||
})
|
||||
)
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user