Winston: لا يعمل تمرير معلمات متعددة إلى وظائف التسجيل كما هو متوقع

تم إنشاؤها على ٦ أغسطس ٢٠١٨  ·  43تعليقات  ·  مصدر: winstonjs/winston

من فضلك أخبرنا عن بيئتك:

  • _ winston نسخة؟ _

    • [] winston@2

    • [x] winston@3

  • النواتج _ node -v _ v8.11.3
  • _نظام التشغيل؟ _ macOS
  • _Language؟ _ Flow ES6 / 7

ما المشكلة؟


مع 3.xx:

const winston = require('winston')

const logger = winston.createLogger({
    transports: [new winston.transports.Console()]
})

logger.info('test log', 'with a second parameter')

المخرجات:

{"level":"info","message":"test log"}

مع 2.xx:

const winston = require('winston')

const logger = new winston.Logger({
    transports: [new winston.transports.Console()]
})

logger.info('test log', 'with a second parameter')

المخرجات:

info: test log with a second parameter

ماذا تتوقع ان يحدث بدلا من ذلك؟


يجب إخراج:

{"level":"info","message":"test log with a second parameter"}
important

التعليق الأكثر فائدة

هذا تغيير هائل بالنسبة لنا. إذا كان ذلك مقصودًا ، فيجب تفصيله في https://github.com/winstonjs/winston/blob/master/UPGRADE-3.0.md

ال 43 كومينتر

واجهت نفس المشكلة اليوم. أعتقد أنه خطأ نظرًا لأن وثائق الترقية تحتوي أيضًا على مثال كهذا هنا :

logger.info('transaction ok', { creditCard: 123456789012345 });

للتغلب على هذا حاليًا ، يمكنك إنشاء وظيفة تحلل المعطيات قبل تمريرها إلى winston

@ mulligan121 حسنًا ، لكني لا أريد استبدال كل بيان سجل في قاعدة الكود الخاصة بي ...

indexzero هل هذا تحت

الحل المؤقت:

const wrapper = ( original ) => {
    return (...args) => original(args.join(" "));
};

winstonLogger.error = wrapper(winstonLogger.error);
winstonLogger.warn = wrapper(winstonLogger.warn);
winstonLogger.info = wrapper(winstonLogger.info);
winstonLogger.verbose = wrapper(winstonLogger.verbose);
winstonLogger.debug = wrapper(winstonLogger.debug);
winstonLogger.silly = wrapper(winstonLogger.silly);

هذا تغيير هائل بالنسبة لنا. إذا كان ذلك مقصودًا ، فيجب تفصيله في https://github.com/winstonjs/winston/blob/master/UPGRADE-3.0.md

لذلك بعد المزيد من الاستقصاء ، وجدت أنك بحاجة إلى مُنسق splat من أجل طباعة وسيطات متعددة. اعتقدت أن هذا كان فقط لاستيفاء الوسيطة (أي الأشياء التي تحتوي على٪ s وما إلى ذلك) ، ولكن يبدو أنك تحتاجه فقط للقيام بـ logger.info("something", value) .

لكن هذا لا يزال غريبًا بعض الشيء بالنسبة لي - أحصل على شيء يشبه JSON في الإخراج مع مفتاح "meta" ، على الرغم من أنني لا أستخدم تنسيق JSON:

logger.info('Test: %s', 1, 2, 3, 4);

ينتج عنه:

info: Test: 1 {"meta":[2,3,4]}

حتى المثال في الأمثلة لا ينتج ما يقول إنه سيفعله:

https://github.com/winstonjs/winston/blob/master/examples/interpolation.js#L20 -L21

info: test message first, second {"meta":{"number":123}}

لقد قمت بحلها باستخدام شيء من هذا القبيل:

const { version } = require('../package');

const { createLogger, format, transports } = require('winston');
const { combine, timestamp, colorize, label, printf, align } = format;
const { SPLAT } = require('triple-beam');
const { isObject } = require('lodash');

function formatObject(param) {
  if (isObject(param)) {
    return JSON.stringify(param);
  }
  return param;
}

// Ignore log messages if they have { private: true }
const all = format((info) => {
  const splat = info[SPLAT] || [];
  const message = formatObject(info.message);
  const rest = splat.map(formatObject).join(' ');
  info.message = `${message} ${rest}`;
  return info;
});

