Winston: يبدو أن 3.0 يقوم بتسجيل {} كائنات الخطأ

تم إنشاؤها على ١٩ مارس ٢٠١٨  ·  12تعليقات  ·  مصدر: winstonjs/winston

تحية للجميع
أواجه بعض المتاعب مع Winston 3.0 تسجيل كائنات الخطأ الفارغة عند استخدام تنسيق json.

module.exports = winston.createLogger({
  format: format.combine(
    format.label({ label: 'my label'}),
    format.timestamp(),
    format.prettyPrint()
  ),
  transports: [
    new (winston.transports.Console)({
      level: error
    })
  ]
}); 

يسجل المتوقع

 {error: [stack trace here] }
 ```

 while 

module.exports = winston.createLogger ({
التنسيق: format.combine (
format.label ({label: 'my label'}) ،
format.timestamp () ،
format.json ()
) ،
النقل: [
جديد (winston.transports.Console) ({
المستوى: خطأ
})
]
}) ؛

logs the erroneous

{خطأ: {} }

when it is passed 

logger.log ({
خطأ: خطأ جديد ("رسالة الخطأ الخاصة بي")
}) ؛

Manually creating a format with 

winston.format.printf
""
عاد أيضًا النتيجة الخاطئة.

هل يعرف أي شخص حل بديل لهذا؟

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

نسخة أكثر إيجازًا:

function format() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

const logger = createLogger({
  format: format(),
});

ولكن هذا ما أفعله في الواقع للحصول على سجلات جميلة محليًا وأخطاء JSON في الإنتاج:

function prodFormat() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

function devFormat() {
  const formatMessage = info => `${info.level} ${info.message}`;
  const formatError = info => `${info.level} ${info.message}\n\n${info.stack}\n`;
  const format = info => info instanceof Error ? formatError(info) : formatMessage(info);
  return combine(colorize(), printf(format))
}

const logger = createLogger({
  level: process.env.LOG_LEVEL || 'info',
  exitOnError: false,
  transports: [new transports.Console()],
  format: isProd ? prodFormat() : devFormat(),
});

الذي يعطيني هذا في الإنتاج

bildschirmfoto 2018-09-21 um 16 46 35

وهذا قيد التطوير

bildschirmfoto 2018-09-21 um 16 47 04

ال 12 كومينتر

الحل:

function errorReplacer(key, value) {
  if (value instanceof Error) {
    return { message: value.message, stack: value.stack };
  }
  return value;
}

const logFormat = winston.format.printf((info) => {
  return `${JSON.stringify(info, errorReplacer)}`;
});

module.exports = winston.createLogger({
  format: format.combine(
    format.label({ label: 'my label' }),
    format.timestamp(),
    logFormat
  ), ...

آمل أن يساعد.

لم يعمل الحل البديل بالنسبة لي (تضيع رسالة المعلومات في مكان ما)

الحل البديل:

const winston = require('winston')
const MESSAGE = Symbol.for('message')

/*
 * function replacer (key, value)
 * Handles proper stringification of Buffer output.
 */
const replacer = function (key, value) {
  return value instanceof Buffer
    ? value.toString('base64')
    : value
}

var json_log = winston.format(function (info, opts) {
  var display = info
  if (info._error) {
    display = Object.assign({}, info, { message: info._error })
    delete display._error
  }
  info[MESSAGE] = JSON.stringify(display, opts.replacer || replacer, opts.space)
  return info
})

var preserve_error_message = format(function (info, opts) {
  if (_.isError(info)) {
    info._error = info.message
  }
  return info
})

const logger = winston.createLogger({
  levels: ...,
  format: format.combine(format.timestamp(), preserve_error_message()),
  transports: [
    new transports.Console({
    level: this.config.console.level,
    format: json_log({ space: 2 })
  })
]

هذا لا يبدو أنيقًا بشكل خاص ، لذا فإن المسؤول عن الحفاظ على info.message عندما يكون info Error سيكون مثاليًا (يعمل عندما يكون info عاديًا موضوع)

أنا أواجه هذا أيضًا. ألا يجب على وينستون التعامل مع هذا خارج الصندوق؟ indexzero ما رأيك في هذا؟

بعد النظر في تنفيذ logform json ، أرى الآن كيف يُفترض أن يتم استخدام opts.replacer وتوصلت إلى حل آخر عند الجمع بين مشاركة التدوير المكدس

'use strict';

const winston = require('../');

const logger = winston.createLogger({
    format: winston.format.combine(
        winston.format.json({ replacer: replaceErrors })
    ),
    transports: [
        new winston.transports.Console(),
    ]
});

function replaceErrors(key, value) {
    if (value instanceof Buffer) {
        return value.toString('base64');
    } else if (value instanceof Error) {
        var error = {};

        Object.getOwnPropertyNames(value).forEach(function (key) {
            error[key] = value[key];
        });

        return error;
    }

    return value;
}


var error = new Error('foooo');
error.my_custom_stuff = 'bar';

logger.log('error', 'Hello, this is a raw logging event', { error });

الذي يطبع:

{"error":{"stack":"Error: foooo\n    at Object.<anonymous> (/home/dino/work/winston/examples/json.js:31:13)\n    at Module._compile (module.js:662:30)\n    at Object.Module._extensions..js (module.js:673:10)\n    at Module.load (module.js:575:32)\n    at tryModuleLoad (module.js:515:12)\n    at Function.Module._load (module.js:507:3)\n    at Function.Module.runMain (module.js:703:10)\n    at startup (bootstrap_node.js:193:16)\n    at bootstrap_node.js:660:3","message":"foooo","my_custom_stuff":"bar"},"level":"error","message":"Hello, this is a raw logging event"}

لم أعد أعتقد أنه يجب التعامل مع هذا الأمر خارج الصندوق ، لأنني أعتقد أن مكتبة التسجيل يجب ألا تحدد كيفية تسلسل خطأك في رسالة سجل ، فأنت تحدد ذلك بنفسك.

لست متأكدًا من حالة الاستخدام بالضبط ولكن لماذا لا تقوم بتسجيل الأخطاء بشكل مباشر:

logger.log(new Error('my error message'));

(هذا يعمل اعتبارًا من https://github.com/winstonjs/winston/pull/1234).

إذا كنت بحاجة إلى كائن الخطأ داخل كائن أكبر تقوم بتسجيله ، فمن الجدير بالذكر أن Node.js Errors ليست كائنات JSON ، ولكن هناك أشياء مثل https://www.npmjs.com/package / utils-error-to-json أو ربما عمل parse(stringify(error)) الذي سيجعل هذا يعمل مع مُنسق JSON. يبدو أن هذا ما يفعله حل

المضي قدمًا ووضع علامة مغلق ، لا تتردد في إعادة فتح أو إنشاء مشكلة جديدة إذا ظهرت مشاكل / أسئلة جديدة! شكرا!

لا يعمل حتى parse(stringify(error)) لأنك لا تزال تفقد تتبع المكدس.
تمكنت من القيام بهذا العمل من خلال إنشاء تنسيق مخصص مثل هذا:

const formatErrorConverter = winston.format(
    info =>
        info instanceof Error
            ? Object.assign({ level: info.level, message: info.message, stack: info.stack }, info)
            : info,
);

وهي تعمل بشكل جيد!

instance of Error يعمل فقط مع منسق المستوى الأعلى. لا يعمل مع المنسقين على مستوى النقل. يمكن لأي شخص أن يشرح لماذا؟

نسخة أكثر إيجازًا:

function format() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

const logger = createLogger({
  format: format(),
});

ولكن هذا ما أفعله في الواقع للحصول على سجلات جميلة محليًا وأخطاء JSON في الإنتاج:

function prodFormat() {
  const replaceError = ({ label, level, message, stack }) => ({ label, level, message, stack });
  const replacer = (key, value) => value instanceof Error ? replaceError(value) : value;
  return combine(label({ label: 'ssr server log' }), format.json({ replacer }));
}

function devFormat() {
  const formatMessage = info => `${info.level} ${info.message}`;
  const formatError = info => `${info.level} ${info.message}\n\n${info.stack}\n`;
  const format = info => info instanceof Error ? formatError(info) : formatMessage(info);
  return combine(colorize(), printf(format))
}

const logger = createLogger({
  level: process.env.LOG_LEVEL || 'info',
  exitOnError: false,
  transports: [new transports.Console()],
  format: isProd ? prodFormat() : devFormat(),
});

الذي يعطيني هذا في الإنتاج

bildschirmfoto 2018-09-21 um 16 46 35

وهذا قيد التطوير

bildschirmfoto 2018-09-21 um 16 47 04

لقد كتبت هذا لدعم فئات الخطأ المخصصة ذات الخصائص غير المعروفة ، وكذلك لتنظيف المكدس لأن هذه الأسطر الجديدة مروعة في التسجيل المستند إلى json.

const replacer = (key, value) => {
  if (value instanceof Error) {
    return Object.getOwnPropertyNames(value).reduce((all, valKey) => {
      if(valKey === 'stack') {
        return {
          ...all,
          at: value[valKey].split('\n').filter(va => va.trim().slice(0, 5) != 'Error').map((va, i) => `stack ${i} ${va.trim().slice(3).trim()}`)
        }
      } else {
        return {
          ...all,
          [valKey]: value[valKey]
        }
      }

    }, {});

  } else {
    return value;
  }
}

نتيجة:

{"at":["stack 0 /Users/sarahriehl/Documents/code/boilerplate/logging/routes/log.js:24:15","stack 1 Layer.handle [as handle_request] (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/layer.js:95:5)","stack 2 next (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/route.js:137:13)","stack 3 Route.dispatch (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/route.js:112:3)","stack 4 Layer.handle [as handle_request] (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/layer.js:95:5)","stack 5 /Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:281:22","stack 6 Function.process_params (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:335:12)","stack 7 next (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:275:10)","stack 8 Function.handle (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:174:3)","stack 9 router (/Users/sarahriehl/Documents/code/boilerplate/logging/node_modules/express/lib/router/index.js:47:12)"],"message":"argh!!!","level":"error","timestamp":"Thu 2019-02-14 01:58:58 -0600"}

لقد صنعت مثالاً لبيئة التنمية المحلية و GCP Stackdriver Logging .

https://github.com/mrdulin/blog/issues/75

كنت أواجه نفس المشكلة لذا كتبت هذه الحزمة ، utils-deep-clone . تحقق من ذلك.

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