Winston: [3.0.0] Objek kesalahan tidak diurai atau dicetak

Dibuat pada 29 Mei 2018  ·  68Komentar  ·  Sumber: winstonjs/winston

Beri tahu kami tentang lingkungan Anda:

  • _ winston versi? _
  • _ node -v keluaran: _ v8.11.1
  • _Sistem Operasi? _ (Windows, macOS, atau Linux) macOS
  • _Language? _ (Semua | TypeScript XX | ES6 / 7 | ES5 | Dart) Semua

Apa masalahnya?

Membuat log objek Error menghasilkan pesan kosong:

Contoh:

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

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

let err = new Error('this is a test');
logger.log({level: 'error', message: err});

Hasil keluaran:

% node test.js
{"level":"error","message":{}}

Juga:

logger.error(new Error('hello'))

Hasil dalam:

{"level":"error"}

Apa yang Anda harapkan terjadi?

Saya Berharap kunci pesan memiliki setidaknya pesan kesalahan yang disertakan di dalamnya. Jika saya mencoba pemformat khusus, info juga tidak memiliki objek kesalahan di dalamnya sehingga harus dihapus di suatu tempat?

Informasi lainnya

Beri tahu saya bagaimana saya bisa membantu - senang menjentikkan PR tetapi saya belum tahu cara saya sekitar [email protected] cukup untuk menemukannya

bug important

Komentar yang paling membantu

Tidak juga, ini tidak dapat diterima untuk perpustakaan logging.
Maintainer harus meletakkan contoh yang disorot dengan baik pada dokumen di mana ditunjukkan cara mencatat kesalahan, bahkan menentukan format printf kustom dan format non json dan di mana Anda dapat mencatat kesalahan dengan sesuatu seperti logger.error ("sesuatu", err) dan logger .error (err)
Winston tampaknya hebat tetapi masalah ini sangat tidak dapat diterima

Semua 68 komentar

Kami memiliki beberapa cakupan tes untuk ini, tetapi jelas kami membutuhkan lebih banyak. Apa yang terjadi di balik selimut:

  1. Instance Error diteruskan di sepanjang rantai pipa aliran objectMode
  2. Format default untuk Logger adalah json (lihat: json kode format logform )
  3. Properti message dan stack pada Error tidak dapat dihitung yang menyebabkan JSON.stringify mengeluarkan sesuatu yang tidak diharapkan.
console.log(JSON.stringify(new Error('lol nothing here')));
// '{}'

Dari perspektif desain winston@3 memperkenalkan formats untuk masalah seperti ini guna meningkatkan kinerja. Berbicara tentang kinerja, cukup menarik pino melakukan sesuatu yang menarik di sini . Mungkin solusinya adalah mengimplementasikan sesuatu yang mirip dengan asJson dalam format default json .

Jika ada yang mencari solusi cepat, Anda dapat menyertakan enumerateErrorFormat dalam format logger Anda untuk saat ini. Mudah-mudahan kami akan memperbaikinya sebelum 3.0.0 minggu depan (atau segera setelahnya di 3.0.1 )

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

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

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

// Error as message
console.log('Run FIRST test...');
logger.log({ level: 'error', message: new Error('FIRST test error') });

// Error as info (one argument)
console.log('\nRun SECOND test...');
const err = new Error('SECOND test error');
err.level = 'info';
logger.info(err);

// Error as info (two arguments);
console.log('\nRun THIRD test...');
logger.log('info', new Error('THIRD test error'));

@indexzero , saya mencoba mengikuti solusi Anda, tetapi tidak berhasil. Apa kamu tahu kenapa?