const customLogger = createLogger({
  format: combine(
    all(),
    label({ label: version }),
    timestamp(),
    colorize(),
    align(),
    printf(info => `${info.timestamp} [${info.label}] ${info.level}: ${formatObject(info.message)}`)
  ),
  transports: [new transports.Console()]
});

فيما يلي حل بديل شائع للسماح بمعلمات متعددة:
https://github.com/rooseveltframework/roosevelt/blob/master/lib/tools/logger.js#L29

متعلق ب:
https://github.com/winstonjs/winston/issues/1377

هناك الكثير من الأشياء التي لا تعمل بالطريقة نفسها.

مرحبا ، أي تحديثات هنا؟ شكرا.

تنتظر أيضًا الطريقة الصحيحة لمحاكاة console.log(...args) في winston ...

لقد أصلحنا عددًا من حالات الحافة / الزاوية حول splat و meta في 3.2.0 ، لكن يبدو أن هذه لا تزال مشكلة (راجع: https://github.com / winstonjs / winston / pull / 1576 مقابل CHANGELOG.md ).

سوف نتأكد من التعامل مع هذا في 3.3.0 . شكرا يا رفاق صبركم.

كان هذا حلاً لي:

'use strict';

const { createLogger, format, transports } = require('winston');
const { SPLAT } = require('triple-beam');

const { combine, timestamp, label, printf, colorize } = format;

const formatObject = (param) => {
  if (typeof param === 'string') {
    return param;
  }

  if (param instanceof Error) {
    return param.stack ? param.stack : JSON.stringify(param, null, 2);
  }

  return JSON.stringify(param, null, 2);
};

const logFormat = printf((info) => {
  const { timestamp: ts, level, message } = info;
  const rest = info[SPLAT] || [];
  const msg = info.stack ? formatObject(info.stack) : formatObject(message);
  let result = `${ts} ${level}: ${msg}`;

  if (rest.length) {
    result += `\n${rest.map(formatObject).join('\n')}`;
  }

  return result;
});

const logger = createLogger({
  format: combine(
    label({ label: 'app' }),
    timestamp(),
    logFormat,
  ),
  transports: [
    new transports.Console({
      format: combine(colorize()),
      handleExceptions: true,
    }),
  ],
  exceptionHandlers: [
    new transports.File({ filename: 'exceptions.log' }),
  ],
});

عندما أحاول التسجيل بالحجج أحصل على إخراج غريب
var s = "Hello" log.info("asdasda", s)

الحصول على الإخراج

{"0":"H","1":"e","2":"l","3":"l","4":"o","service":"XXXX","level":"info","message":"asdasda","timestamp":"2019-04-15 13:58:51"}

لقد استخدمت رمز البدء السريع العادي

شيء واحد لاحظته هو هذا:

  • حصلت على المسجل مع 2 من النقل (وحدة التحكم والملف الدوار)
  • كلاهما يستخدم تنسيق splat
  • يؤدي استدعاء وظيفة التحويل الخاصة بـ splat من أجل النقل الأول إلى مسح المصفوفة المخزنة على المعلومات ضمن رمز SPLAT
  • عند استدعاء وظيفة التحويل لـ splat للنقل الثاني ، تكون مصفوفة SPLAT فارغة وبالتالي لا يتم تسجيل الوسائط الإضافية بعد الآن

آمل أن هذا يمكن / سيتم إصلاحه

ملاحظة: اختبرت هذا باستخدام أحدث إصدار تم إصداره من Winston ، ويبدو أن نظرة سريعة على الكود تشير إلى أنه لا يزال على هذا النحو (الذي يحتوي على إصلاحات أخرى على ما يبدو)

بعض التحسينات على حلluislobo الصورة 👏

  • تجاهل الرسالة إذا كانت تحتوي على نمط splat ، أي تحتوي على %s %d or %j لرسائل مثل logger.info(`hello %s`,'world')
  • إعادة ترتيب أدوات التنسيق لجعل التلوين يأتي أولاً https://github.com/winstonjs/winston#colorizing -standard-logging-levels
  • تمت إزالة twise formateObject في printf
  • trimEnd إذا لم يتم توفير وسيطات الإضافة في Looger
const { version } = require('../package');

const { createLogger, format, transports } = require('winston');
const { combine, timestamp, colorize, label, printf, align } = format;
const { SPLAT } = require('triple-beam');
const { isObject,trimEnd } = require('lodash');

function formatObject(param) {
  if (isObject(param)) {
    return JSON.stringify(param);
  }
  return param;
}

const all = format((info) => {
  const splat = info[SPLAT] || []

    const isSplatTypeMessage =
        typeof info.message === 'string' &&
        (info.message.includes('%s') || info.message.includes('%d') || info.message.includes('%j'))
    if (isSplatTypeMessage) {
        return info
    }
    const message = formatObject(info.message)
    const rest = splat
        .map(formatObject)
        .join(' ')
    info.message = trimEnd(`${message} ${rest}`)
    return info
});

const customLogger = createLogger({
  format: combine(
    colorize(),
    all(),
    label({ label: version }),
    timestamp(),
    align(),
    printf(info => `${info.timestamp} [${info.label}] ${info.level}: ${info.message}`)
  ),
  transports: [new transports.Console()]
});

هل هناك أي تحديث آخر لهذا قد يكون في عداد المفقودين؟ يبدو أن هناك دعمًا قويًا لإعادة إضافة هذه الميزة ، لكن الالتزام الأخير بهذا كان منذ ما يقرب من 6 أشهر.

مرحبًا ، هناك مصد ضخم وسدادة عرض ، تحاول الانتقال إلى 3.X ، وربما ستحتفظ بـ 2.x لفترة من الوقت.

قليلا بخيبة أمل :(

هذا ما نجح معي:

const { format, createLogger, transports } = require('winston');
const jsonStringify = require('fast-safe-stringify');

const logLikeFormat = {
  transform(info) {
    const { timestamp, label, message } = info;
    const level = info[Symbol.for('level')];
    const args = info[Symbol.for('splat')];
    const strArgs = args.map(jsonStringify).join(' ');
    info[Symbol.for('message')] = `${timestamp} [${label}] ${level}: ${message} ${strArgs}`;
    return info;
  }
};

const debugFormat = {
  transform(info) {
    console.log(info);
    return info;
  }
};

const logger = createLogger({
  format: format.combine(
    // debugFormat, // uncomment to see the internal log structure
    format.timestamp(),
    format.label({ label: 'myLabel' }),
    logLikeFormat,
    // debugFormat, // uncomment to see the internal log structure
  ),
  transports: [
    new transports.Console()
  ]
});


logger.info('foo', 'bar', 1, [2, 3], true, { name: 'John' });

والذي ينتج عنه: 2019-07-04T21:30:08.455Z [myLabel] info: foo "bar" 1 [2,3] true {"name":"John"}

يعين format.combine أساسًا خط أنابيب لكائن info . لكل دالة تنسيق ، يتم استدعاء transform ويجب كتابة رسالة السجل النهائية على info[Symbol.for('message')]
أتمنى أن يساعدك هذا

أردت حلاً يدعم %d ، %o إلخ ، ولكن لا يزال يتم تضمين أي وسيطات بشكل افتراضي ، بحيث يتم عرض logger.info('hello %d %j', 42, {a:3}, 'some', 'more', 'arguments') النحو التالي:

hello 42 {"a": 3} some more arguments

انتهى الحل باستخدام الرمز splat ولكن استدعى يدويًا util.format() مباشرة من printf ، والذي يتضمن افتراضيًا أي وسيطات راحة:

const {format} = require('util');
const winston = require('winston');
const {combine, timestamp, printf} = winston.format;
const SPLAT = Symbol.for('splat');

const transport = new winston.transports.Console({
    format: combine(
        timestamp(),
        printf(({timestamp, level, message, [SPLAT]: args = []}) =>
            `${timestamp} - ${level}: ${format(message, ...args)}`)
    )
})

إذا كنت لا تريد printf يمكنك بالطبع إضافة تحويل يقوم ببساطة بتوسيع args إلى info.message ، ثم تنسيق النتيجة النهائية بالطريقة التي تريدها:

format: combine(
  {
    transform(info) {
      const {[SPLAT]: args = [], message} = info;

      info.message = format(message, ...args);

      return info;
    }
  },
  simple()
)  

تكمن مشكلة استخدام format.splat() أنه يستهلك وسيطات المطابقة ولكن يبدو أنه يتخلص من الباقي. من خلال استدعاء util.format() بنفسي ، يمكنني تجاوز هذا السلوك.

نفس المشكلة ، أي تحديث بخصوص هذا واحد؟ أنا أحب وينستون ، لكن هذا يصيبني بالجنون عندما لا أستطيع طباعة جميع الوسائط التي تم تمريرها إلى المسجل ، وهو ما يمكنني فعله باستخدام console.log() .

@ fr1sk هل جربت التنسيق أعلاه؟ إنه يعطي console.log() مثل السلوك (تنفيذ العقدة console.log() يستخدم داخليًا util.format() afaik).

إنه لأمر مخيب للآمال أن هذه المشكلة لم يتم حلها بعد ، وأن مشكلتي ذات الصلة قد تم إغلاقها.
أنا أعمل مع العديد من الفرق المختلفة وهم جميعًا يشاركونني الإحباط الناتج عن فقدان DX السابق عند الانتقال إلى الإصدار 3.

لقد أمضيت يومًا كاملاً في تجربة الأشياء.
كانت الحلول المذكورة أعلاه قريبة ولكني كنت أفتقد التلوين وكسر الأسطر للحجج الإضافية.

IMO ، يجب أن يكون تسجيل الدخول إلى وحدة التحكم أمرًا ممتعًا.
ها هي محاولتي لتحقيق ذلك ...

الإعداد v2 للمقارنة

const winston = require('winston');
const chalk = require('chalk');

const logger = new winston.Logger({
  transports: [
    new winston.transports.Console({
      level: 'info',
      colorize: true,
      prettyPrint: true,
      timestamp: true
    })
  ]
});

logger.info({ one: 1, two: 2, three: 3 });
logger.info(chalk.blue('[TEST]:'), { one: 1, two: 2, three: 3 }, [4, 5, 6]);
logger.info(chalk.blue('[TEST]:'), null, undefined, 'one', 2, { 3: 3, 4: '4' });
logger.info(chalk.blue('[TEST]:'), chalk.yellow('Bombastic'), () => {}, /foo/);
logger.error(chalk.blue('[ERR]:'), new Error('Error number 1'));
logger.error(new Error('Error number 2'));

Winston2

v3 الإعداد

const { createLogger, format, transports } = require('winston');
const { inspect } = require('util');
const chalk = require('chalk');
const hasAnsi = require('has-ansi');

function isPrimitive(val) {
  return val === null || (typeof val !== 'object' && typeof val !== 'function');
}
function formatWithInspect(val) {
  const prefix = isPrimitive(val) ? '' : '\n';
  const shouldFormat = typeof val !== 'string' || !hasAnsi(val);

  return prefix + (shouldFormat ? inspect(val, { depth: null, colors: true }) : val);
}

const logger = createLogger({
  level: 'info',
  format: format.combine(
    format.timestamp(),
    format.errors({ stack: true }),
    format.colorize(),
    format.printf(info => {
      const msg = formatWithInspect(info.message);
      const splatArgs = info[Symbol.for('splat')] || [];
      const rest = splatArgs.map(data => formatWithInspect(data)).join(' ');

      return `${info.timestamp} - ${info.level}: ${msg} ${rest}`;
    })
  ),
  transports: [new transports.Console()]
});

logger.info({ one: 1, two: 2, three: 3 });
logger.info(chalk.blue('[TEST]:'), { one: 1, two: 2, three: 3 }, [4, 5, 6]);
logger.info(chalk.blue('[TEST]:'), null, undefined, 'one', 2, { 3: 3, 4: '4' });
logger.info(chalk.blue('[TEST]:'), chalk.yellow('Bombastic'), () => {}, /foo/);
logger.error(chalk.blue('[ERR]:'), new Error('Error number 1'));
logger.error(new Error('Error number 2'));

Winston3

هناك العديد من الأشياء التي يجب التعامل معها ، وبعضها

  • قيمة تشبه الكائن كالوسيطة الأولى
  • عدة حجج للقيم المختلطة
  • سلاسل بأكواد هروب ANSI ، على سبيل المثال باستخدام chalk
  • القيم الباطنية مثل Function و RegEx
  • خطأ كوسيطة أولى أو في أي مكان بعد ذلك
  • يجب أن تظل تعمل بشكل جيد جنبًا إلى جنب مع التنسيقات الأخرى

البق الحالي مع هذا الحل

  • لا يؤدي تمرير خطأ كالوسيطة الأولى إلى طباعة Stack Trace

    • هذا لأن info.message مجرد سلسلة وأن مسار المكدس موجود في خاصية stack

  • تمرير كائن بخاصية message كالوسيطة الأولى يطبع message ، مع تجاهل أي خصائص أخرى

    • نفس السبب كما هو مذكور أعلاه

  • يؤدي تمرير خطأ كوسيطة ثانية إلى ربط رسالة الخطأ فوق info.message (وهي عادةً قيمة الوسيطة الأولى) ، مما يؤدي إلى رؤية رسالة الخطأ مرتين

    • تتبعها في https://github.com/winstonjs/winston/issues/1660

    • هذا في الواقع جزء من README:

      > ملاحظة: أي خاصية {message} في كائن meta يتم توفيرها تلقائيًا سيتم ربطها بأي رسالة سبق تقديمها: على سبيل المثال ، سيتم ربط "world" بـ "hello":

لم يساعد اللعب مع منسق errors .

التحسينات الإيجابية

  • أصبح تسجيل القيم البدائية الآن أجمل
  • يضيف تسجيل العديد من القيم الشبيهة بالكائنات الآن سطرًا جديدًا بينها
  • أصبح تسجيل المصفوفة محسّنًا الآن بدلاً من أن يبدو ككائن بمفاتيح مؤشرات

تعديل:

يمكننا التعامل مع أخطاء التنسيق ولكنها اختراق:

function formatWithInspect(val) {
+ if (val instanceof Error) {
+   return '';
+ }

  const prefix = isPrimitive(val) ? '' : '\n';
  const shouldFormat = typeof val !== 'string' || !hasAnsi(val);

  return prefix + (shouldFormat ? inspect(val, { depth: null, colors: true }) : val);
}

...
    format.printf((info) => {
      const msg = formatWithInspect(info.message);
      const splatArgs = info[Symbol.for('splat')] || [];
      const rest = splatArgs.map((data) => formatWithInspect(data)).join(' ');
+    const stackTrace = info.stack ? `\n${info.stack}` : '';

      return `${info.timestamp} - ${info.level}: ${msg} ${rest}${stackTrace}`;
    })
...

إنه يعمل معي باستخدام info[Symbol.for('splat')]

const logger = winston.createLogger({
    level: 'debug',
    transports: [
        ...
    ],
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.printf((info: any) => {
            const timestamp = info.timestamp.trim();
            const level = info.level;
            const message = (info.message || '').trim();
            const args = info[Symbol.for('splat')];
            const strArgs = (args || []).map((arg: any) => {
                return util.inspect(arg, {
                    colors: true
                });
            }).join(' ');
            return `[${timestamp}] ${level} ${message} ${strArgs}`;
        })
    )
});

أنا أفهم أن الإصدارات الرئيسية تقدم تغييرات جذرية ، لكن يا إلهي ...

لم يمنحني أي من الحلول نفس سلوك winston v2.
الحلول من henhal و yamadashy لها نفس المشكلة: يتم عرض قيمة الرسالة كسلسلة.
إنشاء رسالة سجل logger.debug(err) :

debug:  Error: ETIMEDOUT

بينما logger.debug('anystringhere', err) ينشئ:

debug:  anystringhereError: ETIMEDOUT { RequestError: Error: ETIMEDOUT
    at new RequestError (/path/to/node_modules/request-promise-core/lib/errors.js:14:15)
 <the rest of full error stack here>

المسألة الثانية هي أن الحجج الإضافية يتم قمعها عند الاستخدام مع مستوى المعلومات - يبدو أن Winston v3 يتعامل مع هذه الطريقة الأخرى قبل التنسيق.

المشكلة الثالثة هي الفراغ المفقود بين رسالتين (لاحظ "anystringhereError").

تكوين مسجل v3 الحالي الخاص بي:

const { format } = require('util');
const winston = require("winston");

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      level: 'debug'
      format: winston.format.combine(
          winston.format.colorize(),
          winston.format.align(),
          winston.format.printf(
              ({level, message, [Symbol.for('splat')]: args = []}) => `${level}: ${format(message, ...args)}`
          )
      )
    }),
  ]
});
module.exports = logger;

