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:
@@ -72,8 +72,7 @@
|
||||
"./utils/zod/*": "./utils/zod/*.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@sentry/nextjs": "^10.11.0",
|
||||
"@sentry/nextjs": "^10.26.0",
|
||||
"@t3-oss/env-nextjs": "^0.13.4",
|
||||
"deepmerge": "^4.3.1",
|
||||
"flat": "^6.0.1",
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
// Central place for telemetry
|
||||
// TODO: Replace all of this with proper tracers and events
|
||||
|
||||
import { type Attributes, metrics } from "@opentelemetry/api"
|
||||
import * as Sentry from "@sentry/nextjs"
|
||||
import deepmerge from "deepmerge"
|
||||
import { flatten } from "flat"
|
||||
|
||||
@@ -20,7 +17,6 @@ import type { ZodError } from "zod"
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { sanitize } from '@/server/telemetry';
|
||||
*
|
||||
* const input = {
|
||||
* key1: "Example",
|
||||
@@ -43,7 +39,7 @@ import type { ZodError } from "zod"
|
||||
* // }
|
||||
* ```
|
||||
*/
|
||||
export function sanitize(data: any): Attributes {
|
||||
export function sanitize(data: any): Record<string, string | number | boolean> {
|
||||
if (!data) return {}
|
||||
if (typeof data === "string") {
|
||||
return { value: data }
|
||||
@@ -68,14 +64,8 @@ export function sanitize(data: any): Attributes {
|
||||
* See the codebase for reference usage.
|
||||
*/
|
||||
export function createCounter(meterName: string, counterName: string) {
|
||||
const meter = metrics.getMeter(meterName)
|
||||
|
||||
const fullName = `${meterName}.${counterName}`
|
||||
|
||||
const counter = meter.createCounter(fullName)
|
||||
const success = meter.createCounter(`${fullName}-success`)
|
||||
const fail = meter.createCounter(`${fullName}-fail`)
|
||||
|
||||
return {
|
||||
/**
|
||||
* Initializes the counter event handlers with a set of base attributes.
|
||||
@@ -91,12 +81,8 @@ export function createCounter(meterName: string, counterName: string) {
|
||||
*
|
||||
* @param attrs - Additional attributes specific to this 'start' event. Defaults to an empty object.
|
||||
*/
|
||||
start(attrs: object = {}) {
|
||||
const mergedAttrs = deepmerge.all<object>([baseAttrs, attrs])
|
||||
const finalAttrs = sanitize(mergedAttrs)
|
||||
|
||||
counter.add(1, finalAttrs)
|
||||
logger.debug(`[${fullName}] start`, mergedAttrs)
|
||||
start(attrs: object | undefined = undefined) {
|
||||
logger.debug(`[${fullName}] start`, attrs)
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -107,8 +93,9 @@ export function createCounter(meterName: string, counterName: string) {
|
||||
success(attrs: object = {}) {
|
||||
const mergedAttrs = deepmerge.all<object>([baseAttrs, attrs])
|
||||
const finalAttrs = sanitize(mergedAttrs)
|
||||
|
||||
success.add(1, finalAttrs)
|
||||
Sentry.metrics.count(fullName, 1, {
|
||||
attributes: { ...finalAttrs, status: "success" },
|
||||
})
|
||||
logger.debug(`[${fullName}] success`, mergedAttrs)
|
||||
},
|
||||
|
||||
@@ -132,7 +119,9 @@ export function createCounter(meterName: string, counterName: string) {
|
||||
])
|
||||
const finalAttrs = sanitize(mergedAttrs)
|
||||
|
||||
fail.add(1, finalAttrs)
|
||||
Sentry.metrics.count(fullName, 1, {
|
||||
attributes: { ...finalAttrs, status: "error" },
|
||||
})
|
||||
logger.error(`[${fullName}] dataError: ${errorMsg}`, mergedAttrs)
|
||||
},
|
||||
|
||||
@@ -154,7 +143,9 @@ export function createCounter(meterName: string, counterName: string) {
|
||||
])
|
||||
const finalAttrs = sanitize(mergedAttrs)
|
||||
|
||||
fail.add(1, finalAttrs)
|
||||
Sentry.metrics.count(fullName, 1, {
|
||||
attributes: { ...finalAttrs, status: "error" },
|
||||
})
|
||||
logger.error(`[${fullName}] noDataError:`, mergedAttrs)
|
||||
},
|
||||
|
||||
@@ -174,7 +165,9 @@ export function createCounter(meterName: string, counterName: string) {
|
||||
])
|
||||
const finalAttrs = sanitize(mergedAttrs)
|
||||
|
||||
fail.add(1, finalAttrs)
|
||||
Sentry.metrics.count(fullName, 1, {
|
||||
attributes: { ...finalAttrs, status: "error" },
|
||||
})
|
||||
logger.error(`[${fullName}] validationError`, mergedAttrs)
|
||||
},
|
||||
|
||||
@@ -198,11 +191,14 @@ export function createCounter(meterName: string, counterName: string) {
|
||||
"error.status": res.status,
|
||||
"error.statusText": res.statusText,
|
||||
"error.text": text,
|
||||
url: res.url,
|
||||
},
|
||||
])
|
||||
const finalAttrs = sanitize(mergedAttrs)
|
||||
|
||||
fail.add(1, finalAttrs)
|
||||
Sentry.metrics.count(fullName, 1, {
|
||||
attributes: { ...finalAttrs, status: "error" },
|
||||
})
|
||||
logger.error(
|
||||
`[${fullName}] httpError ${res.status}, ${res.statusText}:`,
|
||||
mergedAttrs
|
||||
@@ -235,7 +231,9 @@ export function createCounter(meterName: string, counterName: string) {
|
||||
])
|
||||
const finalAttrs = sanitize(mergedAttrs)
|
||||
|
||||
fail.add(1, finalAttrs)
|
||||
Sentry.metrics.count(fullName, 1, {
|
||||
attributes: { ...finalAttrs, status: "error" },
|
||||
})
|
||||
logger.error(`[${fullName}] fail message: ${msg}`, mergedAttrs)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { trace, type Tracer } from "@opentelemetry/api"
|
||||
import * as Sentry from "@sentry/nextjs"
|
||||
|
||||
import { getCacheClient } from "../dataCache"
|
||||
import { env } from "../env/server"
|
||||
@@ -11,24 +11,18 @@ interface ServiceTokenResponse {
|
||||
expires_in: number
|
||||
}
|
||||
|
||||
export async function getServiceToken() {
|
||||
const tracer = trace.getTracer("getServiceToken")
|
||||
|
||||
return await tracer.startActiveSpan("getServiceToken", async () => {
|
||||
export async function getServiceToken(): Promise<ServiceTokenResponse> {
|
||||
return Sentry.startSpan({ name: "getServiceToken" }, async () => {
|
||||
const scopes = env.CURITY_CLIENT_SERVICE_SCOPES
|
||||
|
||||
const cacheKey = getServiceTokenCacheKey(scopes)
|
||||
const cacheClient = await getCacheClient()
|
||||
const token = await getOrSetServiceTokenFromCache(cacheKey, scopes, tracer)
|
||||
const token = await getOrSetServiceTokenFromCache(cacheKey, scopes)
|
||||
|
||||
if (token.expiresAt < Date.now()) {
|
||||
await cacheClient.deleteKey(cacheKey)
|
||||
|
||||
const newToken = await getOrSetServiceTokenFromCache(
|
||||
cacheKey,
|
||||
scopes,
|
||||
tracer
|
||||
)
|
||||
const newToken = await getOrSetServiceTokenFromCache(cacheKey, scopes)
|
||||
return newToken.jwt
|
||||
}
|
||||
|
||||
@@ -38,16 +32,14 @@ export async function getServiceToken() {
|
||||
|
||||
async function getOrSetServiceTokenFromCache(
|
||||
cacheKey: string,
|
||||
scopes: string[],
|
||||
tracer: Tracer
|
||||
scopes: string[]
|
||||
) {
|
||||
const cacheClient = await getCacheClient()
|
||||
const token = await cacheClient.cacheOrGet(
|
||||
cacheKey,
|
||||
async () => {
|
||||
return await tracer.startActiveSpan("fetch new token", async () => {
|
||||
const newToken = await getJwt(scopes)
|
||||
return newToken
|
||||
return Sentry.startSpan({ name: "fetch new serviceToken" }, async () => {
|
||||
return await getJwt(scopes)
|
||||
})
|
||||
},
|
||||
"1h"
|
||||
@@ -56,19 +48,10 @@ async function getOrSetServiceTokenFromCache(
|
||||
}
|
||||
|
||||
async function getJwt(scopes: string[]) {
|
||||
const getJwtCounter = createCounter("tokenManager", "getJwt")
|
||||
const metricsGetJwt = getJwtCounter.init({
|
||||
scopes,
|
||||
})
|
||||
|
||||
metricsGetJwt.start()
|
||||
|
||||
const jwt = await fetchServiceToken(scopes)
|
||||
|
||||
const expiresAt = Date.now() + jwt.expires_in * 1000
|
||||
|
||||
metricsGetJwt.success()
|
||||
|
||||
return { expiresAt, jwt }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user