feat: harmonize log and metrics

This commit is contained in:
Michael Zetterberg
2025-04-17 07:16:11 +02:00
parent 858a81b16f
commit 5323a8e46e
58 changed files with 2324 additions and 4726 deletions

View File

@@ -1,7 +1,6 @@
import { metrics } from "@opentelemetry/api"
import * as api from "@/lib/api"
import { badRequestError, serverErrorByStatus } from "@/server/errors/trpc"
import { createCounter } from "@/server/telemetry"
import {
router,
safeProtectedServiceProcedure,
@@ -18,19 +17,6 @@ import {
import { bookingConfirmationSchema, createBookingSchema } from "./output"
import { getBookedHotelRoom } from "./utils"
const meter = metrics.getMeter("trpc.booking")
const getBookingCounter = meter.createCounter("trpc.booking.get")
const getBookingSuccessCounter = meter.createCounter("trpc.booking.get-success")
const getBookingFailCounter = meter.createCounter("trpc.booking.get-fail")
const getBookingStatusCounter = meter.createCounter("trpc.booking.status")
const getBookingStatusSuccessCounter = meter.createCounter(
"trpc.booking.status-success"
)
const getBookingStatusFailCounter = meter.createCounter(
"trpc.booking.status-fail"
)
export const bookingQueryRouter = router({
get: safeProtectedServiceProcedure
.input(getBookingInput)
@@ -38,7 +24,10 @@ export const bookingQueryRouter = router({
ctx,
input: { confirmationNumber, lang: inputLang },
}) {
getBookingCounter.add(1, { confirmationNumber })
const getBookingCounter = createCounter("trpc.booking", "get")
const metricsGetBooking = getBookingCounter.init({ confirmationNumber })
metricsGetBooking.start()
let lang = ctx.lang ?? inputLang
@@ -54,23 +43,7 @@ export const bookingQueryRouter = router({
)
if (!apiResponse.ok) {
const responseMessage = await apiResponse.text()
getBookingFailCounter.add(1, {
confirmationNumber,
error_type: "http_error",
error: responseMessage,
})
console.error(
"api.booking.confirmation error",
JSON.stringify({
query: { confirmationNumber },
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text: responseMessage,
},
})
)
await metricsGetBooking.httpError(apiResponse)
// If the booking is not found, return null.
// This scenario is expected to happen when a logged in user trying to access a booking that doesn't belong to them.
@@ -84,18 +57,7 @@ export const bookingQueryRouter = router({
const apiJson = await apiResponse.json()
const booking = bookingConfirmationSchema.safeParse(apiJson)
if (!booking.success) {
getBookingFailCounter.add(1, {
confirmationNumber,
error_type: "validation_error",
error: JSON.stringify(booking.error),
})
console.error(
"api.booking.confirmation validation error",
JSON.stringify({
query: { confirmationNumber },
error: booking.error,
})
)
metricsGetBooking.validationError(booking.error)
throw badRequestError()
}
@@ -109,34 +71,17 @@ export const bookingQueryRouter = router({
)
if (!hotelData) {
getBookingFailCounter.add(1, {
confirmationNumber,
hotelId: booking.data.hotelId,
error_type: "http_error",
error: "Couldn`t get hotel",
})
console.error(
"api.booking.confirmation error",
JSON.stringify({
query: { confirmationNumber, hotelId: booking.data.hotelId },
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text: "Couldn`t get hotel",
},
})
metricsGetBooking.dataError(
`Failed to get hotel data for ${booking.data.hotelId}`,
{
hotelId: booking.data.hotelId,
}
)
throw serverErrorByStatus(404)
}
getBookingSuccessCounter.add(1, { confirmationNumber })
console.info(
"api.booking.confirmation success",
JSON.stringify({
query: { confirmationNumber },
})
)
metricsGetBooking.success()
return {
...hotelData,
@@ -152,7 +97,13 @@ export const bookingQueryRouter = router({
input,
}) {
const { confirmationNumber } = input
getBookingStatusCounter.add(1, { confirmationNumber })
const getBookingStatusCounter = createCounter("trpc.booking", "status")
const metricsGetBookingStatus = getBookingStatusCounter.init({
confirmationNumber,
})
metricsGetBookingStatus.start()
const apiResponse = await api.get(
api.endpoints.v1.Booking.status(confirmationNumber),
@@ -164,52 +115,18 @@ export const bookingQueryRouter = router({
)
if (!apiResponse.ok) {
const responseMessage = await apiResponse.text()
getBookingStatusFailCounter.add(1, {
confirmationNumber,
error_type: "http_error",
error: responseMessage,
})
console.error(
"api.booking.status error",
JSON.stringify({
query: { confirmationNumber },
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text: responseMessage,
},
})
)
await metricsGetBookingStatus.httpError(apiResponse)
throw serverErrorByStatus(apiResponse.status, apiResponse)
}
const apiJson = await apiResponse.json()
const verifiedData = createBookingSchema.safeParse(apiJson)
if (!verifiedData.success) {
getBookingStatusFailCounter.add(1, {
confirmationNumber,
error_type: "validation_error",
error: JSON.stringify(verifiedData.error),
})
console.error(
"api.booking.status validation error",
JSON.stringify({
query: { confirmationNumber },
error: verifiedData.error,
})
)
metricsGetBookingStatus.validationError(verifiedData.error)
throw badRequestError()
}
getBookingStatusSuccessCounter.add(1, { confirmationNumber })
console.info(
"api.booking.status success",
JSON.stringify({
query: { confirmationNumber },
})
)
metricsGetBookingStatus.success()
return verifiedData.data
}),