كان لدي ما يكفي من ذلك وسأعود إلى Winston v2 مع هذا فقط:

const Winston = require("winston");

const logger = new Winston.Logger({
  transports: [
    new Winston.transports.Console({
      level: 'debug',
      handleExceptions: true,
      json: false,
      colorize: true,
    })
  ],
});
module.exports = logger;

لا يحتوي هذا التكوين v2 على المشكلات المذكورة أعلاه.

أرغب في مشاركة إعداد Winston الخاص بي:

const util = require('util');
const { createLogger, format, transports } = require('winston');
const { combine, colorize, timestamp, printf, padLevels} = format;

const myFormat = printf(({ level, message, label, timestamp, ...rest }) => {
    const splat = rest[Symbol.for('splat')];
    const strArgs = splat ? splat.map((s) => util.formatWithOptions({ colors: true, depth: 10 }, s)).join(' ') : '';
    return `${timestamp}  ${level}  ${util.formatWithOptions({ colors: true, depth: 10}, message)} ${strArgs}`;
});

const logger = createLogger({
    level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
    format: combine(
        colorize(),
        timestamp({
            format: 'YYYY-M-DD HH:mm:ss',
        }),
        padLevels(),
        myFormat
    ),
    transports: [new transports.Console()],
});

logger.info('test info');
logger.error('test error');
logger.debug('test debug');