Pemformat:
`` `` javascript const level = settings.debug ? 'debug' : 'info'; const printFormat = winston.format.printf(info => $ {info.timestamp} - $ {info.level}: $ {info.message} `);
const enumerateErrorFormat = winston.format (info => {
if (info.message instanceof Error) {
info.message = Object.assign ({
pesan: info.message.message,
tumpukan: info.message.stack,
}, info.message);
}
if (info kejadian Error) {
return Object.assign ({
pesan: info.message,
tumpukan: info.stack,
}, info);
}
mengembalikan info;
});

const consoleLogger = winston.createLogger ({
tingkat,
format: winston.format.timestamp (),
transportasi: [
winston.transports.Console baru ({
format: winston.format.combine (
winston.format.colorize (),
enumerateErrorFormat (),
printFormat,
),
}),
],
});
Code: javascript
coba {
// Beberapa kesalahan melempar kode
} tangkap (err) {
logger.error (err);
}
Output:
2018-06-28T21: 17: 25.140Z - error: tidak ditentukan
Info object: javascript
{level: '\ u001b [31merror \ u001b [39m', stempel waktu: '2018-06-28T21: 17: 25.140Z', [Simbol (level)]: 'error'}
`` ''
Di manakah atribut pesan di log kesalahan?

@sandrocsimas Saya perhatikan bahwa Anda perlu memberikan fungsi enumerateErrorFormat ke pemformat default dari logger untuk membuatnya berfungsi.

Formatter

const consoleLogger = winston.createLogger({
  level,
  format: winston.format.combine(
    winston.format.timestamp(),
    enumerateErrorFormat()
  ),
  transports: [
    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.colorize(),
        printFormat,
      ),
    }),
  ],
});

Saya masih tidak mengerti mengapa demikian

Sepertinya saya mengalami bug yang sama dengan @sandrocsimas.

Ini adalah konfigurasi logger saya:

logger.js

const winston = require('winston');
const {configure, format} = winston;
const {combine, colorize, timestamp, printf} = format;

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const myConsoleFormat = printf(info => {
  console.log('** Info Object: **');
  console.log(info);
  console.log('** Winston Output: **');
  return `${info.level}: ${info.message}`;
});

winston.configure({
  transports: [
    new winston.transports.Console({
      format: combine(
        colorize(),
        enumerateErrorFormat(),
        myConsoleFormat
      ),
    })
  ]
});

Jika saya mengujinya dengan blok kode ini:

Tes A

const logger = require('winston');
try {
  throw(new Error());
} catch (err) {
  logger.error(err);
}

di mana new Error() tidak mengandung nilai pesan, saya mendapatkan output ini:

Keluaran A

** Info Object: **
{ message: 
   { message: '',
     stack: 'Error\n    at Object.<anonymous> (app.js:21:9)\n    at Module._compile (module.js:652:30)\n    at Object.Module._extensions..js (module.js:663:10)\n    at Module.load (module.js:565:32)\n    at tryModuleLoad (module.js:505:12)\n    at Function.Module._load (module.js:497:3)\n    at Module.require (module.js:596:17)\n    at require (internal/module.js:11:18)\n    at Object.<anonymous> (server.js:11:13)\n    at Module._compile (module.js:652:30)' },
  level: '\u001b[31merror\u001b[39m',
  [Symbol(level)]: 'error',
  [Symbol(message)]: '{"message":{},"level":"error"}' }
** Winston Output: **
error: [object Object]

Di mana error: [object Object] persis seperti yang saya harapkan

Namun, jika saya mengujinya dengan blok kode ini:

Tes B

const logger = require('winston');
try {
  throw(new Error('This causes error: undefined'));
} catch (err) {
  logger.error(err);
}

Di mana new Error() memang mengandung nilai pesan, saya mendapatkan output ini:

Keluaran B

** Info Object: **
{ level: '\u001b[31merror\u001b[39m',
  [Symbol(level)]: 'error',
  [Symbol(message)]: '{"level":"error"}' }
** Winston Output: **
error: undefined

Seperti yang Anda lihat, saya mendapatkan error: undefined yang sama dengan yang didapat error: [object Object]

Perhatikan, jika saya mencoba blok kode ini:

Tes C

const logger = require('winston');
try {
  throw(new Error('This should work'));
} catch (err) {
  logger.log({level: 'error', message: err});
}

Di mana saya menggunakan logger.log daripada logger.error Saya mendapatkan output yang sama seperti Output A di atas

Saya memiliki masalah yang sama. Saya baru di winston. Saya mencoba solusi @indexzero tetapi tidak berhasil. Apakah Anda punya solusi?

@ nvtuan305 , apakah Anda benar-benar mencoba solusi @indexzero atau apakah Anda mengeditnya sedikit? Jika demikian, bisakah Anda memberikan kode contoh? Kodenya harus berfungsi jika Anda menggunakan logger.log({level: ____, message: err}); Ini tidak akan berhasil jika Anda menghasilkan logger.info , logger.error , atau rasa logger.<level> . Saya hampir yakin itu adalah bug seperti yang saya sebutkan di atas dan itu harus diperbaiki di rilis selanjutnya.

Apakah saya melewatkan sesuatu, atau apakah itu benar-benar sakit kepala (atau bahkan tidak mungkin?) Untuk mendapatkan output yang sama dengan mudah didapat dari console.log / error / warn?

try {
   // ...
  throw new Error('foo');
} catch (e) {
  console.error('Caught error:', e);  // convenient, informative
  logger.error('Caught error:', e);  // nope, the second parameter is something else (couldn't find docs)
  logger.error(`Caught error: ${e}`);  // stack lost
  logger.error(`Caught error: ${JSON.stringify(e)}`);  // Caught error: {}
}

Apa kode winston yang setara untuk mendapatkan hasil yang sama
console.error('Caught error:', error); ?

Dan di mana dokumentasi untuk parameter yang diambil oleh metode kemudahan pada objek logger?

@bayu_joo

logger.error('Caught error:', e);

Ini tidak berhasil karena, tidak seperti console.log() , winston logger.<level>(message) hanya mengambil satu parameter yang disebut pesan. Parameter pesan itu bisa berupa objek atau string (seseorang mengoreksi saya jika saya salah tapi itu pemahaman saya).

Perhatikan bahwa Anda juga dapat menggunakan logger.log({level: <level>, message: <message>}) . Untuk mempelajari lebih lanjut tentang kedua fungsi ini, saya akan merekomendasikan membaca bagian dokumen ini: Winston Docs on Log Levels . Pastikan untuk membaca Menggunakan Tingkat Pencatatan

logger.error(`Caught error: ${e}`);

Saya tidak bisa secara pasti mengatakan mengapa ini tidak mengeluarkan tumpukan, tetapi saya tahu ini bukan masalah dengan winston. Jika Anda mencoba console.log(`Caught error: ${e}`) itu juga tidak termasuk tumpukan. Saya belum banyak bekerja dengan template literal jadi baik template literal tidak bekerja dengan baik dengan objek, atau console.log javascript mengenali objek sebagai objek kesalahan dan dengan demikian hanya menampilkan properti message. Itu tebakan terbaik saya.

logger.error(`Caught error: ${JSON.stringify(e)}`)

Yang satu ini membahas inti topik utas bug ini. Pertama, Anda harus memahami beberapa detail teknis tentang javascript. Perhatikan bahwa jika Anda mencoba console.log(`Caught error: ${JSON.stringify(e)}`) Anda juga mendapatkan hasil yang sama Caught error: {} . Seperti yang dijelaskan @indexzero :

message dan stack properti pada Error tidak dapat dihitung yang menyebabkan JSON.stringify menghasilkan sesuatu yang tidak diharapkan.

Pada dasarnya, karena properti message dan stack tidak dapat dihitung, JSON.stringify melompati properti tersebut yang akan membuat Anda mendapatkan objek kosong {} . Untuk memahami enumerabilitas lebih baik, saya sarankan membaca Enumerabilitas dan kepemilikan properti .

Untungnya, karena cara winston 3.0 dirancang (alat peraga untuk tim winston), kami memiliki solusi untuk hal ini yang diberikan @indexzero . Saya akan membantu menjelaskannya. Pertama Anda membuat fungsi ini:

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

Dari Streams dokumen info.level , dan info.message . Properti info.message IS objek kesalahan jika hanya itu yang Anda berikan. Jadi kami membuat objek baru di mana message.stack dan message.message (Anggap saja sebagai Error.stack dan Error.message ) sekarang dapat dihitung, dan kami menyertakan properti lain apa pun yang mungkin juga dilampirkan ke objek kesalahan itu.

Selanjutnya Anda akan membuat logger ini yang menggunakan fungsi enumerateErrorFormat() atas:

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

Ini akan mengambil message Anda berikan dan memeriksa apakah itu objek kesalahan. Jika sudah maka akan memperbaiki masalah pencacahan. Kemudian mengirimkan pesan ke format.json yang akan merangkai objek apa pun (kesalahan atau tidak). Jika itu bukan objek maka itu adalah string dan format.json effectivley tidak melakukan apa-apa, dan Anda bebas di rumah!

Namun, alangkah baiknya jika kita tidak harus membuat enumerateErrorFormat karena objek kesalahan biasanya dicatat. Seperti yang saya pahami, tim winston sedang mengerjakan perbaikan yang akan dirilis di versi yang lebih baru.

Beberapa catatan akhir. Ini hanya berfungsi jika Anda menggunakan logger.log({level: <level>, message: <message>}) mana pesan adalah objek kesalahan. Contoh:

try {
  throw(new Error('This should work'));
} catch (err) {
  logger.log({level: 'error', message: err});
}

Ada bug lain di winston dimana kode ini tidak berfungsi, seperti yang saya jelaskan di posting saya yang lain di atas:

try {
  throw(new Error('This will not work'));
} catch (err) {
  logger.error(err);
}

Untuk beberapa alasan, properti info.message tidak ditentukan saat kita menggunakan logger.error(err) . Semoga @indexzero bisa mengetahuinya.

@ SamuelMaddox17 @indexzero Terima kasih! Saya mencoba menggunakan logger.log({level: 'error', message: err}); dan berhasil

Bisakah ini diperbaiki untuk logger.error, dll?

Ini rumit dan panjang untuk menggunakan logger.log , terutama karena dengan logger.error Anda dapat dengan mudah menambahkan beberapa argumen.

Hei semua, aku sedang menyelidiki ini. @indexzero: masih berpikir ide terbaik adalah untuk dasarnya menambahkan enumerateErrorFormat fungsi ke json formatter secara default? Apakah kita perlu khawatir secara terpisah tentang jika meta adalah Error bukan hanya object (Saya menduga orang akan mengeluh jika kita tidak menangani kasus itu juga?) ? Juga, saya menggunakan master , tetapi sepertinya logger.error bekerja untuk saya dengan solusi oleh @indexzero / @ SamuelMaddox17 di atas:

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

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new winston.transports.Console(),
  ],
});

logger.error(new Error('whatever'));

Setelah diselidiki lebih lanjut tampaknya masalah logger.error saya jelaskan di atas hanya masalah saat menggunakan logger default. @DABH , saya mencoba kode Anda dan itu berfungsi untuk saya, tetapi ketika saya mengalihkannya ke logger default itu tidak berfungsi:

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

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

winston.configure({
  transports: [
    new winston.transports.Console({
      level: 'debug',
      format: format.combine(
        enumerateErrorFormat(),
        format.json()
      ),
    })
  ]
});

winston.error(new Error('whatever'));

Kedua, saya setuju bahwa enumerateErrorFormat harus ditambahkan ke format json; dan Anda mungkin benar tentang meta juga.

Terakhir, saya ingin mencatat contoh kode yang diberikan oleh @DABH menyebabkan tumpukan tidak "mencetak cantik" jika Anda mau; setidaknya di komputer saya yang menjalankan macOS High Sierra. Ini yang terlihat bagi saya:

{"message":"whatever","stack":"Error: whatever\n    at Object.<anonymous> (/Users/samuelmaddox/Desktop/winston-test/index.js:33:14)\n    at Module._compile (internal/modules/cjs/loader.js:689:30)\n    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)\n    at Module.load (internal/modules/cjs/loader.js:599:32)\n    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)\n    at Function.Module._load (internal/modules/cjs/loader.js:530:3)\n    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)\n    at startup (internal/bootstrap/node.js:266:19)\n    at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)","level":"error"}

Seperti yang Anda lihat, saat mengeluarkan kesalahan dengan fungsi a to JSON, karakter baris baru \n tidak membuat baris baru yang sebenarnya. Ini adalah perilaku yang diharapkan saat mengambil objek dan mengonversinya menjadi JSON, tetapi mungkin bukan perilaku yang sebenarnya kita inginkan dari logger, setidaknya saat masuk ke konsol.

Terima kasih telah melihat lebih dalam @DABH ini

FYI ini adalah tempat saya mendapatkan setelah bermain dengan ini sedikit:

import winston from 'winston';
const format = winston.format;

const printNice = format.printf(info => {
    const {level, message} = info;
    return `Logging Level: ${level} - Logging Message: ${message}`;
});

const enumerateErrorFormat = format(info => {
    if (info.message instanceof Error) {
        info.message = Object.assign({
            message: `${info.message.message}\n============\n${info.message.stack}`
        }, info.message);
    }

    if (info instanceof Error) {
        return Object.assign({
            message: `${info.message}\n============\n${info.stack}`
        }, info);
    }

    return info;
});

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

export default logger;

Masalahnya disebabkan oleh bug ini: https://github.com/winstonjs/winston-transport/issues/31

Kami pasti menggunakan formulir ini di winston2.x tanpa masalah. winston.err('some message', err); bersama dengan winston.error(err) di atas enumerateErrorFormat memperbaiki winston.error(err) tetapi bukan kasus penggunaan dengan err sebagai parameter kedua.

@Samuel_gaduh

logger.log ({level: ____, pesan: err});

itu berhasil terima kasih

Oke, saya menemukan sesuatu. Komentar saya dari 3 September salah. Ini bukan masalah dengan logger default. Ini adalah masalah ketika Anda mendefinisikan level dan / atau format . @DABH ini kode lama Anda:

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

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new winston.transports.Console(),
  ],
});

logger.error(new Error('whatever'));

Jika Anda menghapus ini:

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    enumerateErrorFormat(),
    format.json()
  ),
  transports: [
    new winston.transports.Console(),
  ],
});

Dan ganti dengan ini:

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      level: 'debug',
      format: format.combine(
        enumerateErrorFormat(),
        format.json()
      ),
    }),
  ],
});

Kemudian masalah info.message === undefined muncul. Saya yakin tidak masalah untuk menentukan level dan format untuk setiap transportasi; dan saya hampir yakin ini diizinkan di Winston 2.0.

Berikut adalah contoh kode Anda dengan perubahan kode saya sehingga Anda dapat dengan mudah menjalankan dan menguji:

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

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      level: 'debug',
      format: format.combine(
        enumerateErrorFormat(),
        format.json()
      ),
    }),
  ],
});

logger.error(new Error('whatever'));

Semoga ini membantu sampai ke akar masalahnya.

Saya membuat https://github.com/winstonjs/winston/pull/1527

Ini mencakup semua opsi. Namun beberapa tes gagal jadi saya telah menutupnya untuk saat ini. Kegagalan diharapkan diberikan perbaikan, tetapi saya tidak yakin saya dalam posisi untuk membuat panggilan untuk mengubah / menghapus tes.

Build yang gagal ada di sini https://travis-ci.org/winstonjs/winston/jobs/453012141 dan jelas mengapa pengujian sekarang gagal ketika Anda membaca kode pengujian:
https://github.com/winstonjs/winston/blob/c42ab7fdc51b88db180a7dd90c52ce04ddd4e054/test/logger.test.js#L668

Pikiran?

Saya pikir masalahnya ada di baris ini
const info = (pesan && !(msg instanceof Error) && pesan pesan && pesan) || {
pesan: pesan
};
menambahkan tanda centang dari Kesalahan tampaknya menyelesaikan masalah seperti yang ditunjukkan @crowleym

Untuk siapa pun yang masih berurusan dengan ini, ini adalah pemformat solusi yang berhasil saya hasilkan (cuplikan modul logger.js saya):

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

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

    return combine(timestamp(), printf(format));
}

Untuk beberapa alasan logger.error(new Error("hello")) hanya berfungsi jika Anda mendefinisikan pemformat secara global di winston.createLogger 🤔 dan kemudian Anda mendapatkan objek Kesalahan di info di pemformat.

Jika Anda menentukan pemformat per transport maka Anda harus menggunakan logger.log({level: "error", message: new Error("FAILED")}) dan menangani objek Error melalui info.message alih-alih info untuk mengakses objek Error.

Saya kira ada bug saat mengatur bidang format di opsi transportasi?

Itu hanya 2 sen saya dan apa yang berhasil untuk saya, saya baru mengenal Winston dan tidak berpengalaman dalam JavaScript jadi jangan mengutip saya pada apa pun.

Pendekatan saya adalah upaya untuk memperbaiki akar penyebabnya. Tapi itu tidak mendapatkan banyak daya tarik dari pemilik repo ...

Ya, saya mengerti itu. Saya benar-benar menghabiskan banyak waktu untuk memikirkan hal ini karena saya baru mengenal Winston dan berpikir mungkin saya menggunakannya secara tidak benar atau belum memahami konsep di baliknya dengan cukup baik.

Tapi untungnya saya menemukan beberapa utas (termasuk yang ini) yang menunjukkan sebaliknya. Mudah-mudahan mereka akan memperbaikinya jadi saya tidak harus terus menggunakan solusi tersebut.

Ini mungkin disebabkan oleh wintson-transport , lihat https://github.com/winstonjs/winston-transport/issues/31 untuk masalah tersebut dan https://github.com/winstonjs/winston-transport/pull/ 34 untuk PR.

Pencatatan langsung objek kesalahan selalu berantakan karena propertinya yang tidak dapat dihitung. Secara pribadi saya menganggap ini praktik yang buruk, tetapi cukup banyak orang di komunitas yang bersikukuh tentang hal itu sebagai persyaratan yang harus kami dukung.

Mempertimbangkan untuk mengadopsi https://github.com/winstonjs/logform/pull/59 sebagai format untuk mendukung perilaku seperti ini. Di sisi positifnya, ini merangkum semua kasus edge yang sangat umum saat memperlakukan kesalahan sebagai pesan log. Di sisi bawah itu akan menjadi format lain yang perlu diikutsertakan oleh orang-orang (mirip dengan .splat() )

@indexzero Saya cenderung setuju tetapi pencatatan kesalahan langsung dapat berguna ketika digabungkan dengan format pencatatan khusus / printf jika ada kebutuhan untuk menampilkan beberapa jenis Error berbeda, dan saya tidak ingat Winston 2.x mencoba untuk melawan praktik ini karena diizinkan di luar kotak.

Jadi solusi yang diusulkan untuk enumerateErrorFormat berfungsi tetapi tidak mendukung format logger.error('some message', err) . Karena baik info.message atau info adalah instanceof Error . Saya juga ingin menunjukkan masalah lain dengan solusi ini. Saat ini saya sedang mencatat kesalahan yang dikembalikan dari superagent

    try {
      const response = await request
        .get('https://some/endpoint')
        .set('Authorization', bearerToken);
      logger.info('successfully received response');
      return response.body;
    } catch (e) {
      logger.error('An error was caught while getting programs');
      logger.error(e); // <<< THE ERROR LOG  
    }

Jika kita hanya menggunakan Object.assign maka dinginkan tumpukan dan pesan akan disetel! TAPI, info lain yang merupakan bagian dari kesalahan juga akan dicatat. Ini bisa sangat berbahaya jika kesalahan memiliki data sensitif seperti Authorization Headers (yang dalam hal ini dimasukkan sebagai bagian dari objek kesalahan).

Tapi kemudian Anda mungkin berkata. Ini bukan kesalahan winston, ini bukan kesalahan winston yang superagent menambahkan data ini ke kesalahan. SAYA SETUJU! NAMUN, karena semuanya disimpan rata pada objek info , menjadi sangat sulit untuk menyimpan info lama dan tidak menimpa yang lain.

Akan lebih baik jika, saat menggunakan logger.error. Diasumsikan parameter kedua adalah dan error dan meletakkannya di objek info sebagai info.error dan kemudian jika logging ke arah lain, antarmuka akan menjadi { level: "error", error: YOUR ERROR OBJECT}

Saya benar-benar hanya mengomel di sini tetapi antarmuka baru pasti sedikit membuat frustrasi (semuanya ada di info).

Hanya untuk menguraikan poin yang saya buat, misalkan Anda logger.error( e ) mana e adalah tipe kesalahan.

Kemudian dalam kode Anda, Anda telah mengkonfigurasi winston sebagai berikut:

winston.configure({
    format: combine(
      timestamp(),
      enumerateErrorFormat(),
      ...
    ),
  });

stempel waktu semakin didorong ke objek kesalahan 😱. Apakah itu masuk akal? Pikirkan tentang itu .. objek kesalahan yang Anda kirim mendapatkan prop baru secara dinamis .. stempel waktu.

Saya pikir solusi terbaik secara keseluruhan untuk masalah ini adalah mendukung sintaks berikut

logger.error('An error occurred when doing something important', { error: e } );

dan kemudian secara internal Anda dapat membuat pemformat kesalahan yang mencari bidang kesalahan!

Pembaruan pada orang-orang ini:

Berharap ini dijahit dan dikirim dalam beberapa hari ke depan. Ini adalah terbitan terakhir berikutnya dalam pelacak [email protected]

Halo semuanya - silakan periksa https://github.com/winstonjs/winston/pull/1562. Ini adalah item terakhir pada daftar periksa rilis 3.2.0 sehingga setelah PR selesai kami akan dapat merilisnya.

Sampai perbaikan diterbitkan, saya menggunakan solusi berikut ini:

logger.error = item => {
  logger.log({ level: 'error', message: item instanceof Error ? item.stack : item });
};

Saya menggunakan winston (3.2.1) terbaru dan masih mendapatkan undefined ketika menyampaikan kesalahan ke logger.error

@ezze memiliki solusi yang bagus tetapi pelacakan tumpukan dipaksa ke baris baru. di sini adalah versi yang sedikit dimodifikasi yang meletakkannya dalam satu baris (jadi ini tertangkap oleh grep file log sederhana)

logger.error = item => {
  const message = item instanceof Error
    ? item.stack.replace('\n', '').replace('    ', ' - trace: ')
    : item;
  logger.log({ level: 'error', message });
};

dengan keluaran <Error message> - trace: <stack trace>

jika ada cara yang lebih mudah untuk melakukan ini dengan winston terbaru, beri tahu saya @indexzero. saya baru mengenal perpustakaan dan mengikuti dokumen

Saya baru saja melihat link yang Anda posting ke PR. apakah ini berarti bahwa untuk melewatkan kesalahan ke logger.error membutuhkan string pesan, lalu kesalahan?

try {
  someThing();
} catch(error) {
  logger.error(error); // what I would like to do
  logger.error('special message', error); // what I believe is required?
}

@ the-vampiire Akhirnya ada 2 masalah yang dibicarakan utas ini. Yang pertama adalah apa yang dibawa oleh poster asli, dan yang kedua adalah masalah yang saya kemukakan yang sama dengan masalah Anda. Saya pikir mereka hanya memperbaiki masalah poster asli. Saya bermaksud untuk memeriksa lebih lanjut untuk memastikan dan kemudian membuka masalah baru jika itu masalahnya. Sayangnya saya belum punya waktu untuk menyelam lebih dalam. Sementara itu, jika Anda menggunakan logger.log({level: 'error', message: err}); mana err adalah Objek Kesalahan maka itu akan berhasil.

Masih mengalami masalah ini, kehilangan banyak waktu untuk mencari tahu, solusi dari @ the-vampiire berfungsi dengan baik.

Mengapa tiket ini ditutup?

Mengganti logger.error sejauh ini merupakan solusi terbaik karena tidak menambahkan properti timestamp ke objek Error yang diteruskan sebagai argumen tunggal ke error (). Kebanyakan orang mungkin berharap bahwa objek Error tidak dapat diubah. Jika Anda juga tidak menimpa logger.info dan setiap metode terkait level lainnya, akan mengejutkan ketika hal-hal tidak berfungsi seperti yang diharapkan. Sekali lagi, kecuali Anda ingin objek Anda dimodifikasi, apa pun tipenya, jangan kirimkan langsung ke metode logger Winston.

Fitur ini didukung sejak [email protected]

Contoh penggunaan:

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

const print = format.printf((info) => {
  const log = `${info.level}: ${info.message}`;

  return info.stack
    ? `${log}\n${info.stack}`
    : log;
});

const logger = winston.createLogger({
  level: 'debug',
  format: format.combine(
    format.errors({ stack: true }),
    print,
  ),
  transports: [new transports.Console()],
});

const error = new Error('Ooops');

logger.error(error);
logger.error('An error occurred:', error);

cc @ HRK44 @ the-vampiire

Saya juga masih mengalami masalah.
Ketika saya menyebut kesalahan seperti logger.error(error); saya hanya mendapatkan undefined .
Hanya jika saya menyebutnya seperti logger.error('Something went wrong', error) saya mendapatkan kesalahan lengkap dan dapat menguraikannya.

Saya juga masih mengalami masalah.
Ketika saya menyebut kesalahan seperti logger.error(error); saya hanya mendapatkan undefined .
Hanya jika saya menyebutnya seperti logger.error('Something went wrong', error) saya mendapatkan kesalahan lengkap dan dapat menguraikannya.
Apakah Anda menambahkan ini?

format.errors({ stack: true })

Ya, masih masalah yang sama. Saya mencoba mereproduksinya dalam sebuah intisari.

@ OBrown92 Saya menghadapi masalah yang sama hari ini. Saya dapat mengkonfirmasi, bahwa itu berhasil, jika format.errors({ stack: true }) , diterapkan ke logger, bukan untuk transportasi. Dalam hal ini, dimungkinkan untuk menggunakan logger.error(error); dan logger.error('Something went wrong', error) . Namun, ada masalah, ketika saya mencoba menerapkan format.errors({ stack: true }) ke transportasi yang dipilih. Dalam hal ini saya mendapatkan undefined untuk logger.error(error); , tetapi logger.error('Something went wrong', error) berfungsi dengan baik.

Saya tidak yakin apakah itu perilaku yang diharapkan atau itu bug, tetapi saya menghabiskan banyak waktu untuk menemukan penyebabnya, jadi tolong perbaiki atau sebutkan tentang itu di suatu tempat di dokumentasi Anda. Ini akan sangat membantu.

Bagaimanapun, saya sangat berterima kasih atas pekerjaan Anda dalam proyek hebat ini.

Saya menghadapi masalah yang sama jadi saya menulis paket ini, utils-deep-clone . Coba lihat.

format.errors is not a function ... yah itu kejutan.

@bayu_joo
Apakah Anda mengimpor format dari paket winston?
Contoh penggunaan:
const { format } = require('winston')
Atau
const winston = require('winston'); const { format } = winston;

@aybhalala yepp, meskipun tidak masalah tumpukan kesalahan diteruskan ke printf tanpa itu.

Pembaruan: karena masih ada masalah dengan ini, saya telah melakukan hal berikut untuk sementara waktu dan berfungsi dengan baik

// Grab the default winston logger
const winston = require('winston');

const { format } = winston;
const { combine, timestamp } = format;

// Custom format function that will look for an error object and log out the stack and if 
// its not production, the error itself
const myFormat = format.printf((info) => {
  const { timestamp: tmsmp, level, message, error, ...rest } = info;
  let log = `${tmsmp} - ${level}:\t${message}`;
  // Only if there is an error
  if ( error ) {
    if ( error.stack) log = `${log}\n${error.stack}`;
    if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
  }
  // Check if rest is object
  if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
    log = `${log}\n${JSON.stringify(rest, null, 2)}`;
  }
  return log;
});

 winston.configure({
    transports: [
      new winston.transports.Console({
        level: 'debug',
        timestamp: true,
        handleExceptions: true
    }),
  ];
    format: combine(
      trace(),
      timestamp(),
      myFormat
    ),
  });


// Finally you log like this
logger.error('An error occurred!!!', { error } );

^^ Itulah penggunaan yang diharapkan. Karena manusia biasa tidak akan pernah mengetahui hal ini, ini harus didokumentasikan.

Karena manusia biasa tidak akan pernah mengetahui hal ini, itu harus didokumentasikan

😂 +1 untuk sobat itu

Saya menggunakan winston dengan transportasi pihak ke-3 ( @google-cloud/logging-winston ) jadi saya memiliki sedikit kendali atas sintaks. Selain itu, menurut saya ini lebih intuitif:

const error = new Error('something bad happened');
logger.error('was doing this and', error);

Saat masuk ke konsol saya menggabungkan tumpukan ke pesan. Tapi hasilnya kira-kira seperti ini:

ERROR was doing this andsomething bad happened Error: something bad happened <rest of the stack.>

Karena winston menggabungkan meta.message ke pesan asli, ada andsomething aneh dan pesan duplikat yang juga dicetak di tumpukan. Ini dijelaskan dalam # 1660.

Sepertinya # 1664 mencoba memperbaiki ini. Sementara itu, saya menulis pemformat yang "membatalkan" rangkaian itu: https://github.com/winstonjs/winston/issues/1660#issuecomment -512226578

@bayu_joo

logger.error('Caught error:', e);

Ini tidak berhasil karena, tidak seperti console.log() , winston logger.<level>(message) hanya mengambil satu parameter yang disebut pesan. Parameter pesan itu bisa berupa objek atau string (seseorang mengoreksi saya jika saya salah tapi itu pemahaman saya).

Perhatikan bahwa Anda juga dapat menggunakan logger.log({level: <level>, message: <message>}) . Untuk mempelajari lebih lanjut tentang kedua fungsi ini, saya akan merekomendasikan membaca bagian dokumen ini: Winston Docs on Log Levels . Pastikan untuk membaca Menggunakan Tingkat Pencatatan

logger.error(`Caught error: ${e}`);

Saya tidak bisa secara pasti mengatakan mengapa ini tidak mengeluarkan tumpukan, tetapi saya tahu ini bukan masalah dengan winston. Jika Anda mencoba console.log(`Caught error: ${e}`) itu juga tidak termasuk tumpukan. Saya belum banyak bekerja dengan template literal jadi baik template literal tidak bekerja dengan baik dengan objek, atau console.log javascript mengenali objek sebagai objek kesalahan dan dengan demikian hanya menampilkan properti message. Itu tebakan terbaik saya.

logger.error(`Caught error: ${JSON.stringify(e)}`)

Yang satu ini membahas inti topik utas bug ini. Pertama, Anda harus memahami beberapa detail teknis tentang javascript. Perhatikan bahwa jika Anda mencoba console.log(`Caught error: ${JSON.stringify(e)}`) Anda juga mendapatkan hasil yang sama Caught error: {} . Seperti yang dijelaskan @indexzero :

message dan stack properti pada Error tidak dapat dihitung yang menyebabkan JSON.stringify menghasilkan sesuatu yang tidak diharapkan.

Pada dasarnya, karena properti message dan stack tidak dapat dihitung, JSON.stringify melompati properti tersebut yang akan membuat Anda mendapatkan objek kosong {} . Untuk memahami enumerabilitas lebih baik, saya sarankan membaca Enumerabilitas dan kepemilikan properti .

Untungnya, karena cara winston 3.0 dirancang (alat peraga untuk tim winston), kami memiliki solusi untuk hal ini yang diberikan @indexzero . Saya akan membantu menjelaskannya. Pertama Anda membuat fungsi ini:

const enumerateErrorFormat = format(info => {
  if (info.message instanceof Error) {
    info.message = Object.assign({
      message: info.message.message,
      stack: info.message.stack
    }, info.message);
  }

  if (info instanceof Error) {
    return Object.assign({
      message: info.message,
      stack: info.stack
    }, info);
  }

  return info;
});

Dari Streams dokumen info.level , dan info.message . Properti info.message IS objek kesalahan jika hanya itu yang Anda berikan. Jadi kami membuat objek baru di mana message.stack dan message.message (Anggap saja sebagai Error.stack dan Error.message ) sekarang dapat dihitung, dan kami menyertakan properti lain apa pun yang mungkin juga dilampirkan ke objek kesalahan itu.

Selanjutnya Anda akan membuat logger ini yang menggunakan fungsi enumerateErrorFormat() atas:

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

Ini akan mengambil message Anda berikan dan memeriksa apakah itu objek kesalahan. Jika sudah maka akan memperbaiki masalah pencacahan. Kemudian mengirimkan pesan ke format.json yang akan merangkai objek apa pun (kesalahan atau tidak). Jika itu bukan objek maka itu string dan format.json effectivley tidak melakukan apa-apa, dan Anda bebas di rumah!

Namun, alangkah baiknya jika kita tidak harus membuat enumerateErrorFormat karena objek kesalahan biasanya dicatat. Seperti yang saya pahami, tim winston sedang mengerjakan perbaikan yang akan dirilis di versi yang lebih baru.

Beberapa catatan akhir. Ini hanya berfungsi jika Anda menggunakan logger.log({level: <level>, message: <message>}) mana pesan adalah objek kesalahan. Contoh:

try {
  throw(new Error('This should work'));
} catch (err) {
  logger.log({level: 'error', message: err});
}

Ada bug lain di winston dimana kode ini tidak berfungsi, seperti yang saya jelaskan di posting saya yang lain di atas:

try {
  throw(new Error('This will not work'));
} catch (err) {
  logger.error(err);
}

Untuk beberapa alasan properti info.message tidak terdefinisi saat kita menggunakan logger.error(err) . Semoga @indexzero bisa mengetahuinya.

Penjelasan yang sangat bagus, saya hanya ingin menambahkannya dengan logger.error( Kesalahan yang terjadi: $ {e} ); Anda kehilangan tumpukan karena cara kerja string literal di javascript, `${e}` persis sama dengan e.toString() , jadi hanya mencetak pesan kesalahan yang merupakan perilaku yang diharapkan.

Ini masih menjadi masalah? Saya masih mengalami masalah dengan ini:

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

const { combine } = format

const errorFormatter = format((info) => {
  console.log(info)
  return info
})


const consoleTransport = new transports.Console({
  format: combine(errorFormatter()),
})

const logger = createLogger({
  transports: [
    consoleTransport,
  ],
})

try {
  throw new Error('Error message')
} catch(err) {
  logger.error(err) // info doesnt have the error object
  logger.error('', err) // info have the error object
}

Ini masih menjadi masalah? Saya masih mengalami masalah dengan ini:

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

const { combine } = format

const errorFormatter = format((info) => {
  console.log(info)
  return info
})


const consoleTransport = new transports.Console({
  format: combine(errorFormatter()),
})

const logger = createLogger({
  transports: [
    consoleTransport,
  ],
})

try {
  throw new Error('Error message')
} catch(err) {
  logger.error(err) // info doesnt have the error object
  logger.error('', err) // info have the error object
}

Masalah yang sama disini...

setelah melihat kode sumber, saya dapat melihat parameter apa yang diterimanya:

interface LeveledLogMethod {
(pesan: string, callback: LogCallback): Logger;
(pesan: string, meta: any, callback: LogCallback): Logger;
(pesan: string, ... meta: any []): Logger;
(infoObject: object): Logger;
}

jadi jika Anda melewatkan objek kesalahan sebagai parameter pertama, itu hanya akan mengambil pesan kesalahan karena hanya memahami string, dan jika Anda melewatkan kesalahan di parameter kedua maka Anda dapat mengakses pelacakan tumpukan di info.stack

btw saya tidak bisa menemukan ini di mana pun di dokumen

Saya menemukan dua solusi, yang pertama adalah menggunakan format.errors , disebutkan pada logform di logger induk , lalu buat messageFormatter menggunakan format.printf dan secara kondisional menambahkan kolom stack diekstrak dari info ( format.errors({ stack: true}) akan menambahkan itu).

Solusi lain, yang saya sukai adalah meretas ke penebang level winston:

const addArgs = format((info) => {
  const args: any[] = info[Symbol.for('splat')]
  info.args = args ? [...args] : []
  return info
})

const messageFormatter = format.printf(info => {
  const { timestamp: timeString = '', message, args = [] } = info
  const formattedMsgWithArgs = util.formatWithOptions({ colors: true }, message, ...args)
  const msg = `${timeString} - ${info.level}: ${formattedMsgWithArgs}`
  return msg
})

const logger = createLogger({
  format: format.combine(
    addArgs(),
    format.timestamp({ format: 'HH:mm:ss.SSS' })
  ),

  transports: [
    new transports.Console({
      format: format.combine(format.colorize(), messageFormatter),
    }),
  ],
})

const levels = ['debug', 'info', 'error']
levels.forEach((level) => {
  logger[level] = (msg: any, ...remains: any) => {
    if(typeof msg != "string") {
      return logger.log(level, '', msg, ...remains)
    }

    logger.log(level, msg, ...remains)
  }  
})

Sepertinya dengan cara ini saya bisa mendapatkan error logging yang mirip dengan console.log

Saya dapat memverifikasi bahwa komentar @tiagonapoli tentang bagaimana format.errors harus ada di _parent_ logger adalah akurat. Ketika saya melakukan sesuatu seperti ini:

winston.loggers.add("default");
const log = winston.loggers.get("default");
/* get a `transportOptions` object and a `transportType` */
transportOptions.format = logform.format.combine(
  logform.format.errors({ stack: true }),
  logform.format.timestamp(),
  logform.format.printf(myFormatter)
);
log.add(new winston.transports[transportType](transportOptions);

Penanganan objek Error dilakukan seolah-olah mereka adalah sebuah string. Namun, jika saya melakukan hal seperti ini:

winston.loggers.add("default");
const log = winston.loggers.get("default");
log.format = logform.format.errors({ stack: true });
/* get a `transportOptions` object and a `transportType` */
transportOptions.format = logform.format.combine(
  logform.format.timestamp(),
  logform.format.printf(myFormatter)
);
log.add(new winston.transports[transportType](transportOptions);

Penanganan objek Error bekerja dengan benar.

Menurut saya, bug di sini adalah seharusnya tidak ada perbedaan dalam perilaku.

Jadi ini masih belum diperbaiki setelah 1 tahun? Apakah saya harus meretas kode logger winston untuk membuatnya berfungsi?

Ya, ini memberi saya cukup sakit kepala sehingga Winston mulai tampak seperti jauh lebih merepotkan daripada nilainya untuk kasus penggunaan saya yang relatif sederhana ... Saya akhirnya hanya menulis kelas logger kecil saya sendiri, dan saya akan merekomendasikan orang lain melakukan hal yang sama kecuali Winston memberikan sesuatu yang BENAR-BENAR Anda butuhkan.

Sungguh? ini membuat frustasi ...

Saya bukan seorang pelaku, tetapi saya mungkin benar untuk mengatakan bahwa ini tidak akan "diperbaiki" karena tidak rusak. Winston layak digunakan. Anda hanya perlu mengkonfigurasinya - saran terbaik untuk saya ada di atas di https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691

Belum ?

Pembaruan: karena masih ada masalah dengan ini, saya telah melakukan hal berikut untuk sementara waktu dan berfungsi dengan baik

// Grab the default winston logger
const winston = require('winston');

const { format } = winston;
const { combine, timestamp } = format;

// Custom format function that will look for an error object and log out the stack and if 
// its not production, the error itself
const myFormat = format.printf((info) => {
  const { timestamp: tmsmp, level, message, error, ...rest } = info;
  let log = `${tmsmp} - ${level}:\t${message}`;
  // Only if there is an error
  if ( error ) {
    if ( error.stack) log = `${log}\n${error.stack}`;
    if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
  }
  // Check if rest is object
  if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
    log = `${log}\n${JSON.stringify(rest, null, 2)}`;
  }
  return log;
});

 winston.configure({
    transports: [
      new winston.transports.Console({
        level: 'debug',
        timestamp: true,
        handleExceptions: true
    }),
  ];
    format: combine(
      trace(),
      timestamp(),
      myFormat
    ),
  });


// Finally you log like this
logger.error('An error occurred!!!', { error } );

darimana jejak itu berasal?

Tidak juga, ini tidak dapat diterima untuk perpustakaan logging.
Maintainer harus meletakkan contoh yang disorot dengan baik pada dokumen di mana ditunjukkan cara mencatat kesalahan, bahkan menentukan format printf kustom dan format non json dan di mana Anda dapat mencatat kesalahan dengan sesuatu seperti logger.error ("sesuatu", err) dan logger .error (err)
Winston tampaknya hebat tetapi masalah ini sangat tidak dapat diterima

Ini adalah pendapat saya tentang cara mencatat kesalahan menggunakan Winston. Ini tidak unik, banyak orang di atas memiliki solusi yang berfungsi berdasarkan konsep yang sama juga.

Latar Belakang
Saya menggunakan @jsdevtools/ono untuk membungkus jenis objek arbitrer menjadi kesalahan khusus, tetapi terlepas dari itu, solusi ini tampaknya masih berfungsi dengan baik pada kesalahan simpul asli (misalnya kesalahan fs eperm), dan kelas kesalahan kustom.

Penjelasan
Pada dasarnya, saya mengandalkan format.errors({stack:true}) dan format.metadata() . Seperti yang disebutkan oleh https://github.com/winstonjs/winston/issues/1338#issuecomment -532327143, ini harus dalam formatter induk .

Metadata membantu untuk menggeser semua properti kustom objek kesalahan ke info.metadata .

Saya ingin mencetak 3 jenis informasi: pesan kesalahan, pelacakan tumpukan, dan properti objek kesalahan. Pesan kesalahan sudah berupa teks biasa. Saya cukup mencetak tumpukan info.metadata.stack menggunakan modul pretty-error . Untuk properti objek kesalahan, saya tidak ingin stacktrace muncul lagi, jadi saya mengkloning objek tersebut, dan menghapus properti stacktrace. Saya kemudian cukup mencetak objek kesalahan menggunakan fast-safe-stringify , yang merupakan modul stringify yang sama yang diandalkan oleh winston.

    const lodash = require("lodash");
    const path = require("path");
    const winston = require("winston");
    const { default: stringify } = require("fast-safe-stringify");
    const logDir = "D:/temp/logs";

    // pretty formatting
    const PrettyError = require("pretty-error");
    const pe = new PrettyError();
    pe.withoutColors()
        .appendStyle({
            'pretty-error > trace':
            {
                display: 'inline'
            },
            'pretty-error > trace > item':
            {
                marginBottom: 0,
                bullet: '"*"'
            }
        })
        // @ts-ignore
        .alias(/.*[\\\/]CelebrityQuery/i, "<project>")
        .alias(/\[CelebrityQuery\][\\\/]?/i, "")
        .skip(/** <strong i="23">@type</strong> {(_:any) => boolean} */ (traceline => {
            if (traceline && traceline.dir) {
                return traceline.dir.toString().startsWith("internal");
            }
            return false;
        }))
        .skipNodeFiles();

    const consoleFormat = winston.format.combine(
        winston.format.colorize(),
        winston.format.timestamp({
            format: 'DD MMM HH:mm:ss'
        }),
        winston.format.printf(info => {
            if (!lodash.isEmpty(info.metadata) && info.metadata.hasOwnProperty("stack")) {
                let dup = lodash.clone(info.metadata);
                delete dup.stack;
                const errBody = stringify(dup, undefined, 4);
                const stack = pe.render({ stack: info.metadata.stack });
                return `${info.timestamp} ${info.level} ${info.message}${errBody}\n${stack}`;
            } else if (lodash.isString(info.message)) {
                return `${info.timestamp} ${info.level} ${info.message}`;
            } else {
                return `${info.timestamp} ${info.level} ${stringify(info.message, undefined, 4)}`;
            }
        })
    );
    const logFormat = winston.format.combine(winston.format.timestamp(), winston.format.json());
    return winston.createLogger({
        level: 'debug',
        format: winston.format.combine(
            winston.format.errors({ stack: true }),
            winston.format.metadata()
        ),
        transports: [
            new winston.transports.Console({
                format: consoleFormat,
                level: 'info',
            }),
            new winston.transports.File({
                filename: path.join(logDir, "stdout.json"),
                format: logFormat,
                level: 'debug',
                maxsize: 1000000,
                tailable: true
            })
        ]
    });

Log Screenshot

PS: Saya juga menemukan solusi yang disebutkan di https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691 sebagai alternatif yang baik. Yaitu menggunakan logger.warn("Oh no", { error: new Error() }) , kemudian mereferensikan info.error di formatter kustom Anda.

@tiagonapoli solusi Anda tentang menggunakan format.errors pada pencatat induk bekerja untuk saya:

const logger = createLogger({
  transports: loggerTransports,
});

logger.format = format.errors({ stack: true });

Cukup menyakitkan untuk mengkonfigurasi logger ini ... Mungkinkah itu tidak hanya berperilaku seperti console.log luar kotak?

@ will093 sama di sini. Pernah membahas masalah itu lagi dan jangan mengerti mengapa console.log saya bagus dan bersih dan format winston adalah omong kosong.

2 ¢ saya

// Enable console logging when not in production
if (process.env.NODE_ENV !== "production") {
    logger.add(new transports.Console({
        format: format.combine(
            format.colorize(),
            format.simple(),
            format.printf(info => {
                const { level, ...rest } = info;
                let rtn = "";
                // rtn += info.timestamp;
                rtn += "[" + info.level + "] ";
                if (rest.stack) {
                    rtn += rest.message.replace(rest.stack.split("\n")[0].substr(7),"");
                    rtn += "\n";
                    rtn += "[" + level + "] ";
                    rtn += rest.stack.replace(/\n/g, `\n[${level}]\t`);
                } else {
                    rtn += rest.message;
                }
                return rtn;
            }),
        ),
    }));
}

Contoh untuk logger.error("Error during schema stitching", e);

image

menggunakan solusi @tiagonapoli dan @ will093 untuk menambahkannya hanya ke induk tampaknya menjadi cara termudah untuk mendukung secara langsung pencatatan kesalahan dan masih mencatat pesan - berikut adalah contoh lengkap dari penyiapan minimal dengan stempel waktu:

const createLogger = () => {
  const logFormatter = winston.format.printf(info => {
    let { timestamp, level, code, stack, message } = info;

    // print out http error code w/ a space if we have one
    code = code ? ` ${code}` : '';
    // print the stack if we have it, message otherwise.
    message = stack || message;

    return `${timestamp} ${level}${code}: ${message}`;
  });

  return winston.createLogger({
    level: 'info',
    // put the errors formatter in the parent for some reason, only needed there:
    format: winston.format.errors({ stack: true }),
    transports: new winston.transports.Console({
      format: winston.format.combine(
        winston.format.timestamp(),
        logFormatter
      ),
  });
};

bekerja dengan tumpukan ketika dipanggil dengan kesalahan seperti: logger.error(error) , bekerja dengan string ketika dipanggil seperti logger.error('a regular message') , terlihat seperti ini di log saya:

2020-09-23T20:05:30.30Z info: Feathers application started on http://localhost:3030
2020-09-23T20:05:35.40Z info: job queue - redis ready, registering queues...
2020-09-23T20:05:40.25Z error 401: NotAuthenticated: invalid authorization header
    at new NotAuthenticated (/path/to/server/node_modules/@feathersjs/errors/lib/index.js:94:17)
    at Object.<anonymous> (/path/to/server/src/hooks/authentication.js:123:456)
    at /path/to/server/node_modules/@feathersjs/commons/lib/hooks.js:116:46

ini tidak mencoba menyelesaikan winston logger.error('message here', error) -incompatibility w / console.log , yang tampaknya dilakukan oleh solusi @tiagonapoli yang lebih terlibat.

Juga, jika Anda menyukai log json, Anda dapat menjatuhkan logFormatter sini dan menggunakan winston.format.json() sebagai gantinya, yang masih akan menyertakan tumpukan - tetapi tidak cantik.

Pembaruan: karena masih ada masalah dengan ini, saya telah melakukan hal berikut untuk sementara waktu dan berfungsi dengan baik

// Grab the default winston logger
const winston = require('winston');

const { format } = winston;
const { combine, timestamp } = format;

// Custom format function that will look for an error object and log out the stack and if 
// its not production, the error itself
const myFormat = format.printf((info) => {
  const { timestamp: tmsmp, level, message, error, ...rest } = info;
  let log = `${tmsmp} - ${level}:\t${message}`;
  // Only if there is an error
  if ( error ) {
    if ( error.stack) log = `${log}\n${error.stack}`;
    if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
  }
  // Check if rest is object
  if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
    log = `${log}\n${JSON.stringify(rest, null, 2)}`;
  }
  return log;
});

 winston.configure({
    transports: [
      new winston.transports.Console({
        level: 'debug',
        timestamp: true,
        handleExceptions: true
    }),
  ];
    format: combine(
      trace(),
      timestamp(),
      myFormat
    ),
  });


// Finally you log like this
logger.error('An error occurred!!!', { error } );

di mana definisi trace ()?

Pembaruan: karena masih ada masalah dengan ini, saya telah melakukan hal berikut untuk sementara waktu dan berfungsi dengan baik

// Grab the default winston logger
const winston = require('winston');

const { format } = winston;
const { combine, timestamp } = format;

// Custom format function that will look for an error object and log out the stack and if 
// its not production, the error itself
const myFormat = format.printf((info) => {
  const { timestamp: tmsmp, level, message, error, ...rest } = info;
  let log = `${tmsmp} - ${level}:\t${message}`;
  // Only if there is an error
  if ( error ) {
    if ( error.stack) log = `${log}\n${error.stack}`;
    if (process.env.NODE_ENV !== 'production') log = `${log}\n${JSON.stringify(error, null, 2)}`;
  }
  // Check if rest is object
  if ( !( Object.keys(rest).length === 0 && rest.constructor === Object ) ) {
    log = `${log}\n${JSON.stringify(rest, null, 2)}`;
  }
  return log;
});

 winston.configure({
    transports: [
      new winston.transports.Console({
        level: 'debug',
        timestamp: true,
        handleExceptions: true
    }),
  ];
    format: combine(
      trace(),
      timestamp(),
      myFormat
    ),
  });


// Finally you log like this
logger.error('An error occurred!!!', { error } );

darimana jejak itu berasal?

ada jawaban tentang ini?

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

kjin picture kjin  ·  3Komentar

bertolo1988 picture bertolo1988  ·  3Komentar

pocesar picture pocesar  ·  3Komentar

anks333 picture anks333  ·  3Komentar

JaehyunLee-B2LiNK picture JaehyunLee-B2LiNK  ·  3Komentar