> ## Documentation Index
> Fetch the complete documentation index at: https://docs.logbrew.co/llms.txt
> Use this file to discover all available pages before exploring further.

# تسجيل السجلات في Node.js باستخدام Winston وPino وExpress

> اضبط مسجِّل Winston أو مسجِّل Pino في Node.js وExpress، واختر مستويات السجلات، وأرسل سجلات منظمة مع معرّفات التتبّع إلى LogBrew.

LogBrew منصة لقابلية الملاحظة (Observability) للمطوّرين ووكلاء البرمجة، مع خطة
مجانية سخية ودون الحاجة إلى بطاقة دفع.

يضبط هذا الدليل تسجيل السجلات باستخدام Winston وPino في Node.js، ويضيف مسجِّلًا
لـ Express، ويرسل كل سجل إلى LogBrew مع تتبّع طلبه. شُغّل كل مثال على Node.js 22
مع Winston 3.19 وPino 10.4 وExpress 5.3 و`@logbrew/sdk` 0.1.40 و`@logbrew/node`
0.1.24 و`@logbrew/express` 0.1.10. وتعرض كل كتلة مخرجات مخرجاتها الفعلية.

## اختر Winston أو Pino

تكتب المكتبتان كلتاهما سجلات JSON منظمة. احتفظ بالمكتبة التي يستخدمها تطبيقك
بالفعل. ويختلف إعداد LogBrew لكل منهما.

| | Winston | Pino |
| - | - | - |
| المخرجات الافتراضية | تختار التنسيق بنفسك، مثل `winston.format.json()`. | سطر JSON واحد لكل سجل. |
| وسيط الرسالة | `logger.info("message", { fields })` | `logger.info({ fields }, "message")` |
| الوجهات | وسائل نقل (transports) داخل عملية التطبيق. | وسائل نقل داخل خيط عامل (worker thread). |
| المسجِّلات الفرعية | `logger.child({ fields })` | `logger.child({ fields })` |
| الحجب | تنسيق تكتبه بنفسك. | الخيار المضمّن `redact`. |
| إعداد LogBrew | أضف `createLogBrewWinstonTransport()` إلى `transports`. | استدعِ `installLogBrewPinoInstrumentation()` مرة واحدة. |

## جهّز مشروعًا في LogBrew

**1. أنشئ مفتاحًا للمشروع**