image

فيما يلي حل بديل شائع للسماح بمعلمات متعددة:
https://github.com/rooseveltframework/roosevelt/blob/master/lib/tools/logger.js#L29

هنا رابط محدث للحل المقترح
https://github.com/rooseveltframework/roosevelt/blob/0.13.0/lib/tools/logger.js

المنجم هو نوع من الاقتراحات العظيمة alexilyaev :

const { omit } = require('lodash');
const hasAnsi = require('has-ansi');

function isPrimitive(val) {
  return val === null || (typeof val !== 'object' && typeof val !== 'function');
}
function formatWithInspect(val) {
  if (val instanceof Error) {
    return '';
  }

  const shouldFormat = typeof val !== 'string' && !hasAnsi(val);
  const formattedVal = shouldFormat
    ? inspect(val, { depth: null, colors: true })
    : val;

  return isPrimitive(val) ? formattedVal : `\n${formattedVal}`;
}

// Handles all the different log formats for console
function getDomainWinstonLoggerFormat(format) {
  return format.combine(
    format.timestamp(),
    format.errors({ stack: true }),
    format.colorize(),
    format.printf((info) => {
      const stackTrace = info.stack ? `\n${info.stack}` : '';

      // handle single object
      if (!info.message) {
        const obj = omit(info, ['level', 'timestamp', Symbol.for('level')]);
        return `${info.timestamp} - ${info.level}: ${formatWithInspect(obj)}${stackTrace}`;
      }

      const splatArgs = info[Symbol.for('splat')] || [];
      const rest = splatArgs.map(data => formatWithInspect(data)).join('');
      const msg = formatWithInspect(info.message);

      return `${info.timestamp} - ${info.level}: ${msg}${rest}${stackTrace}`;
    }),
  );
}

