Mundarija (30)
- Bu darsda
- 1. Nega bu kerak?
- 2. Winston asoslari
- 2.1 Birinchi logger
- 2.2 Darajalar teskari
- 3. Format zanjiri
- 3.1 combine: quvur kabi
- 3.2 Tuzoq: xato obyekti
- 4. Transport'lar
- 5. Log rotatsiya
- 5.1 Muammo: fayl cheksiz o'sadi
- 5.2 winston-daily-rotate-file
- 5.3 logrotate (Linux)
- 5.4 Docker log driver
- 6. Fayl yoki stdout?
- 7. API qadami o'rniga: tajriba
- 8. Ko'p uchraydigan xatolar
- 8.1 errors() formatisiz xato yozish
- 8.2 Pino odati bilan { err } berish
- 8.3 Darajalarni aralashtirish
- 8.4 Rotatsiyasiz File transport
- 8.5 Rotatsiyani tekshirmaslik
- 9. Mashqlar
- 1-mashq (oson): qaysi qatorlar yoziladi?
- 2-mashq (o'rta): Winston'dan Pino'ga ko'chirish
- 3-mashq (qiyin): o'z rotatsiyangiz
- 4-mashq: API qadami o'rniga — tajriba
- 10. Real ishda
- Xulosa
- Manbalar
Winston logger va log rotatsiya: transport, format va diskni to'ldirmaslik
Qisqacha: Winston — Node'ning eng eski va keng tarqalgan logger'i:
createLoggerga format zanjiri (timestamp,json,printf) va transportlar (konsol, fayl, tarmoq) beriladi. U moslashuvchan, lekin teng sharoitda Pino'dan ~1.4 barobar sekin (kanon o'lchovi) va xato obyektida tuzog'i bor:errors()formatisizlog.error(new Error(…))xabarsiz qator yozdi. Faylga yozilgan log rotatsiyasiz diskni to'ldiradi:winston-daily-rotate-file, Linux'dalogrotate, konteynerda Docker log driver. Kanon qarori — faylga umuman yozmaslik: stdout + muhit.
Bu darsda
- Winston logger'ini format va transport'lar bilan yig'a olasiz.
- Winston va Pino darajalari teskari ekanini va xato obyekti tuzog'ini bilasiz.
- Log rotatsiyasi nima uchun kerakligini va uning uch yo'lini tushuntirasiz.
- Rotatsiya kutubxonasining haqiqiy xulqini o'lchov bilan ko'rasiz.
- Fayl yoki stdout — qaysi biri qachon, asosli tanlay olasiz.
Oldin bilishingiz kerak: Logging asoslari, Pino chuqur, fs: kataloglar, stat va watch.
1. Nega bu kerak?
Siz yangi ishga kirdingiz. Loyiha 2019-yilda boshlangan, package.json da winston turibdi, logs/ papkasida error.log va combined.log bor. Bir kuni server javob bermay qoladi. Sabab — disk 100 % to'lgan: combined.log uch yilda 40 GB bo'lgan.
Bu darsda ikki narsani o'rganamiz. Birinchisi — Winston'ni o'qish va sozlash: eski va mavjud loyihalarning katta qismi unda. Ikkinchisi — log fayllari diskni yemasligi uchun nima qilinadi.
Hayotiy o'xshatish: do'kondagi chek lentasi. Kassa har xaridni lentaga bosadi. Lenta tugasa — yangisi qo'yiladi, eskisi arxivga ketadi, juda eskilari yo'q qilinadi. Hech kim bitta cheksiz lentani saqlamaydi. Log rotatsiyasi — xuddi shu: fayl ma'lum hajm yoki vaqtga yetganda yangisi ochiladi, eskilari sanoqli qoladi.
2. Winston asoslari
2.1 Birinchi logger
Winston'da logger uch qismdan yig'iladi: daraja, format va transport'lar.
import winston from "winston";
const { combine, timestamp, json } = winston.format;
const log = winston.createLogger({
level: "info",
defaultMeta: { ilova: "vazifalar-api" },
format: combine(timestamp(), json()),
transports: [new winston.transports.Console()],
});
log.info("vazifa yaratildi", { vazifaId: 7 });
log.debug("ko'rinmaydi");
log.warn("sekin so'rov", { ms: 1200 });
log.child({ sorovId: "kor-0001" }).info("child bilan");Biz ishga tushirdik (winston 3.19.0, Node 24.21.0; vaqt o'zgarmasligi uchun timestamp ga qat'iy qiymat berdik):
{"ilova":"vazifalar-api","level":"info","message":"vazifa yaratildi","timestamp":"2026-10-24T06:00:00.000Z","vazifaId":7}
{"ilova":"vazifalar-api","level":"warn","message":"sekin so'rov","ms":1200,"timestamp":"2026-10-24T06:00:00.000Z"}
{"ilova":"vazifalar-api","level":"info","message":"child bilan","sorovId":"kor-0001","timestamp":"2026-10-24T06:00:00.000Z"}Pino bilan farqlarga qarang:
| Pino | Winston | |
|---|---|---|
| Chaqiruv | log.info({ vazifaId }, "xabar") |
log.info("xabar", { vazifaId }) |
| Xabar maydoni | msg |
message |
| Daraja | son (30) |
matn ("info") |
| Doimiy maydonlar | base |
defaultMeta |
Argumentlar tartibi teskari — bir loyihadan ikkinchisiga o'tganda eng ko'p adashtiradigan joy.
2.2 Darajalar teskari
console.log(winston.config.npm.levels);{ error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6 }Winston'da son qancha kichik — shuncha jiddiy (error: 0). Pino'da teskari (fatal: 60). fatal yo'q, lekin http, verbose, silly bor. Bu "npm darajalari" deb ataladi — npm o'zining logida shunday ishlatgan. level: "warn" bersangiz — error va warn yoziladi, qolgani yo'q.
3. Format zanjiri
3.1 combine: quvur kabi
Format (format) — log yozuvini (info obyekti) qadamma-qadam o'zgartiradigan funksiya. combine ularni ketma-ket ulaydi: timestamp() vaqt qo'shadi, json() oxirida JSON satr yasaydi.
Dev uchun odam o'qiydigan format — printf:
const { combine, timestamp, printf } = winston.format;
const dev = winston.createLogger({
format: combine(
timestamp(),
printf((i) => {
const daraja = i.level.toUpperCase();
return `${i.timestamp} ${daraja}: ${i.message}`;
}),
),
transports: [new winston.transports.Console()],
});
dev.info("vazifa yaratildi");Biz ishga tushirdik (vaqt qat'iy berilgan):
11:02:05 INFO: vazifa yaratildiPino'da bu ish tashqi pino-pretty da, Winston'da esa logger ichida. Qulay, lekin ishlab chiqarishga tasodifan printf formati bilan chiqib ketish oson.
3.2 Tuzoq: xato obyekti
Endi muhim tajriba. Xatoni uch xil yo'l bilan yozamiz, avval errors() formatisiz:
const log = winston.createLogger({
format: json(),
transports: [new winston.transports.Console()],
});
log.error(new Error("errors formatisiz"));
log.error("xato", { err: new Error("ichki") });Biz ishga tushirdik:
{"level":"error"}
{"err":{},"level":"error","message":"xato"}Birinchi qatorda xabar ham, stack ham yo'q — faqat "level":"error". Ikkinchisida "err":{} — bo'sh obyekt. Sabab Pino chuqur darsida aytilgan: Error ning message va stack xususiyatlari sanalmaydigan, JSON.stringify ularni ko'rmaydi. Tunda yiqilgan server logida bitta {"level":"error"} qolsa — nima bo'lganini hech kim bilmaydi.
Yechim — errors({ stack: true }) formati:
const log = winston.createLogger({
format: combine(errors({ stack: true }), json()),
transports: [new winston.transports.Console()],
});
log.error(x); // x — new Error("ulanish uzildi")
log.error("saqlanmadi", x);
log.error("meta", { err: x });Biz ishga tushirdik (stack qisqa bo'lsin deb uni qo'lda berdik):
{"level":"error","message":"ulanish uzildi","stack":"Error: ulanish uzildi\n at saqla (ombor.js:12:9)"}
{"level":"error","message":"saqlanmadi ulanish uzildi","stack":"Error: ulanish uzildi\n at saqla (ombor.js:12:9)"}
{"err":{"level":"error"},"level":"error","message":"meta"}Birinchi ikki usul endi ishlaydi (ikkinchisida xabarlar qo'shilib ketdi). Uchinchisi — { err: x } — baribir buzuq: "err":{"level":"error"}. errors() faqat yuqori darajadagi xatoni ko'radi. Qoida: Winston'da xatoni birinchi yoki ikkinchi argument qilib bering, { err } ichida emas. Pino'da esa aksincha — { err } to'g'ri yo'l. Ikki kutubxona, ikki xil odat.
Tekshirib ko'ring: Eski loyihada
logger.error(err)qatorlari bor va loglarda faqat{"level":"error"}ko'rinyapti. Eng kichik tuzatish nima?
Javob
Logger yaratilgan joyda formatga errors({ stack: true }) ni birinchi qo'shish: combine(errors({ stack: true }), timestamp(), json()). Har logger.error(err) qatorini o'zgartirish shart emas. Tartib muhim: errors() json() dan oldin turishi kerak, aks holda JSON allaqachon bo'sh obyekt bilan yasalgan bo'ladi.
4. Transport'lar
Transport — Winston'da yozuv boradigan joy: Console, File, Http, Stream va jamoa paketlari (bulut xizmatlari). Har transport'ga alohida daraja va format berish mumkin:
const log = winston.createLogger({
format: combine(timestamp(), json()),
transports: [
new winston.transports.Console({ level: "info" }),
new winston.transports.File({
filename: "logs/error.log",
level: "error",
}),
],
});Bu "klassik" Winston sozlamasi: hammasi konsolga, xatolar alohida faylga. Pino'dagi targets ning o'xshashi. Farqi — Winston transport'lari asosiy threadda ishlaydi, Pino transport'lari esa alohida worker thread'da.
Pino va Winston'ni yonma-yon:
| Mezon | Pino 10.4.0 | Winston 3.19.0 |
|---|---|---|
| 100 000 qator faylga | 882 ms | 1 246 ms |
| Paketlar / hajm | 13 / 1.1 MB | 29 / 1.8 MB |
| Xato obyekti | { err } sukut ishlaydi |
errors() kerak |
| Format | tashqarida (pino-pretty) |
ichida (printf) |
Raqamlar — kanon o'lchovi (t42-log.txt, Windows NTFS, bitta o'lchov). Kanon Pino'ni tanladi: tezroq, kichikroq, xato obyekti sukut bo'yicha to'g'ri. Winston'ni esa o'qiy olish kerak — u ko'p loyihada bor.
5. Log rotatsiya
5.1 Muammo: fayl cheksiz o'sadi
Faylga yozilgan log hech qachon o'z-o'zidan kichraymaydi. Soniyasiga 100 so'rov, har biri ~250 baytli qator — kuniga ~2 GB. Rotatsiya uchun uchta yo'l bor:
flowchart TD
L[Log qayerga?] --> F[faylga]
L --> S[stdout]
F --> W[ilova o'zi: winston-daily-rotate-file]
F --> R[OS: logrotate]
S --> D[Docker log driver: max-size, max-file]Diagrammaga qarang: faylga yozsangiz, rotatsiyani yo ilova, yo OS qiladi. Stdout'ga yozsangiz — konteyner muhiti qiladi.
5.2 winston-daily-rotate-file
Kutubxona har kuni (yoki hajm chegarasida) yangi fayl ochadi va eskilarini o'chiradi:
import DailyRotateFile from "winston-daily-rotate-file";
const r = new DailyRotateFile({
dirname: "rot",
filename: "ilova-%DATE%.log",
datePattern: "YYYY-MM-DD",
maxSize: "20k", // shu hajmda yangi fayl
maxFiles: 3, // faqat oxirgi 3 tasi qolsin
auditFile: "rot/audit.json",
});
const log = winston.createLogger({
format: winston.format.json(),
transports: [r],
});
for (let i = 0; i < 2000; i++) {
log.info("vazifa yaratildi", { sorovId: `s-${i}`, vazifaId: i });
}maxFiles: 3 — demak papkada 3 ta log fayli qolishi kerak. Kanon o'lchadi (t42-log.txt, winston-daily-rotate-file 5.0.0). Ro'yxatda fayl nomlarining oxiriga qarang — .log, .log.1 … .log.8:
audit.json 986 bayt
ilova-2026-10-24.log 20486 bayt
ilova-2026-10-24.log.1 20532 bayt
…
ilova-2026-10-24.log.7 20559 bayt
ilova-2026-10-24.log.8 11481 baytTo'qqizta fayl qoldi, uchta emas. Kanon buni yozib qo'ydi, lekin sababini aniqlamadi. Biz qayta tekshirdik (o'sha versiyalar, Windows 11; uzun nomlar … bilan qisqartirildi):
500 ms dan keyin: 10 fayl — audit.json, ilova-2026-10-24.log, … .log.8
3000 ms dan keyin: 10 fayl — audit.json, ilova-2026-10-24.log, … .log.8
sekin yozish: 4 fayl — audit.json, ilova-2026-10-24.log.6, .log.7, .log.8; logRemoved: 6Ikki xulosa. Birinchisi — kutish yordam bermadi: 3 soniyadan keyin ham 9 ta log fayli. Demak o'chirish kechikmagan — u bajarilmagan. Ikkinchisi — qatorlarni bo'lib yozganda (100 tadan, orasida 50 ms) kutubxona 6 ta faylni o'chirdi va 3 tasi qoldi, ya'ni maxFiles ishladi. audit.json esa birinchi holatda ham faqat 3 ta faylni "eslab qolgan".
Taxminimiz: juda tez rotatsiyada kutubxona eski faylni u hali ochiq turganda o'chirmoqchi bo'ladi. Windows ochiq faylni o'chirishga ruxsat bermaydi, xato esa jim yutiladi. Bu — taxmin, kutubxona kodida tasdiqlamadik. Linux'da sinalmagan. Amaliy saboq: rotatsiya sozlamasini o'z muhitingizda tekshiring, hujjatga ko'r-ko'rona ishonmang.
5.3 logrotate (Linux)
Linux serverlarda rotatsiyani ko'pincha ilova emas, OS'dagi logrotate dasturi qiladi. Namuna sozlama (/etc/logrotate.d/vazifalar-api), hujjat bo'yicha — biz sinamadik (mashinada Linux yo'q):
/var/log/vazifalar-api/*.log {
daily
rotate 7
maxsize 100M
compress
missingok
notifempty
copytruncate
}| Qator | Ma'nosi |
|---|---|
daily, rotate 7 |
har kuni yangi, 7 ta eski qoladi |
maxsize 100M |
kun tugamasa ham, 100 MB da aylantir |
compress |
eskilarini gzip bilan siqish |
copytruncate |
faylni nusxalab, aslini bo'shatish |
copytruncate nega kerak? Node fayl deskriptorini ochiq ushlab turadi. logrotate faylni qayta nomlasa, Node eski (nomi o'zgargan) faylga yozishda davom etadi. Nusxalab-bo'shatish bu muammoni chetlab o'tadi, lekin nusxa va bo'shatish orasida bir necha qator yo'qolishi mumkin. Muqobili — ilovaga signal yuborib, faylni qayta ochtirish.
5.4 Docker log driver
Konteynerda ilova stdout'ga yozadi, Docker esa chiqishni o'zi saqlaydi. Sukut drayver (json-file) ham cheksiz o'sadi — chegarani berish kerak. Docker Compose'da (hujjat bo'yicha; Docker'ni 26-qismda o'rnatamiz, prod sozlamasi — 33-qismda):
services:
api:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"Har konteyner uchun eng ko'pi 3 × 10 MB. Ilova kodi hech narsa bilmaydi — u faqat stdout'ga yozadi.
6. Fayl yoki stdout?
| Savol | Faylga | Stdout'ga |
|---|---|---|
| Rotatsiya kimda? | ilova yoki logrotate |
Docker / platforma |
| Bir nechta nusxa ishlasa | har birida alohida fayl | hammasi bitta oqimda yig'iladi |
| Konteyner o'chsa | fayl u bilan yo'qoladi | Docker saqlagan |
| Kod murakkabligi | transport, papka, huquqlar | yo'q |
Kanon qarori: Pino + pino-http kirdi; Winston, morgan va fayl rotatsiyasi kirmadi. Sabab — vazifalar-api konteynerda ishlaydi (33-qism), u yerda stdout + Docker log driver yetarli. Faylga yozish qachon o'rinli? Konteynersiz eski serverda, yoki auditorlar alohida audit fayli talab qilganda.
7. API qadami o'rniga: tajriba
Bu darsda vazifalar-api ga kod qo'shilmaydi — Winston loyihaga kirmadi. Holat 44 davom etmoqda: commit qilmang, commit keyingi darsda.
O'rniga — 4-mashqda kanon tajribasini o'zingiz takrorlaysiz va o'z muhitingizdagi natijani ko'rasiz.
8. Ko'p uchraydigan xatolar
8.1 errors() formatisiz xato yozish
{"level":"error"} — xabarsiz qator. combine(errors({ stack: true }), …, json()).
8.2 Pino odati bilan { err } berish
Winston'da "err":{}. Xatoni argument sifatida: log.error("saqlanmadi", x).
8.3 Darajalarni aralashtirish
Winston'da level: "verbose" va http darajalari bor, Pino'da yo'q. Kutubxona almashtirilsa, LOG_LEVEL=verbose jarayonni yiqitadi (Pino'da «Noma'lum daraja» xatosi). Config'da ruxsat etilgan qiymatlar ro'yxati.
8.4 Rotatsiyasiz File transport
Disk to'ladi — server javob bermaydi, ba'zan baza ham yiqiladi. Rotatsiya yoki stdout.
8.5 Rotatsiyani tekshirmaslik
«winston-daily-rotate-file» bo'limidagi kabi maxFiles kutilgandek ishlamasligi mumkin. Yuk ostida bir marta sinab, papkadagi fayllar sonini tekshiring.
9. Mashqlar
1-mashq (oson): qaysi qatorlar yoziladi?
Winston logger level: "http" bilan. Chaqiruvlar: error, warn, info, http, verbose, debug. Qaysilari yoziladi?
Yechim
error, warn, info, http — to'rttasi. Winston'da chegara soni http: 3; soni 3 dan kichik yoki teng darajalar yoziladi. verbose (4) va debug (5) — yo'q. Pino'da qoida teskari: chegaradan katta yoki teng.
2-mashq (o'rta): Winston'dan Pino'ga ko'chirish
Har Winston chaqiruvini Pino ko'rinishiga o'tkazing: (a) log.info("vazifa yaratildi", { vazifaId: 7 }); (b) log.error("saqlanmadi", xato); (c) log.verbose("kesh topildi", { kalit: "v:7" }); (d) log.child({ sorovId: "a1" }).warn("sekin").
Yechim
(a) log.info({ vazifaId: 7 }, "vazifa yaratildi") — obyekt birinchi. (b) log.error({ err: xato }, "saqlanmadi") — err kaliti, Pino serializer'i stack va cause ni yozadi. (c) Pino'da verbose yo'q — eng yaqini debug: log.debug({ kalit: "v:7" }, "kesh topildi"). (d) log.child({ sorovId: "a1" }).warn("sekin") — o'zgarmaydi. Ko'chirishni grep bilan qiling (log\.\w+\(") va har natijani qo'lda ko'ring: argumentlar tartibi avtomatik almashtirishda eng ko'p buziladi.
3-mashq (qiyin): o'z rotatsiyangiz
Kutubxonasiz kichik rotatsiya mantiqini yozing — faqat qaror qismini, fayl operatsiyalarisiz. rotatsiyaRejasi(fayllar, maks) — fayllar — ["ilova.log", "ilova.log.1", …] ko'rinishidagi nomlar. Funksiya qaytarsin: { nomlash: [[eski, yangi], …], ochirish: [...] } — har .N → .N+1, asosiy ilova.log → .1, maks dan oshganlari o'chiriladi. Nomlash tartibi muhim: kattasidan boshlang (aks holda .1 ni .2 ga nomlaganda eski .2 ustiga yoziladi).
Yechim
function raqam(nom) {
const m = nom.match(/\.(\d+)$/);
return m ? Number(m[1]) : 0;
}
function rotatsiyaRejasi(fayllar, maks) {
const tartib = [...fayllar].sort((a, b) => raqam(b) - raqam(a));
const nomlash = [];
const ochirish = [];
for (const nom of tartib) {
const n = raqam(nom);
if (n + 1 > maks) ochirish.push(nom);
else nomlash.push([nom, `ilova.log.${n + 1}`]);
}
return { nomlash, ochirish };
}
const fayllar = ["ilova.log", "ilova.log.1", "ilova.log.2"];
console.log(JSON.stringify(rotatsiyaRejasi(fayllar, 2)));Konsolda:
{"nomlash":[["ilova.log.1","ilova.log.2"],["ilova.log","ilova.log.1"]],"ochirish":["ilova.log.2"]}Kattasidan boshladik: avval .2 o'chiriladi, keyin .1 → .2, keyin asosiy → .1. Haqiqiy dastur (logrotate) aynan shu tartibda ishlaydi va qo'shimcha ravishda siqadi. Rejani alohida toza funksiya qilish — uni fayllarsiz test qilish imkonini beradi (Mock, stub, spy va fake darsida bu g'oyani davom ettiramiz).
4-mashq: API qadami o'rniga — tajriba
Bo'sh papkada npm i --save-exact winston@3.19.0 winston-daily-rotate-file@5.0.0. «winston-daily-rotate-file» bo'limidagi kodni ishga tushiring va rot/ papkasidagi fayllarni sanang. Keyin qatorlarni 100 tadan, orasida await new Promise((r) => setTimeout(r, 50)) bilan yozing. Natijalaringiz bizniki bilan mos keldimi? Linux yoki macOS'da bo'lsangiz — natija ayniqsa qiziq: u bizning taxminimizni tekshiradi.
Yechim
Windows'da kutiladigan natija — «winston-daily-rotate-file» bo'limidagidek: tez yozishda 9 ta log fayli, bo'lib yozishda 3 ta. Fayllar sonini readdirSync("rot").length bilan sanang. Agar Linux'da tez yozishda ham 3 ta qolsa — demak muammo Windows'ning ochiq faylni o'chirmasligida edi. Natijani vazifalar-api ga kiritmaysiz — bu faqat tajriba.
10. Real ishda
- Eski loyihalar: 2015–2020 yillardagi Express loyihalarining katta qismida Winston va
morgan(HTTP log middleware) birga turadi. Ularni o'qish va keyin Pino'ga ko'chirish — tez-tez beriladigan vazifa. - Serverlar: konteynersiz VPS'da
logrotatedeyarli har doim allaqachon o'rnatilgan — nginx va tizim loglari shu bilan aylanadi. - Kubernetes va bulut loglarni faqat stdout'dan oladi; faylga yozgan ilova u yerda "jim" qoladi.
- Intervyu savollari: "Winston va Pino farqi?", "Log rotatsiya nima va kim qiladi?", "Konteynerda log qayerga yoziladi?", "
copytruncatenima uchun?".
Xulosa
- Winston:
createLogger= daraja + format zanjiri (combine) + transport'lar; argumentlar("xabar", meta). - Darajalar teskari: Winston'da
error: 0, Pino'dafatal: 60; Winston'dahttp,verbose,sillybor. errors({ stack: true })sizlog.error(xato)— xabarsiz qator;{ err }meta ichida — baribir buzuq.- Rotatsiya uch yo'l: ilova (
winston-daily-rotate-file), OS (logrotate), konteyner (Dockermax-size,max-file). - Bizning sinovda tez yozishda
maxFiles: 3ishlamadi (9 fayl) — rotatsiyani o'z muhitingizda tekshiring. - Kanon: faylga yozmaydi; Pino → stdout → muhit.
Keyingi dars: Correlation ID va so'rov kuzatuvi — X-Request-Id ni AsyncLocalStorage orqali har log qatoriga yetkazish, servislararo uzatish va W3C traceparent; holat 44 commit'i.
Manbalar
- Winston: README — formats, transports, levels (3.x, 2026-10-24 da ko'rildi).
- winston-daily-rotate-file: README (5.x).
- logrotate: man sahifasi.
- Docker hujjati: JSON File logging driver.
- Kanon:
natijalar/tajriba/t42-log.txt; bizning qayta tekshiruvimiz — 2026-10-24, Node 24.21.0, Windows 11.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!