سجّل الدخول باستخدام [الـ CLI](https://docs.logbrew.co/ar/guides/cli.md). أنشئ مشروعًا وخزّن مفتاح
الاستيعاب الخاص به في ملف لا يقرؤه إلا مالكه.

```bash theme={null}
install -d -m 700 "$HOME/.logbrew"
logbrew projects create checkout-api \
  --runtime node \
  --environment development \
  --ingest-key-file "$HOME/.logbrew/checkout-api.ingest" \
  --json
```

لا يطبع الـ CLI المفتاح. في بيئة الإنتاج، استخدم مدير الأسرار في منصتك.

**2. ثبّت الحزم**

تتطلب الحزم Node.js 18.19 أو أحدث. ثبّت Winston أو Pino أو كليهما.

```bash theme={null}
npm install @logbrew/sdk @logbrew/node @logbrew/express express winston pino
```

**3. اضبط المفتاح وهوية النشر**

```bash theme={null}
export LOGBREW_SERVER_API_KEY="$(tr -d '\r\n' < "$HOME/.logbrew/checkout-api.ingest")"
export LOGBREW_ENVIRONMENT="development"
export LOGBREW_RELEASE="checkout-api@1.0.0"
```

يقرأ `createLogBrewNodeClient()` المفتاح من `LOGBREW_SERVER_API_KEY`. واسم
الخدمة هو قيمة `name` في `package.json`. اضبط `LOGBREW_SERVICE_NAME`
لاستخدام اسم مختلف. تستخدم الأمثلة وحدات ES، لذلك اضبط `"type": "module"` في
`package.json`.

## مستويات السجلات في Node.js

لكل مكتبة أسماء مستويات وأرقام خاصة بها. يخزّن LogBrew 4 مستويات ويحتفظ بالمستوى
الأصلي في البيانات الوصفية.

| مستوى LogBrew | مستوى Winston (الأولوية) | مستوى Pino (الرقم) |
| - | - | - |
| `info` | `info` (2)، `http` (3)، `verbose` (4)، `debug` (5)، `silly` (6) | `info` (30)، `debug` (20)، `trace` (10) |
| `warning` | `warn` (1) | `warn` (40) |
| `error` | `error` (0) | `error` (50) |
| `critical` | `fatal` أو `critical` إذا عرّفتهما | `fatal` (60) |

في Winston، الرقم الأقل أشد خطورة. وفي Pino، الرقم الأعلى أشد خطورة. اضبط `info`
في بيئة الإنتاج، واضبط `debug` لتشخيص قصير فقط.

## مسجِّل Winston

احفظ هذا الملف باسم `winston-app.js`. يُسقط التنسيق الأول السجلات التي تقل عن
مستوى المسجِّل قبل أن تصل إلى أي وسيلة نقل. تستقبل وسيلة نقل LogBrew كل سجل
يكتبه المسجِّل، لذلك تحتاج إلى هذه التصفية.

```js theme={null}
import winston from "winston";
import { createLogBrewWinstonTransport } from "@logbrew/sdk";
import { createLogBrewNodeClient } from "@logbrew/node";

const client = createLogBrewNodeClient();

const logger = winston.createLogger({
  level: "info",
  format: winston.format.combine(
    winston.format((info) => (logger.isLevelEnabled(info.level) ? info : false))(),
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  defaultMeta: { component: "checkout" },
  transports: [
    new winston.transports.Console(),
    createLogBrewWinstonTransport({ client })
  ]
});

logger.debug("cart loaded");
logger.info("order created", { orderId: "ord_1001", totalCents: 4200 });
logger.warn("payment retry", { attempt: 2 });
logger.error(new Error("card declined"));

await client.shutdown();
```

شغّل `node winston-app.js`. تتلقى وحدة التحكم سطر JSON واحدًا لكل سجل بالمستوى
`info` أو أعلى. وقد اختُصر تتبّع المكدّس هنا.

```text theme={null}
{"component":"checkout","level":"info","message":"order created","orderId":"ord_1001","timestamp":"2026-11-07T14:19:53.863Z","totalCents":4200}
{"attempt":2,"component":"checkout","level":"warn","message":"payment retry","timestamp":"2026-11-07T14:19:53.864Z"}
{"component":"checkout","level":"error","message":"card declined","stack":"Error: card declined\n    at file:///srv/app/winston-app.js:25:14\n ...","timestamp":"2026-11-07T14:19:53.864Z"}
```

يستقبل LogBrew السجلات نفسها، وعددها 3. وتصبح الحقول بيانات وصفية `context.*`.

| `message` | `level` | `metadata` |
| - | - | - |
| `order created` | `info` | `winstonLevel` `info`, `context.component` `checkout`, `context.orderId` `ord_1001`, `context.totalCents` 4200 |
| `payment retry` | `warning` | `winstonLevel` `warn`, `context.component` `checkout`, `context.attempt` 2 |
| `card declined` | `error` | `winstonLevel` `error`, `context.component` `checkout`, `errorName` `Error`, `errorMessage` `card declined` |

ترسل وسيلة النقل اسم الخطأ ورسالته، لكن دون تتبّع المكدّس. اضبط
`includeErrorStack: true` في `createLogBrewWinstonTransport()` لإرسال تتبّع
المكدّس. وتصبح كل رسالة أيضًا Breadcrumb (حدثًا قصيرًا مسجَّلًا قبل وقوع
المشكلة) في المشكلة التالية. اضبط `breadcrumbs: false` لإيقاف ذلك.

## مسجِّل Pino

احفظ هذا الملف باسم `pino-app.js`. استدعِ `installLogBrewPinoInstrumentation()`
مرة واحدة قبل أول سجل. فهو يقرأ كل سجل Pino مكتمل. ويظل Pino يكتب إلى وجهته
الخاصة.

```js theme={null}
import pino from "pino";
import {
  createLogBrewNodeClient,
  installLogBrewPinoInstrumentation
} from "@logbrew/node";

const client = createLogBrewNodeClient();
installLogBrewPinoInstrumentation({ client });

const logger = pino({
  level: "info",
  redact: ["password", "token", "req.headers.authorization"]
});
const orderLogger = logger.child({ component: "checkout" });

orderLogger.debug("cart loaded");
orderLogger.info({ orderId: "ord_1001", totalCents: 4200 }, "order created");
orderLogger.warn({ attempt: 2, token: "tok_example" }, "payment retry");
orderLogger.error(new Error("card declined"), "payment failed");

await client.shutdown();
```

شغّل `node pino-app.js`. وقد اختُصر اسم المضيف وتتبّع المكدّس هنا.

```text theme={null}
{"level":30,"time":1794061059490,"pid":13985,"hostname":"app-host","component":"checkout","orderId":"ord_1001","totalCents":4200,"msg":"order created"}
{"level":40,"time":1794061059493,"pid":13985,"hostname":"app-host","component":"checkout","attempt":2,"token":"[Redacted]","msg":"payment retry"}
{"level":50,"time":1794061059494,"pid":13985,"hostname":"app-host","component":"checkout","err":{"type":"Error","message":"card declined","stack":"Error: card declined\n ..."},"msg":"payment failed"}
```

يستقبل LogBrew 3 سجلات. ويُسقط Pino سجل `debug` قبل أن يراه LogBrew.

| `message` | `level` | `metadata` |
| - | - | - |
| `order created` | `info` | `pinoLevel` `info`, `pinoLevelNumber` 30, `context.component` `checkout`, `context.orderId` `ord_1001`, `context.totalCents` 4200 |
| `payment retry` | `warning` | `pinoLevel` `warn`, `pinoLevelNumber` 40, `context.component` `checkout`, `context.attempt` 2 |
| `payment failed` | `error` | `pinoLevel` `error`, `pinoLevelNumber` 50, `context.component` `checkout`, `errorName` `Error`, `errorMessage` `card declined` |

الحقل `token` غير موجود في LogBrew. يُسقط LogBrew حقول بيانات الاعتماد وملفات
تعريف الارتباط ومتن الطلب والاستعلام وعنوان URL وتتبّع المكدّس، ويُبقي مسارات
`redact` في Pino ضابطًا ثانيًا. الحقول `pid` و`hostname` و`time` افتراضية في
Pino، لذلك لا ينسخها LogBrew.

يتطلب الالتقاط التلقائي Pino 9.11 أو أحدث ضمن الفرع 9.x، أو Pino 10.1 أو أحدث.
لإصدارات Pino الأقدم، استخدم `createLogBrewPinoDestination()` من `@logbrew/sdk`
وجهةً لـ Pino.

لقراءة مخرجات Pino أثناء التطوير، مرّرها إلى `pino-pretty`.

```bash theme={null}
node pino-app.js | npx pino-pretty
```

## مسجِّل Express

ينشئ `logbrewMiddleware()` Span طلب واحدًا لكل طلب. ويُبلغ
`logbrewErrorHandler()` عن الأخطاء كمشكلات. ويحصل سجل Pino داخل الطلب على معرّف
التتبّع ومعرّف الـ Span لذلك الطلب. احفظ هذا الملف باسم `express-app.js`.

```js theme={null}
import express from "express";
import pino from "pino";
import { logbrewErrorHandler, logbrewMiddleware } from "@logbrew/express";
import {
  createLogBrewNodeClient,
  installLogBrewPinoInstrumentation
} from "@logbrew/node";

const client = createLogBrewNodeClient();
installLogBrewPinoInstrumentation({ client });
const logger = pino({ level: "info" });

const app = express();
app.use(logbrewMiddleware());

app.get("/orders/:orderId", (req, res) => {
  logger.info({ orderId: req.params.orderId }, "order loaded");
  res.json({ ok: true });
});

app.get("/fail", () => {
  throw new Error("inventory service timeout");
});

app.use(logbrewErrorHandler());
app.use((err, req, res, next) => {
  logger.error(err, "request failed");
  res.status(500).json({ error: "internal" });
});

const server = app.listen(3000, () => logger.info("listening on 3000"));

process.on("SIGTERM", () => {
  server.close(async () => {
    await client.shutdown();
    process.exit(0);
  });
});
```

شغّل التطبيق. ثم أرسل طلبين من طرفية ثانية.

```bash theme={null}
curl -s http://127.0.0.1:3000/orders/ord_1001
curl -s http://127.0.0.1:3000/fail
```

يستقبل LogBrew هذه الأحداث. ويحمل السجل والـ Span في كل طلب معرّف التتبّع نفسه.

| الحدث | الاسم أو الرسالة | التتبّع |
| - | - | - |
| Span | `GET /orders/:orderId`، الحالة `ok` | `4f18970f494d633c2164588fee9c692a` |
| سجل | `order loaded` | `4f18970f494d633c2164588fee9c692a` |
| مشكلة | `GET /fail failed`، الرسالة `inventory service timeout` | `d273e106d73ce6c5a5955e5a8c74d2d0` |
| Span | `GET /fail`، الحالة `error` | `d273e106d73ce6c5a5955e5a8c74d2d0` |
| سجل | `request failed` | `d273e106d73ce6c5a5955e5a8c74d2d0` |

يستخدم اسم الـ Span قالب المسار وليس المسار الفعلي. ولا يحمل سجل
`listening on 3000` أي تتبّع، لأنه خارج أي طلب.

اترك الوسيط (middleware) ينشئ عملاء الطلبات الخاصين به. لا تمرّر `client`
المشترك على مستوى العملية إلى `logbrewMiddleware()` أو `logbrewErrorHandler()`.
ويغلق الوسيط عميل الطلب بعد كل استجابة.

### أضف التتبّع إلى سجلات Winston

في Winston، مرّر التتبّع النشط إلى وسيلة النقل.

```js theme={null}
import { createLogBrewWinstonTransport } from "@logbrew/sdk";
import { createLogBrewNodeClient, getActiveLogBrewTrace } from "@logbrew/node";

const client = createLogBrewNodeClient();
const logbrewTransport = createLogBrewWinstonTransport({
  client,
  traceProvider: getActiveLogBrewTrace
});
```

أضف `logbrewTransport` إلى قائمة `transports` في المسجِّل. عندها يحمل سجل
Winston داخل طلب Express معرّف التتبّع ومعرّف الـ Span لذلك الطلب.

## اقرأ السجلات المخزّنة

```bash theme={null}
logbrew read logs --service checkout-api --since 1h --json
logbrew read logs --severity error --search "request failed" --since 1h --json
logbrew read logs --trace "<trace_id>" --since 1h --json
```

يقرأ الأمر الأخير كل سجلات طلب واحد. انسخ `<trace_id>` من تتبّع أو من مشكلة.
للقراءة من CI أو من وكيل برمجة، استخدم مفتاح القراءة الخاص بالمشروع. راجع [تحقّق
من الإعداد](https://docs.logbrew.co/ar/guides/verify-setup.md).

## أوقف التطبيق دون فقدان السجلات

يرسل العميل الأحداث المنتظرة بعد ثانية واحدة من أول حدث أو عند بلوغ 50 حدثًا.
وعندما تفرغ حلقة الأحداث، يرسل العميل الأحداث المتبقية مدة ثانيتين على الأكثر.
ويتخطى `process.exit()` والإشارات هذه الخطوة. استدعِ `await client.shutdown()`
قبل الخروج، كما يفعل معالج `SIGTERM` في مثال Express.

## استكشاف الأخطاء وإصلاحها

| العَرَض | السبب | الحل |
| - | - | - |
| `createLogBrewNodeClient requires serverApiKey, apiKey, LOGBREW_SERVER_API_KEY, or LOGBREW_API_KEY` | المفتاح غير مضبوط في هذه الطرفية. | شغّل خطوة `export` مرة أخرى. |
| تظهر سجلات `debug` من Winston في LogBrew ولا تظهر في وحدة التحكم | لا تطبّق وسيلة نقل LogBrew مستوى المسجِّل. | أضف تنسيق تصفية المستوى من مثال Winston. |
| لا تظهر سجلات Pino في LogBrew | لا يملك إصدار Pino قناة تتبّع (tracing channel)، أو كُتبت السجلات قبل `installLogBrewPinoInstrumentation()`. | استخدم Pino 9.11 أو أحدث، أو 10.1 أو أحدث. ثبّت الالتقاط قبل أول سجل. |
| تتوقف السجلات بعد الطلب الأول، ويرمي `client.shutdown()` الخطأ `client is already shut down` | مُرّر العميل المشترك على مستوى العملية إلى وسيط Express. | أزل الخيار `client` من `logbrewMiddleware()` و`logbrewErrorHandler()`. |
| آخر السجلات مفقودة بعد النشر | خرجت العملية قبل التسليم. | استدعِ `await client.shutdown()` في معالج `SIGTERM`. |

لاختيار حقول السجلات، راجع [التسجيل المنظم](https://docs.logbrew.co/ar/concepts/structured-logging.md).
لأطر العمل الأخرى، راجع [دمج SDK](https://docs.logbrew.co/ar/guides/sdk-ingestion.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.