لسجلات مثل:

logger.info({
    joe: 'blow',
  });
  logger.info('Single String');
  logger.info('With Func ', () => {}, /foo/);
  logger.info('String One ', 'String Two');
  logger.info('String One ', 'String Two ', 'String Three');
  logger.info('Single Object ', {
    test: 123,
  });
  logger.info(
    'Multiple Objects ',
    {
      test: 123,
    },
    {
      martin: 5555,
    },
  );
  logger.error('Error: ', new Error('Boom!'));

ينتج مثل هذا - وهو أمر جيد لجميع السيناريوهات الخاصة بي:

Screen Shot 2020-02-06 at 10 54 31 pm

مرحبًا ، أنا أبدأ بـ Winston ، لم أستخدم الإصدار 2 مطلقًا ، لذا فأنا على الإصدار 3.2.1

كنت أحاول ببساطة أن أفعل:

import winston, { format } from 'winston';
winston.format(format.combine(format.splat(), format.simple()));

winston.info('buildFastify dataPath %s', opts.dataPath);

وتأمل أن يعمل الاستيفاء الخيطي ؛ لكن كلا.

{"level":"info","message":"buildFastify dataPath %s"}

عندما كنت أتوقع

{"level":"info","message":"buildFastify dataPath /My/Data/Path"}

