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

@@ -2,6 +2,7 @@ import { type NextRequest, NextResponse } from "next/server"
import { env } from "@/env/server"
import { dt } from "@/lib/dt"
import { createCounter } from "@/server/telemetry"
import {
getEntries,
@@ -13,22 +14,16 @@ import {
} from "@/utils/sitemap"
import { contentstackSync } from "./sync"
import {
generateSitemapCounter,
generateSitemapFailCounter,
generateSitemapSuccessCounter,
saveEntriesCounter,
saveSitemapDataCounter,
saveSyncTokenCounter,
} from "./telemetry"
import { mapEntriesToSitemapData, mergeEntries } from "./utils"
export const dynamic = "force-dynamic"
export async function GET(request: NextRequest) {
const generateSitemapCounter = createCounter("sitemap", "generate")
const metricsGenerateSitemap = generateSitemapCounter.init()
try {
generateSitemapCounter.add(1)
console.info("sitemap.generate start")
metricsGenerateSitemap.start()
const headersList = request.headers
const secret = headersList.get("x-sitemap-sync-secret")
@@ -44,49 +39,46 @@ export async function GET(request: NextRequest) {
const responseData = await contentstackSync(syncToken)
const mergedEntries = mergeEntries(currentEntries, responseData.entries)
saveEntriesCounter.add(1, { entriesCount: mergedEntries.length })
console.info(
"sitemap.entries.save",
JSON.stringify({ entriesCount: mergedEntries.length })
)
const entriesSaveCounter = createCounter("sitemap", "entries.save")
const metricsEntriesSave = entriesSaveCounter.init({
entriesCount: mergedEntries.length,
})
metricsEntriesSave.start()
await saveEntries(mergedEntries)
metricsEntriesSave.success()
const sitemapData = mapEntriesToSitemapData(mergedEntries)
const lastUpdated = dt().utc().format()
saveSitemapDataCounter.add(1, {
const saveDataCounter = createCounter("sitemap", "data.save")
const metricsDataSave = saveDataCounter.init({
sitemapEntriesCount: sitemapData.length,
lastUpdated,
})
console.info(
"sitemap.data.save",
JSON.stringify({
sitemapEntriesCount: sitemapData.length,
lastUpdated,
})
)
metricsDataSave.start()
await saveSitemapData(sitemapData)
await saveLastUpdatedDate(lastUpdated)
metricsDataSave.success()
if (syncToken !== responseData.syncToken) {
saveSyncTokenCounter.add(1, {
const syncTokenSaveCounter = createCounter("sitemap", "syncToken.save")
const metricsSyncTokenSave = syncTokenSaveCounter.init({
syncToken: responseData.syncToken,
})
console.info(
"sitemap.synctoken.save",
JSON.stringify({ syncToken: responseData.syncToken })
)
metricsSyncTokenSave.start()
await saveSyncToken(responseData.syncToken)
metricsSyncTokenSave.success()
}
generateSitemapSuccessCounter.add(1)
metricsGenerateSitemap.success()
return NextResponse.json({
message: "Sitemap data generated and stored successfully!",
now: dt().utc().format(),
})
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : JSON.stringify(error)
generateSitemapFailCounter.add(1, { error: errorMessage })
console.error("sitemap.generate.fail", errorMessage)
metricsGenerateSitemap.fail(error)
return NextResponse.json(
{

View File

@@ -1,13 +1,7 @@
import { Region, Stack } from "contentstack"
import { env } from "@/env/server"
import {
syncEntriesCounter,
syncEntriesFailCounter,
syncEntriesPaginationCounter,
syncEntriesSuccessCounter,
} from "./telemetry"
import { createCounter } from "@/server/telemetry"
import type { SyncResponse } from "@/types/sitemap"
@@ -24,72 +18,50 @@ export async function contentstackSync(syncToken: string | null) {
const entries = []
const syncOptions = syncToken ? { sync_token: syncToken } : { init: true }
syncEntriesCounter.add(1, {
const entriesSyncCounter = createCounter("sitemap", "entries.sync")
const metricsEntriesSync = entriesSyncCounter.init({
environment,
...syncOptions,
})
console.info(
"sitemap.entries.sync start",
JSON.stringify({
environment,
...syncOptions,
})
)
metricsEntriesSync.start()
try {
let syncResponse: SyncResponse = await stack.sync(syncOptions)
entries.push(...syncResponse.items)
const entriesSyncPaginationCounter = createCounter(
"sitemap",
"entries.sync.pagination"
)
const metricsEntriesSyncPagination = entriesSyncPaginationCounter.init({
environment,
...syncOptions,
})
// Check if there is a pagination token, and fetch more data if needed
while (syncResponse.pagination_token && !syncResponse.sync_token) {
syncEntriesPaginationCounter.add(1, {
environment,
metricsEntriesSyncPagination.start({
paginationToken: syncResponse.pagination_token,
})
console.info(
"sitemap.entries.sync.pagination start",
JSON.stringify({
environment,
paginationToken: syncResponse.pagination_token,
})
)
syncResponse = await stack.sync({
pagination_token: syncResponse.pagination_token,
})
entries.push(...syncResponse.items)
syncEntriesPaginationCounter.add(1, {
environment,
metricsEntriesSyncPagination.success({
paginationToken: syncResponse.pagination_token,
entriesCount: syncResponse.items.length,
})
console.info(
"sitemap.entries.sync.pagination success",
JSON.stringify({
environment,
paginationToken: syncResponse.pagination_token,
entriesCount: syncResponse.items.length,
})
)
}
if (syncResponse.sync_token) {
syncEntriesSuccessCounter.add(1, {
environment,
...syncOptions,
metricsEntriesSync.success({
newSyncToken: syncResponse.sync_token,
entriesCount: entries.length,
})
console.info(
"sitemap.entries.sync success",
JSON.stringify({
environment,
...syncOptions,
newSyncToken: syncResponse.sync_token,
entriesCount: entries.length,
})
)
return {
syncToken: syncResponse.sync_token,
entries,
@@ -98,14 +70,7 @@ export async function contentstackSync(syncToken: string | null) {
throw new Error("No sync token received, something went wrong")
}
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : JSON.stringify(error)
syncEntriesFailCounter.add(1, {
environment,
...syncOptions,
error: errorMessage,
})
console.error("sitemap.entries.sync error", errorMessage)
metricsEntriesSync.fail(error)
throw new Error("Failed to sync entries")
}

View File

@@ -1,43 +0,0 @@
import { metrics } from "@opentelemetry/api"
const meter = metrics.getMeter("sitemap")
// OpenTelemetry metrics
export const generateSitemapCounter = meter.createCounter("sitemap.generate")
export const generateSitemapSuccessCounter = meter.createCounter(
"sitemap.generate-success"
)
export const generateSitemapFailCounter = meter.createCounter(
"sitemap.generate-fail"
)
export const syncEntriesCounter = meter.createCounter("sitemap.entries.sync")
export const syncEntriesSuccessCounter = meter.createCounter(
"sitemap.entries.sync-success"
)
export const syncEntriesFailCounter = meter.createCounter(
"sitemap.entries.sync-fail"
)
export const syncEntriesPaginationCounter = meter.createCounter(
"sitemap.entries.sync.pagination"
)
export const syncEntriesPaginationSuccessCounter = meter.createCounter(
"sitemap.entries.sync.pagination-success"
)
export const mergeEntriesCounter = meter.createCounter("sitemap.entries.merge")
export const mergeEntriesSuccessCounter = meter.createCounter(
"sitemap.entries.merge-success"
)
export const saveEntriesCounter = meter.createCounter("sitemap.entries.save")
export const transformEntriesCounter = meter.createCounter(
"sitemap.entries.transform"
)
export const transformEntriesSuccessCounter = meter.createCounter(
"sitemap.entries.transform-success"
)
export const saveSitemapDataCounter = meter.createCounter("sitemap.data.save")
export const saveSyncTokenCounter = meter.createCounter(
"sitemap.synctoken.save"
)

View File

@@ -1,32 +1,23 @@
import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import { createCounter } from "@/server/telemetry"
import { removeTrailingSlash } from "@/utils/url"
import {
mergeEntriesCounter,
mergeEntriesSuccessCounter,
transformEntriesCounter,
transformEntriesSuccessCounter,
} from "./telemetry"
import type { SitemapEntry, SyncItem } from "@/types/sitemap"
export function mergeEntries(
currentEntries: SyncItem[],
newEntries: SyncItem[]
) {
mergeEntriesCounter.add(1, {
const entriesMergeCounter = createCounter("sitemap", "entries.merge")
const metricsEntriesMerge = entriesMergeCounter.init({
currentEntriesCount: currentEntries.length,
newEntriesCount: newEntries.length,
})
console.info(
"sitemap.entries.merge start",
JSON.stringify({
currentEntriesCount: currentEntries.length,
newEntriesCount: newEntries.length,
})
)
metricsEntriesMerge.start()
const entries = [...currentEntries]
newEntries.forEach((entry) => {
const index = entries.findIndex(
@@ -40,27 +31,20 @@ export function mergeEntries(
}
})
mergeEntriesSuccessCounter.add(1, {
metricsEntriesMerge.success({
entriesCount: entries.length,
})
console.info(
"sitemap.entries.merge success",
JSON.stringify({
entriesCount: entries.length,
})
)
return entries
}
export function mapEntriesToSitemapData(entries: SyncItem[]) {
transformEntriesCounter.add(1, { entriesCount: entries.length })
console.info(
"sitemap.entries.transform start",
JSON.stringify({
entriesCount: entries.length,
})
)
const entriesTransformCounter = createCounter("sitemap", "entries.transform")
const metricsEntriesTransform = entriesTransformCounter.init({
entriesCount: entries.length,
})
metricsEntriesTransform.start()
const filteredEntries = filterEntriesToSitemapEntries(entries)
@@ -69,17 +53,10 @@ export function mapEntriesToSitemapData(entries: SyncItem[]) {
.map(([_, entries]) => mapEntriesToSitemapEntry(entries))
.filter((entry): entry is SitemapEntry => !!entry)
transformEntriesSuccessCounter.add(1, {
metricsEntriesTransform.success({
entriesCount: entries.length,
sitemapEntriesCount: sitemapEntries.length,
})
console.info(
"sitemap.entries.transform success",
JSON.stringify({
entriesCount: entries.length,
sitemapEntriesCount: sitemapEntries.length,
})
)
return sitemapEntries
}