Mundarija (35)
- Bu darsda
- 1. Nega bu kerak?
- 2. Xato qayerda yuz beradi va kim ushlaydi
- 2.1 Beshta joy
- 2.2 Xatoning yo'li
- 3. Biz ishga tushirdik: kim nimani ko'radi
- 3.1 Tajriba
- 3.2 Foydalanuvchi ko'rgani
- 3.3 Brauzer konsoli
- 3.4 Server logi
- 3.5 Dev rejimida-chi?
- 4. Digest bo'yicha qidirish
- 5. instrumentation.ts
- 5.1 Fayl va ikki funksiya
- 5.2 Qatorma-qator
- 5.3 Uchinchi parametr: kontekst
- 5.4 register() va server ishga tushishi
- 5.5 Biz topdik: Edge ogohlantirishi
- 6. Logda sir bo'lmasin
- 6.1 Muammo
- 6.2 Jonli: sirni yashirish
- 7. Server loglari qayerga boradi
- 8. Sentry Next.js'da (hujjat bo'yicha)
- 9. Brauzer tomoni: instrumentation-client.ts
- 10. OpenTelemetry (ko'rsatkich)
- 11. Portfolio qadami: instrumentation.ts (holat 37)
- 12. Ko'p uchraydigan xatolar
- 13. Mashqlar
- 1-mashq (oson): kim nimani ko'radi?
- 2-mashq (o'rta): kengroq yashirish
- 3-mashq (qiyin): xatolar hisoboti
- 4-mashq: Portfolio qadami
- 14. Real ishda
- Xulosa
- Manbalar
Next.js xatolar va loglar: error.tsx, digest va instrumentation.ts
Qisqacha: Server Component, Server Action yoki Route Handler'da xato bo'lsa, foydalanuvchi uni ko'rmaydi — production'da brauzerga faqat digest (xato raqami) boradi,
error.tsxshu raqamni ko'rsatadi. Xatoning to'liq matni serverda qoladi. Uni ushlash uchun loyiha ildizidainstrumentation.tsfayli yoziladi:register()server ishga tushganda bir marta,onRequestError()esa har server xatosida chaqiriladi. U yerda xato JSON qatori qilib logga yoziladi yoki Sentry kabi xizmatga yuboriladi. Digest — brauzerdagi xabar bilan serverdagi log yozuvini bog'laydigan kalit.
Bu darsda
- Next.js ilovasida xato qayerlarda yuz berishini va har birini kim ushlashini sanab bera olasiz.
- Production'da foydalanuvchi, brauzer konsoli va server logi nimani ko'rishini haqiqiy tajriba chiqishi bilan solishtirasiz.
instrumentation.tsni yozasiz:registervaonRequestError, ularning parametrlari va Edge tuzog'i.- Digest bo'yicha log yozuvini topasiz va logdan sirlarni yashirishni o'rganasiz.
@sentry/nextjs,instrumentation-client.tsva OpenTelemetry qanday ulanishini hujjat bo'yicha bilib olasiz.
Oldin bilishingiz kerak: Maxsus fayllar: loading, error, not-found, Xatolarni kuzatish: Sentry frontendda, Streaming va Suspense, Server Components.
1. Nega bu kerak?
Aziz portfolio ni internetga chiqardi. Bir kuni do'sti Telegram'da yozdi: "Saytingda «Nimadir buzildi» chiqdi". Qaysi sahifada? Qachon? Nima buzildi? Aziz o'z kompyuterida ochib ko'radi — hammasi ishlayapti.
Sentry darsida bu muammoni SPA uchun hal qilgandingiz: xato brauzerda bo'ladi, window.onerror uni ushlaydi va yuboradi. Next.js'da kodning yarmi serverda ishlaydi. Server Component'dagi xato brauzerga umuman yetib bormaydi. Brauzerdagi kuzatuvchi uni ko'rmaydi.
O'xshatish: restoran. Mijoz (brauzer) faqat zalni ko'radi. Oshxonada (server) qozon kuydi. Ofitsiant mijozga "kechirasiz, taom tayyor emas" deydi — oshxona tafsilotini aytmaydi. Lekin oshpaz daftarga yozishi kerak: qaysi qozon, qachon, nima uchun. Aks holda ertaga yana kuyadi. error.tsx — ofitsiantning gapi, instrumentation.ts — oshxona daftari.
2. Xato qayerda yuz beradi va kim ushlaydi
2.1 Beshta joy
| Qayerda | Misol | Foydalanuvchiga | Logga |
|---|---|---|---|
| Server Component render | ma'lumot o'qishda throw |
error.tsx |
onRequestError |
| Server Action | forma yuborishda xato | error.tsx yoki action natijasi |
onRequestError |
| Route Handler | GET ichida xato |
500 javob | onRequestError |
proxy.ts |
proxy ichida xato | 500 javob | onRequestError |
| Client Component | tugma bosilganda xato | error.tsx |
brauzer kuzatuvi |
Birinchi to'rttasi — serverda. Ularning hammasi bitta joyga keladi: onRequestError. Oxirgisi — brauzerda, uni Sentry darsidagi usul (yoki pastdagi instrumentation-client.ts) ushlaydi.
2.2 Xatoning yo'li
Server Component'da xato bo'lganda nima bo'lishini diagrammada kuzating. E'tibor bering: server ikki tomonga ikki xil narsa yuboradi.
sequenceDiagram
participant B as Brauzer
participant S as Next server
participant L as Log
B->>S: GET /sinov-xato
S->>S: render — throw Error
S->>L: onRequestError: matn + digest
S-->>B: HTML oqimi + faqat digest
B->>B: error.tsx: «Xato kodi: 938972021»Logga — to'liq matn va digest. Brauzerga — faqat digest. Ikkalasini bog'laydigan narsa — o'sha raqam.
Tekshirib ko'ring: Route Handler (
app/api/.../route.ts) da xato bo'lsa,error.tsxko'rinadimi?
Javob
Yo'q. error.tsx — React komponentlar daraxtidagi xato chegarasi (error boundary) (Maxsus fayllar), u faqat sahifa chizilayotganda ishlaydi. Route Handler sahifa emas, u JSON yoki matn qaytaradi — xato bo'lsa, Next 500 javob beradi. Lekin onRequestError uni ham ushlaydi (routeType: "route").
3. Biz ishga tushirdik: kim nimani ko'radi
3.1 Tajriba
portfolio (holat 37) ga vaqtincha sinov sahifasi qo'shdik. U Suspense ichida xato tashlaydi, xato matnida esa "sir" bor:
import { connection } from "next/server";
import { Suspense } from "react";
async function Xato(): Promise<React.ReactNode> {
await connection();
throw new Error("Maxfiy ichki tafsilot: DB parol=xxx");
}
export default function SinovXato() {
return (
<main id="asosiy">
<Suspense fallback={<p>…</p>}>
<Xato />
</Suspense>
</main>
);
}connection() — sahifani so'rov vaqtida chizishga majburlaydi (Streaming darsida ko'rgansiz). Aks holda xato build vaqtida chiqib, build yiqilardi. Keyin next build va next start, sahifani headless Chrome'da ochdik.
3.2 Foydalanuvchi ko'rgani
Sahifadagi <main> matni:
status 200
main: Nimadir buzildi | Sahifani ko'rsatib bo'lmadi. Qayta urinib ko'ring. | Xato kodi: 938972021 | Qayta urinishBu — kanondagi error.tsx (Maxsus fayllar darsida yozilgan). "parol" so'zi yo'q, faqat raqam. Ikki narsaga qarang.
Birinchisi — status 200. Xato bor, lekin javob kodi "hammasi joyida". Sabab: Suspense bilan sahifa oqim bo'lib ketadi. Server sarlavhani va sahifa qobig'ini allaqachon yuborgan, xato esa keyinroq, oqim o'rtasida chiqdi. Yuborilgan statusni qaytarib bo'lmaydi. Shuning uchun xatoni status kodidan emas, logdan bilasiz.
Ikkinchisi — Xato kodi: 938972021. Bu digest (inglizcha "qisqa mazmun") — server xatoga bergan raqam. Siz qilgan tajribada boshqa raqam chiqadi: digest xato matni va stack'dan hisoblanadi.
3.3 Brauzer konsoli
[konsol error] Error: Minified React error #441; visit https://react.dev/errors/441 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.Production'da React xabarlarni qisqartiradi va o'rniga raqam qo'yadi. 441-raqamning to'liq matni (React manba kodida):
An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error.Tarjimasi: "Server Components render'ida xato yuz berdi. Maxfiy tafsilot oqib ketmasligi uchun aniq xabar production build'da yashirildi. Xato obyektida digest xususiyati bor — u xato tabiati haqida qo'shimcha ma'lumot berishi mumkin". Ya'ni brauzer konsolida ham sir yo'q.
3.4 Server logi
next start ishlab turgan terminal:
⨯ Error: Maxfiy ichki tafsilot: DB parol=xxx
at e (C:\Users\…\p\.next\server\chunks\ssr\[root-of-the-server]__0ywulexpgu8dq._.js:1:1547) {
digest: '938972021'
}
{"tur":"server-xato","digest":"938972021","xabar":"Maxfiy ichki tafsilot: DB parol=xxx","yol":"/sinov-xato","metod":"GET","route":"/[locale]/sinov-xato","turi":"render","sabab":"react-server-components"}Ikki yozuv. Birinchisini Next o'zi chiqaradi (⨯ belgisi bilan): xato matni, stack va digest. Ikkinchisi — bizning onRequestError yozgan bitta JSON qator. Unda xuddi shu digest — 938972021.
Uch tomonni yonma-yon qo'ysak:
| Kim | Xato matni | Digest |
|---|---|---|
| Foydalanuvchi ekrani | yo'q | 938972021 |
| Brauzer konsoli | yo'q (React #441) | obyekt ichida |
| Server logi | to'liq | 938972021 |
3.5 Dev rejimida-chi?
next dev da xulq boshqacha: Next hujjatiga ko'ra, dev'da brauzerga ketgan Error obyektida asl message bo'ladi — tuzatish oson bo'lishi uchun. Shuning uchun dev'da "hammasi ko'rinadi", production'da esa yashirinadi. Xato sahifangizni albatta next build + next start da ham ko'ring.
Tekshirib ko'ring: Foydalanuvchi sizga «Xato kodi: 938972021» ni skrinshot qilib yubordi. Uni qayerdan qidirasiz va nimani topasiz?
Javob
Server logidan — "digest":"938972021" bo'lgan qatorni. U yerda to'liq xato matni, yo'l (/sinov-xato), metod va qaysi marshrut fayli ekani bor. Digest — xuddi buyurtma raqami: mijoz faqat raqamni biladi, oshxona daftarida esa hamma tafsilot.
4. Digest bo'yicha qidirish
Logda minglab qator bo'ladi. Har biri — bitta JSON obyekt. Shuning uchun qidirish oson: har qatorni JSON.parse qilib, kerakli maydonni solishtirasiz. «Ishga tushir» ni bosing:
const logLines = [
'{"tur":"server-start","runtime":"nodejs"}',
'{"tur":"server-xato","digest":"938972021","yol":"/sinov-xato"}',
'{"tur":"server-xato","digest":"1377524367","yol":"/blog"}',
];
function findByDigest(lines, digest) {
return lines
.map((line) => JSON.parse(line))
.filter((entry) => entry.digest === digest);
}
const found = findByDigest(logLines, "938972021");
console.log(found.length); // 1
console.log(found[0].yol); // /sinov-xatoAgar log oddiy matn bo'lganida ("16:42 da /sinov-xato sahifasida xato bo'ldi…"), har yozuvni qo'lda o'qishga to'g'ri kelardi. JSON qator — tuzilgan log (structured log): har ma'lumot o'z nomli maydonida. Log xizmatlari (Vercel Logs, Grafana Loki, Datadog) aynan shunday qatorlarni maydon bo'yicha filtrlaydi.
5. instrumentation.ts
5.1 Fayl va ikki funksiya
Instrumentation (asboblash) — ilovaga kuzatuv "datchiklari"ni o'rnatish. Mashinaning priborlar paneli kabi: dvigatel o'zi ishlaydi, panel esa ichida nima bo'layotganini ko'rsatadi.
Next.js'da buning uchun loyiha ildizida (bizda src/ ichida) instrumentation.ts fayli yoziladi. U ikki funksiyani eksport qilishi mumkin, ikkalasi ham ixtiyoriy:
| Funksiya | Qachon chaqiriladi |
|---|---|
register() |
Server ishga tushganda bir marta, birinchi so'rovdan oldin |
onRequestError() |
Har server xatosida |
Kanondagi fayl (holat 37):
import type { Instrumentation } from "next";
// instrumentation.ts (N-37): server ishga tushganda bir marta
// register(), har server xatosida onRequestError.
export function register() {
console.info(
JSON.stringify({
tur: "server-start",
runtime: process.env.NEXT_RUNTIME,
}),
);
}
export const onRequestError: Instrumentation.onRequestError = (
xato,
sorov,
kontekst,
) => {
const digest =
typeof xato === "object" && xato !== null && "digest" in xato
? String(xato.digest)
: undefined;
console.error(
JSON.stringify({
tur: "server-xato",
digest,
xabar: xato instanceof Error ? xato.message : String(xato),
yol: sorov.path,
metod: sorov.method,
route: kontekst.routePath,
turi: kontekst.routeType,
sabab: kontekst.renderSource,
}),
);
};Kanon kodida izoh uch qatorli va bitta uzun qator bor; bu yerda telefonga sig'ishi uchun qisqartirildi, kod o'zgarmagan. Kanonning qolgan izohi: "tashqi xizmat (Sentry) kalit va hisob talab qiladi, shuning uchun faqat JSON log; brauzer xatoni faqat digest bilan ko'radi".
5.2 Qatorma-qator
| Qism | Nima qiladi |
|---|---|
Instrumentation.onRequestError |
Next'ning tayyor turi — uchta parametr turini o'zi beradi |
process.env.NEXT_RUNTIME |
"nodejs" yoki "edge" — kod qaysi runtime'da ishlayotgani |
xato — unknown |
throw istalgan narsani tashlashi mumkin, avval tekshiramiz |
"digest" in xato |
React xatoga qo'ygan raqamni o'qish |
xato instanceof Error |
Matnni faqat haqiqiy Error dan olish |
console.error(JSON.stringify(…)) |
Bitta qator JSON — tuzilgan log |
xato nega unknown? JavaScript'da throw "satr" yoki throw 42 ham yoziladi. TypeScript'da catch dagi qiymat ham shuning uchun unknown (TypeScript: unknown). Avval tekshirib, keyin xususiyatni o'qiysiz — bu toraytirish.
5.3 Uchinchi parametr: kontekst
Next hujjatidagi tur bo'yicha kontekst da quyidagilar bor:
| Maydon | Qiymatlar | Ma'nosi |
|---|---|---|
routerKind |
"App Router", "Pages Router" |
Qaysi router |
routePath |
"/[locale]/sinov-xato" |
Marshrut fayli yo'li (manzil emas) |
routeType |
render, route, action, proxy |
Sahifa, Route Handler, Server Action yoki proxy |
renderSource |
react-server-components … |
Render'ning qaysi bosqichi |
Ikkinchi parametr — sorov: path (haqiqiy manzil, query bilan), method, headers. Bizning logda yol: "/sinov-xato" (foydalanuvchi ochgan manzil) va route: "/[locale]/sinov-xato" (fayl) — ikkalasi ham kerak. Birinchisi "qayerda", ikkinchisi "qaysi kodda".
headers ni butunligicha logga yozmang: unda cookie bor — sessiya tokeni. Kanon faqat kerakli maydonlarni oladi.
5.4 register() va server ishga tushishi
next start chiqishi (biz ishga tushirdik):
▲ Next.js 16.4.0
- Local: http://localhost:3291
- Network: http://172.30.224.1:3291
✓ Ready in 626ms
✓ Running next.config.ts took 77ms
{"tur":"server-start","runtime":"nodejs"}Oxirgi qator — register(). U so'rovlar boshlanishidan oldin ishlaydi. Shuning uchun bu yerda kuzatuv vositalari ishga tushiriladi: Sentry'ni init qilish, OpenTelemetry'ni ulash. register async bo'lishi mumkin — server u tugashini kutadi.
5.5 Biz topdik: Edge ogohlantirishi
Kanon dastlab register() da Node versiyasini ham yozgan edi: node: process.version. Build shunday dedi (biz qayta ishga tushirdik, chiqish qisqartirildi):
Turbopack build encountered 1 warning:
./src/instrumentation.ts:11:13
Warning: A Node.js API is used (process.version at line: 11) which is not supported in the Edge Runtime.
Learn more: https://nextjs.org/docs/api-reference/edge-runtimeTarjimasi: "Node.js API ishlatilgan (11-qatorda process.version), Edge Runtime buni qo'llamaydi". Lekin bizda Edge yo'q-ku? Sabab: instrumentation.ts ikkala runtime uchun ham yig'iladi — Next uni Node server uchun ham, Edge uchun ham tayyorlaydi. Build muvaffaqiyatli tugadi (exit 0), server ishga tushganda logda "node":"v24.21.0" chiqdi. Ya'ni Node'da ishlaydi, faqat ogohlantirish qoladi.
Kanon process.version ni olib tashladi — ogohlantirishsiz build toza. Agar Node'ga xos kod (masalan node:fs) haqiqatan kerak bo'lsa, Next hujjati shart bilan ajratishni tavsiya qiladi:
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
await import("./instrumentation.node");
}
}Node va Edge farqini Runtime'lar darsida batafsil ko'ramiz.
Tekshirib ko'ring:
onRequestErrorichida xatoni tashqi xizmatgafetchbilan yubormoqchisiz. Nimaga e'tibor berasiz?
Javob
fetch ni await qilish kerak — Next hujjati shuni talab qiladi: funksiya async bo'lsa, ichidagi vazifalar kutilsin, aks holda server ularni tugatmasdan javobni yopishi mumkin. Yana: tashqi manzilga ulanish — tarmoq vaqti va xavfi (manzil, kalit). Kanon buni qilmaydi, faqat stdout'ga yozadi.
6. Logda sir bo'lmasin
6.1 Muammo
Tajribadagi log qatoriga qayta qarang: "xabar":"Maxfiy ichki tafsilot: DB parol=xxx". Brauzerga sir ketmadi — bu yaxshi. Lekin logga ketdi. Log ham joy: uni ko'p odam o'qiydi, tashqi xizmatga yuboriladi, oylab saqlanadi. Sentry darsida "Nima KIRMASLIGI kerak" degan ro'yxat bor edi: parol, token, karta raqami, shaxsiy ma'lumot. Server loglariga ham shu qoida.
Eng to'g'ri yo'l — xato matniga sirni umuman yozmaslik. Lekin kutubxona xatolari (DB drayveri, HTTP klient) ba'zan ulanish satrini xabarga qo'shib yuboradi. Shuning uchun logga yozishdan oldin xavfli qismlarni yashirish odatiy himoya.
6.2 Jonli: sirni yashirish
maskSecrets funksiyasi kalit=qiymat ko'rinishidagi xavfli kalitlarni topib, qiymatni *** ga almashtiradi. Muntazam ifodalar — 12-qismdan:
const SECRET_KEYS = /(parol|password|token|secret)=([^\s&]+)/gi;
function maskSecrets(text) {
return text.replace(SECRET_KEYS, "$1=***");
}
function makeLogLine(error, path) {
return JSON.stringify({
tur: "server-xato",
xabar: maskSecrets(error.message),
yol: path,
});
}
const error = new Error("Maxfiy ichki tafsilot: DB parol=xxx");
console.log(makeLogLine(error, "/sinov-xato"));Konsolda:
{"tur":"server-xato","xabar":"Maxfiy ichki tafsilot: DB parol=***","yol":"/sinov-xato"}$1 — birinchi qavsdagi topilgan qism (kalit nomi), u saqlanadi; qiymat esa yulduzchaga aylanadi. Bunday ro'yxat hech qachon to'liq bo'lmaydi — u faqat ikkinchi himoya qatlami. Birinchisi — sirni xabarga yozmaslik.
7. Server loglari qayerga boradi
console.info va console.error — Node jarayonining standart chiqishlari: stdout (oddiy chiqish) va stderr (xatolar oqimi). Next ularni hech qayerga saqlamaydi. Kim saqlashi — ilova qayerda ishlashiga bog'liq:
| Qayerda ishlaydi | Loglar qayerda |
|---|---|
next dev, next start |
Terminal oynasi — yopsangiz, yo'qoladi |
| Vercel | Loyiha panelidagi Logs bo'limi (muddati tarifga bog'liq) |
| O'z server (VPS) | Jarayon menejeri yoki Docker logi |
Vercel'ni Deploy I: Vercel darsida, o'z serverni esa keyingi qismlarda ko'rasiz. Hozir bitta qoida yetadi: log faqat terminalda qolsa — u yo'q bilan teng. Production'da loglar yig'iladigan joy bo'lishi kerak.
Log darajalari:
| Usul | Oqim | Qachon |
|---|---|---|
console.info |
stdout | Muhim, lekin oddiy hodisa (server ishga tushdi) |
console.warn |
stderr | G'alati, lekin ishlaydi (zaxira ma'lumot ishlatildi) |
console.error |
stderr | Xato — kimdir qarashi kerak |
console.log |
stdout | Tuzatish vaqtida; production'ga qoldirilmaydi |
Kanonda after() bilan spam urinishlari ham shunday JSON qatorlar bo'lib yoziladi (Request API'lar) — javobni kutdirmasdan.
8. Sentry Next.js'da (hujjat bo'yicha)
Kanonda Sentry yo'q: u hisob va DSN (loyiha kaliti) talab qiladi, biz hisob ochmadik. Quyidagi tartib — Sentry va Next hujjatlari bo'yicha, biz sinab ko'rmadik.
SPA'da bitta @sentry/react va bitta init yetardi. Next'da uchta muhit bor — brauzer, Node server, Edge — shuning uchun @sentry/nextjs paketi uchta joyga ulanadi:
| Fayl | Nima qiladi |
|---|---|
instrumentation-client.ts |
Brauzerda Sentry.init — client xatolari |
instrumentation.ts |
register() da server init; onRequestError = Sentry.captureRequestError |
next.config.ts |
withSentryConfig(...) — build'da source map yuklash |
Sentry'ning sozlash ustasi (npx @sentry/wizard@latest -i nextjs) bu fayllarni o'zi yaratadi. Ko'rib turganingizdek, Sentry ham aynan biz yozgan onRequestError ga ulanadi — kanon kodini almashtirish bitta qatorga teng.
Ikki narx, ular kanonda o'lchanmagan:
- CSP. Kanon CSP'sida
connect-src 'self'— brauzer faqat o'z saytiga so'rov yuboradi (next.config chuqur). Sentry'ga xato yuborish uchun uning manzilini qo'shish kerak. - Hajm. Client SDK brauzerga qo'shimcha JS olib keladi. Sentry darsida bu raqam o'lchangan edi; Next'da ham client qismi shunga yaqin.
9. Brauzer tomoni: instrumentation-client.ts
Server xatolari — instrumentation.ts. Brauzerdagilar uchun Next'da alohida fayl bor: instrumentation-client.ts. U ilova interaktiv bo'lishidan oldin brauzerda bir marta bajariladi. Hujjatdagi misol:
// instrumentation-client.ts
performance.mark("app-init");
window.addEventListener("error", (event) => {
reportError(event.error);
});
export function onRouterTransitionStart(
url: string,
navigationType: "push" | "replace" | "traverse",
) {
console.log(url, navigationType);
}Bu yerda eksport shart emas — fayl shunchaki ishga tushadi. Yagona maxsus eksport — onRouterTransitionStart: har client navigatsiya boshlanganda chaqiriladi (analitika uchun qulay). reportError — sizning yuborish funksiyangiz o'rni.
Kanonda bu fayl yo'q: brauzer xatolarini yuboradigan joy (xizmat) yo'q, error.tsx esa client xatolarini ham ekranda ushlaydi. Sentry darsidagi o'z xato yozuvi naqshini shu faylga ko'chirish mumkin.
10. OpenTelemetry (ko'rsatkich)
Xato — kuzatuvning bir qismi. Ikkinchi savol: "sahifa nega sekin?". Buning uchun OpenTelemetry (OTel) — kuzatuv ma'lumotlarining ochiq standarti ishlatiladi. U so'rov yo'lini span (oraliq) larga bo'ladi: "sahifa render — 40 ms", uning ichida "GitHub API'ga fetch — 35 ms".
Next o'zi bir qancha span chiqaradi (so'rov, render, fetch). Ularni yoqish uchun hujjatda tavsiya qilingan yo'l:
import { registerOTel } from "@vercel/otel";
export function register() {
registerOTel({ serviceName: "portfolio" });
}Span'lar keyin kollektorga (Jaeger, Grafana Tempo, Vercel) yuboriladi. Kanonda OTel yo'q — portfolio'da sekin so'rov yo'q (TTFB 4–12 ms). Bu mavzu backend qismlarida, ko'p xizmatli tizimlarda haqiqiy ahamiyat kasb etadi. Hozir nomini va joyini bilish yetarli: u ham register() ga ulanadi.
11. Portfolio qadami: instrumentation.ts (holat 37)
Holat 37 uchta darsga bo'lingan: bu dars, next.config chuqur va Env o'zgaruvchilar. Hozir commit qilmang — commit uchinchi darsda.
Bu darsning ulushi bitta fayl:
| Fayl | Nima |
|---|---|
src/instrumentation.ts |
register() — server-start qatori; onRequestError — tuzilgan JSON (digest, xabar, yo'l, metod, route, tur, sabab) |
error.tsx va global-error.tsx Maxsus fayllar darsidan beri bor va o'zgarmaydi: ular digest'ni ko'rsatadi, bu dars esa uni logga bog'laydi.
Tekshiruv: npm run build ogohlantirishsiz (process.version yo'q), npm run start dan keyin terminalda {"tur":"server-start","runtime":"nodejs"} chiqadi. Kanon o'lchovi: JS hajmi o'zgarmadi — instrumentation serverda ishlaydi, brauzerga kirmaydi.
12. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| Xato sahifasi bor, lekin logda hech narsa yo'q | instrumentation.ts noto'g'ri joyda |
src/ bo'lsa — src/instrumentation.ts, bo'lmasa ildizda |
A Node.js API is used … not supported in the Edge Runtime |
Node API instrumentation'da | Olib tashlang yoki NEXT_RUNTIME === "nodejs" sharti bilan import |
| Xato sahifasi chiqdi, status 200 | Xato oqim boshlangandan keyin | Kutilgan xulq; xatoni logdan kuzating |
| Dev'da xabar ko'rinadi, prod'da yo'q | Production xabarni yashiradi | To'g'ri xulq; digest bo'yicha logdan qidiring |
| Logda parol yoki token | Xabar yoki headers butunligicha yozilgan |
Faqat kerakli maydonlar + yashirish |
onRequestError dagi fetch ishlamay qoldi |
await qilinmagan |
Funksiyani async qilib, await qiling |
13. Mashqlar
Mashqlar kurs/mashqlar/23/35-xatolar-loglar/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.
1-mashq (oson): kim nimani ko'radi?
- Production'da foydalanuvchi ekranida xatoning to'liq matni ko'rinadimi?
- Brauzer va server logini bog'laydigan raqam nomi —
- Server ishga tushganda bir marta chaqiriladigan funksiya —
- Har server xatosida chaqiriladigan funksiya —
- Server Action'dagi xatoda
kontekst.routeTypeqiymati —
Yechim
- yo'q — production'da faqat digest boradi (React #441 xabari).
- digest — xato matni va stack'dan hisoblangan raqam; logda ham,
error.tsxda ham bir xil. - register — birinchi so'rovdan oldin, bir marta.
- onRequestError — server tomonidagi har xatoda: render, Route Handler, Server Action, proxy.
- action —
routeTypening to'rt qiymati:render,route,action,proxy.
2-mashq (o'rta): kengroq yashirish
«Sirni yashirish» blokidagi maskSecrets ni kengaytiring: u Bearer abc123 kabi tokenlarni ham Bearer *** ga almashtirsin. Keyin uchta xabarni sinang: "DB parol=xxx", "Authorization: Bearer abc123", "token=t1&page=2". Natijada page=2 saqlanishi kerak.
Yechim
const SECRET_KEYS = /(parol|password|token|secret)=([^\s&]+)/gi;
const BEARER = /Bearer\s+\S+/g;
function maskSecrets(text) {
return text
.replace(SECRET_KEYS, "$1=***")
.replace(BEARER, "Bearer ***");
}
console.log(maskSecrets("DB parol=xxx"));
console.log(maskSecrets("Authorization: Bearer abc123"));
console.log(maskSecrets("token=t1&page=2"));Konsolda:
DB parol=***
Authorization: Bearer ***
token=***&page=2[^\s&]+ — qiymat bo'sh joy yoki & gacha davom etadi, shuning uchun &page=2 tegilmaydi. Ikkinchi qoida alohida replace — bitta murakkab ifodadan ikki oddiy ifoda o'qishga oson.
3-mashq (qiyin): xatolar hisoboti
Logdagi qatorlardan hisobot yasang: har digest necha marta takrorlangani va qaysi yo'llarda. Kirish — JSON satrlar massivi (ba'zilari server-start, ularni o'tkazib yuboring). Natija — eng ko'p takrorlangani birinchi. Kerakli usullar: JSON.parse, Map (Map va Set), sort.
Yechim
const logLines = [
'{"tur":"server-start","runtime":"nodejs"}',
'{"tur":"server-xato","digest":"111","yol":"/blog"}',
'{"tur":"server-xato","digest":"222","yol":"/aloqa"}',
'{"tur":"server-xato","digest":"111","yol":"/blog/salom"}',
'{"tur":"server-xato","digest":"111","yol":"/blog"}',
];
function buildReport(lines) {
const byDigest = new Map();
for (const line of lines) {
const entry = JSON.parse(line);
if (entry.tur !== "server-xato") continue;
const item = byDigest.get(entry.digest) ?? {
digest: entry.digest,
count: 0,
paths: new Set(),
};
item.count += 1;
item.paths.add(entry.yol);
byDigest.set(entry.digest, item);
}
return [...byDigest.values()].sort((a, b) => b.count - a.count);
}
for (const item of buildReport(logLines)) {
const paths = [...item.paths].join(", ");
console.log(`${item.digest}: ${item.count} marta — ${paths}`);
}Konsolda:
111: 3 marta — /blog, /blog/salom
222: 1 marta — /aloqaSet bir yo'lni ikki marta yozmaydi: /blog uch yozuvdan ikkitasida bor, ro'yxatda esa bir marta. Haqiqiy log xizmatlari xuddi shu ishni qiladi — "bu xato 3 marta, 2 sahifada" — va eng ko'p takrorlanganini tepaga chiqaradi.
4-mashq: Portfolio qadami
O'z portfolio ingizga src/instrumentation.ts ni qo'shing (register va onRequestError). Vaqtinchalik sinov sahifasi yarating (yuqoridagi SinovXato), npm run build va npm run start qiling, sahifani oching. Ekrandagi xato kodi va terminaldagi digest bir xilmi? Tekshirgach, sinov sahifasini o'chiring. Hozircha commit qilmang.
Yechim
Namuna — «instrumentation.ts» bo'limidagi kanon kodi. Kutilgan natija: ekranda «Xato kodi: N», terminalda ikki yozuv (⨯ Error: … va bizning JSON qatorimiz), ikkalasida bir xil N. Raqam siznikida boshqa bo'ladi. Agar logda hech narsa bo'lmasa — fayl joyini tekshiring: src/ papkali loyihada src/instrumentation.ts. Sinov sahifasi o'chirilmasa, u production'ga chiqib, har ochilishda xato yozadi.
14. Real ishda
- Har production ilovada xato kuzatuvi bor: Sentry, Datadog, New Relic, Grafana yoki o'z log tizimi. Intervyuda "production'dagi xatoni qanday topasiz?" — tez-tez beriladigan savol. Javob: tuzilgan log + digest (yoki so'rov ID) + kuzatuv xizmati.
- Navbatchilik (on-call) — katta jamoalarda xato soni oshsa, navbatchi dasturchiga xabar boradi. Bu xabar aynan shu
onRequestErrordan boshlanadi. - Maxfiylik — logdagi shaxsiy ma'lumot qonun masalasi ham (shaxsiy ma'lumotlar haqidagi qonunlar). Loglarni tozalash — kod sharhida tekshiriladigan narsa.
- OpenTelemetry — mikroservislar dunyosining umumiy tili; backend qismlarida qayta uchraydi.
Xulosa
- Production'da server xatosining matni brauzerga bormaydi: ekranda
error.tsx, konsolda React #441, faqat digest. - Suspense oqimi boshlangandan keyingi xatoda status 200 qoladi — xatoni statusdan emas, logdan bilasiz.
instrumentation.ts:register()— server ishga tushganda bir marta,onRequestError()— har server xatosida (render, route, action, proxy).- Log — bitta qator JSON: digest, yo'l, marshrut fayli; sirlar yozilmaydi yoki yashiriladi.
instrumentation.tsikkala runtime uchun yig'iladi — Node API Edge ogohlantirishini beradi.- Sentry,
instrumentation-client.tsva OpenTelemetry shu ikki faylga ulanadi; kanonda ular yo'q (hisob kerak).
Keyingi dars: next.config chuqur — xavfsizlik sarlavhalari, CSP, v1 manzillaridan redirect va Next sozlamalarining to'liq xaritasi.
Manbalar
- Next.js hujjati —
instrumentation.js,instrumentation-client.js,error.js(retry,error.digest): https://nextjs.org/docs/app/api-reference/file-conventions/instrumentation (16.4.0 bilan kelgan nusxa, 2026-10-21 da o'qildi) - Next.js hujjati — OpenTelemetry: https://nextjs.org/docs/app/guides/open-telemetry
- React xato kodi 441 matni — React manba kodidagi xato kodlari ro'yxati (
scripts/error-codes/codes.json, github.com/facebook/react); konsoldagi react.dev/errors/441 havolasi 2026-10-21 da sahifa bermadi - Sentry hujjati — Next.js uchun SDK: https://docs.sentry.io/platforms/javascript/guides/nextjs/
- Kanon:
portfoliov2, holat 37 (instrumentation.ts, onRequestError tajribasi); sinov sahifasi,process.versionogohlantirishi vanext startchiqishi — biz ishga tushirdik (next 16.4.0, Node 24.21.0, Chrome 155).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!