هذه القضية هي نفس الشيء بطريقة أو بأخرى؟ أم أنني مجبر على استخدام الدالة logger.log('info', .....) بدلاً من ذلك؟

تعديل

الحدث الذي يحاول هذا لا يعمل.

  winston.log('info', 'buildFastify dataPath %s', opts.dataPath);

انتاج:

{"level":"info","message":"buildFastify dataPath %s"}

شكرا لمن نشر الاقتراحات أعلاه.
اللعنة ، لقد رميت يومًا ما فقط لدمج Winston 3 في مشروعي: /

لقد أصابني هذا اليوم - أدركت أن أداة التسجيل الجديدة الرائعة الخاصة بي كانت ترمي جميع حججتي ...rest . قد لا يعمل هذا مع الجميع أو كل حالة استخدام ، ولكن في حالتي وجدت أنه من المقبول فقط تغليف كل ما أريد تسجيله كمصفوفة. إنها ليست الأجمل ، لكنها أخف من بعض الحلول [الذكية جدًا] التي تتطلب المزيد من التعليمات البرمجية. آمل أن يساعد هذا شخص آخر!

logger.info(["Something happened!", foo, bar]);

مزعج حقًا أنهم قرروا إجراء تغيير كبير بهذا الحجم وما زالوا لم

بغض النظر عن رغبتي في مشاركة الحل الذي وجدته مضغوطًا تمامًا ويتبع كيفية تنفيذ node js لـ console.log باستخدام util.format

const winstonLogger= createLogger(...);

const writeLogType = (logLevel) => {
    return function () {
        const args = Array.from(arguments);
        winstonLogger[logLevel](util.format(...args));
    };
};

const logger = {
    silly: writeLogType('silly'),
    debug: writeLogType('debug'),
    verbose: writeLogType('verbose'),
    info: writeLogType('info'),
    warn: writeLogType('warn'),
    error: writeLogType('error'),
};

أرغب في الاتصال وطلب إضافة هذه الميزة إلى جوهر Winston. حاليًا ، أنا أستخدم المنسق المخصص بـ splat لتحقيق هذه الوظيفة ، والتي تبدو بصراحة شديدة الاختراق. سيكون من الجيد أن يكون لديك وظائف تتطابق مع console.log

أي تحديثات؟

إلى جانب السلوكيات المذكورة أعلاه لـ v3 ، أود إضافة هذا أيضًا:

logger.info('param 1', { propInJson1: 'propInJson 1', propInJson2: 'propInJson 2' });

سينتج هذا

{"propInJson1":"propInJson 1","propInJson2":"propInJson 2","level":"info","message":"param 1"}

الإصدار الذي أستخدمه: (v3.2.1)
التكوينات:

winstonLogger.add(new winston.transports.Console());

ما زلت لا أفهم كيفية إخراج قيم متعددة في Winston.

أردت فقط استبدال console.log('Hello', var1, '!') بـ logger.log('Hello', var1, '!') .

بصراحة ، تؤدي محاولة استخدام Winston دائمًا إلى إهدار الكثير من الوقت ومشاكل مفاجئة في التسجيل.

مزعج حقًا أنهم قرروا إجراء تغيير كبير بهذا الحجم وما زالوا لم

بغض النظر عن رغبتي في مشاركة الحل الذي وجدته مضغوطًا تمامًا ويتبع كيفية تنفيذ node js لـ console.log باستخدام util.format

const winstonLogger= createLogger(...);

const writeLogType = (logLevel) => {
    return function () {
        const args = Array.from(arguments);
        winstonLogger[logLevel](util.format(...args));
    };
};

const logger = {
    silly: writeLogType('silly'),
    debug: writeLogType('debug'),
    verbose: writeLogType('verbose'),
    info: writeLogType('info'),
    warn: writeLogType('warn'),
    error: writeLogType('error'),
};

أيضًا ، استخدم util.formatWithOptions({ colors: true }, ...args); للحصول على مخرجات طباعة ملونة كما هو الحال مع console.log العادي

هذا يعمل بالنسبة لي. combineMessageAndSplat يجمع بين الرسالة و splat باستخدام صيغة util.format

const winston = require("winston");
const util    = require('util');

const combineMessageAndSplat = () => {
    return {transform: (info, opts) => {
      //combine message and args if any
      info.message =  util.format(info.message, ...info[Symbol.for('splat')]  ||  [] )
      return info;
    }
  }
}

const logger = winston.createLogger({
  format:
    winston.format.combine(
      combineMessageAndSplat(),
      winston.format.simple()
    )
});

logger.add(new winston.transports.Console({
    level: 'info'
  })
);

logger.info("string");          // info: string
logger.info({a:1,b:[{c:[1]}]}); // info: { a: 1, b: [ { c: [Array] } ] }
logger.info("1","2",{a:1});     // info: 1 2 { a: 1 }
logger.info([{},""]);           // info: [ {}, '' ]
logger.error(new Error());      // error: Error ...    at Object.<anonymous> 

كان علي أن أتوافق مع أساليب وحدة التحكم * ، والتوجيه على كل ما سبق ، و ...

  • طرق وحدة التحكم الافتراضية (يتم تلوينها افتراضيًا) لأدوات chrome-dev
  • خرج وحدة التحكم في الإلكترونات (ملون أيضًا افتراضيًا)
  • الكتابة إلى ملف

لكن: يجب أن يُظهر إخراج الملف تفاصيل الكائن.

لذلك انتهى بي الأمر بـ:

// make File and FileList parseable // from: https://stackoverflow.com/a/51939522/1644202
File.prototype.toObject = function () {
    return Object({
        name: String(this.name),
        path: String(this.path),
        lastModified: parseInt(this.lastModified),
        lastModifiedDate: String(this.lastModifiedDate),
        size: parseInt(this.size),
        type: String(this.type)
    });
};

FileList.prototype.toArray = function () {
    return Array.from(this).map(function (file) {
        return file.toObject()
    });
};

// this fixes: winston console transport to use the original console functions and all the colorization/folding/etc that comes with it
const Transport = require('winston-transport');
class WebDeveloperConsole extends Transport {
    constructor(opts) {
        super(opts);
    }

    log(info, callback) {
        (window.console[info.level] || window.console.log).apply(window.console, [info.timestamp, ...info.message]);
        callback();
    }
};

// Electron app console output
class AppConsole extends Transport {
    constructor(opts) {
        super(opts);

        const { remote } = require('electron');
        this.electronConsole = remote.getGlobal('console');
    }

    log(info, callback) {
        (this.electronConsole[info.level] || this.electronConsole.log).apply(this.electronConsole, [info.timestamp, ...info.message]);
        callback();
    }
};

const util = require('util');
const {
    createLogger,
    transports,
    format
} = require('winston');

let logger = createLogger({
    level: 'trace',
    levels: {
        error: 0,
        warn: 1,
        info: 2,
        //http: 3,   no console.* methods
        //verbose: 4,
        debug: 3,
        trace: 4
    },

    format: format.combine(
        format.prettyPrint(),
        format.timestamp({
            format: 'DD-MM-YYYY hh:mm:ss A'
        }),

        {
            transform(info) {
                const { timestamp, message } = info;
                const level = info[Symbol.for('level')];
                const args = [message, ...(info[Symbol.for('splat')] || [])];  // join the args back into one arr
                info.message = args;  // for all custom transports (mainly the console ones)

                let msg = args.map(e => {
                    if (e.toString() == '[object FileList]')
                        return util.inspect(e.toArray(), true, 10);
                    else if (e.toString() == '[object File]')
                        return util.inspect(e.toObject(), true, 10);
                    else if (e.toString() == '[object Object]') {
                        return util.inspect(e, true, 5);
                    }
                    else if (e instanceof Error)
                        return e.stack
                    else
                        return e;
                }).join(' ');

                info[Symbol.for('message')] = `${timestamp} - ${level}: ${msg}`; // for inbuild transport / file-transport

                return info;
            }
        },
    ),
    transports: [
        //new transports.Console(),
        new WebDeveloperConsole(),
        new AppConsole(),
        ...
    ],
    ...
});

indexzero هل كنت تتساءل عما إذا كنت لا تزال تخطط لمعالجة هذا الأمر في وقت ما؟

أنا أستكشف winston لاستخدامه في مشروعي ، وأتساءل الآن هل يستحق المخاطرة لأن هذه المشكلة مفتوحة لأكثر من عامين. بالنسبة لي ، تبدو هذه وظيفة أساسية لأي إطار عمل للتسجيل

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات