Winston: [3.0.0] Объект ошибки не анализируется и не печатается

Созданный на 29 мая 2018  ·  68Комментарии  ·  Источник: winstonjs/winston

Расскажите, пожалуйста, о вашей среде:

  • _ winston версия? _
  • _ node -v выходы: _ v8.11.1
  • _Операционная система? _ (Windows, macOS или Linux) macOS
  • _Language? _ (Все | TypeScript XX | ES6 / 7 | ES5 | Dart) Все

В чем проблема?

Регистрация объекта узла Error приводит к пустому сообщению:

Пример:

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});

Результат:

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

Также:

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

Результаты в:

{"level":"error"}

Что вы ожидаете вместо этого?

Я ожидаю, что в ключе сообщения будет хотя бы сообщение об ошибке. Если я попробую использовать специальный форматировщик, в info также нет объекта ошибки, поэтому его нужно где-то удалить?

Дополнительная информация

Дайте мне знать, чем я могу помочь - я рад щелкнуть PR, но я еще не знаю, как обойтись [email protected] достаточно, чтобы его найти

bug important

Самый полезный комментарий

Нет, правда, это недопустимо для библиотеки журналов.
Сопровождающий должен просто поместить хорошо выделенный пример в документы, где показано, как регистрировать ошибку, даже определяя собственный формат printf и формат, отличный от json, и где вы можете регистрировать ошибку с помощью чего-то вроде logger.error ("что-то", err) и регистратора .error (ошибка)
Уинстон казался отличным, но эта проблема невероятно неприемлема.

Все 68 Комментарий

У нас есть тестовое покрытие для этого, но очевидно, что нам нужно больше. Что творится под одеялом:

  1. Ваш экземпляр Error передается по цепочке потоков objectMode
  2. Формат по умолчанию для Logger - json (см .: код формата json в logform )
  3. Свойства message и stack в Error не перечисляются, что приводит к тому, что JSON.stringify выводит то, чего никто не ожидает.
console.log(JSON.stringify(new Error('lol nothing here')));
// '{}'

С точки зрения дизайна winston@3 представил formats именно для такого рода задач, чтобы повысить производительность. Говоря о производительности, что интересно, pino делает здесь кое-что интересное . Возможно, решение реализует что-то похожее на asJson в формате по умолчанию json .

Если кто-то ищет быстрое решение, вы можете пока включить enumerateErrorFormat в формат вашего регистратора. Мы надеемся исправить это до 3.0.0 следующей неделе (или вскоре после этого в 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 , я попытался путем , но он не работает. Ты знаешь почему?

Форматировщик:
`` ` 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 ({
сообщение: info.message.message,
стек: info.message.stack,
}, info.message);
}
if (info instanceof Error) {
return Object.assign ({
сообщение: info.message,
стек: info.stack,
}, Информация);
}
вернуть информацию;
});

const consoleLogger = winston.createLogger ({
уровень,
формат: winston.format.timestamp (),
транспорты: [
новый winston.transports.Console ({
формат: winston.format.combine (
winston.format.colorize (),
enumerateErrorFormat (),
printFormat,
),
}),
],
});
Code: javascript
пытаться {
// Некоторая ошибка выдачи кода
} catch (err) {
logger.error (ошибка);
}
Output:
2018-06-28T21: 17: 25.140Z - ошибка: undefined
Info object: javascript
{level: '\ u001b [31merror \ u001b [39m', отметка времени: '2018-06-28T21: 17: 25.140Z', [Symbol (level)]: 'error'}
`` ''
Где находится атрибут сообщения в журнале ошибок?

@sandrocsimas Я заметил, что вам нужно передать функцию enumerateErrorFormat

Форматировщик

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,
      ),
    }),
  ],
});

Я до сих пор не понимаю, почему

Я думаю, что столкнулся с той же ошибкой, что и @sandrocsimas.

Вот моя конфигурация регистратора:

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
      ),
    })
  ]
});

Если я протестирую это с помощью этого блока кода:

Тест А

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

где new Error() не содержит значения сообщения, я получаю такой вывод:

Выход 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]

Где error: [object Object] - именно то, что я ожидал

Однако, если я протестирую это с помощью этого блока кода:

Тест B

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

Если new Error() действительно содержит значение сообщения, я получаю следующий вывод:

Выход B

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

Как видите, я получаю те же error: undefined что и @sandrocsimas . Я ожидал получить error: [object Object]

Обратите внимание, если я попробую этот блок кода:

Тест C

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

Если я использую logger.log вместо logger.error я получаю тот же результат, что и результат A выше.

У меня та же проблема. Я новичок в Уинстоне. Я пробовал решение @indexzero, но не работал. У тебя есть какое-нибудь решение?

@ nvtuan305 , вы пробовали именно решение logger.log({level: ____, message: err}); Он не будет работать, если вы используете logger.info , logger.error или любой другой вариант logger.<level> . Я почти уверен, что это ошибка, указанная выше, и ее следует исправить в более позднем выпуске.

Я что-то упускаю, или это полная головная боль (или даже невозможность?), Чтобы получить тот же результат, который легко получить из 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: {}
}

Каков эквивалентный код Winston, чтобы получить тот же результат, что и
console.error('Caught error:', error); ?

А где документация по параметрам, принимаемым вспомогательными методами объекта логгера?

@dandv

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

Это не работает, потому что, в отличие от console.log() , logger.<level>(message) Winston принимает только один параметр с именем message. Этот параметр сообщения является либо объектом, либо строкой (кто-нибудь поправит меня, если я ошибаюсь, но это мое понимание).

Обратите внимание, что вы также можете использовать logger.log({level: <level>, message: <message>}) . Чтобы узнать больше об этих двух функциях, я бы порекомендовал прочитать эту часть документации: Winston Docs on Log Levels . Обязательно ознакомьтесь с разделом Использование уровней ведения журнала.

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

Я не могу однозначно сказать, почему это не выводит стек, но я знаю, что это не проблема Winston. Если вы попробуете console.log(`Caught error: ${e}`) он также не будет включать стек. Я мало работал с шаблонными литералами, поэтому либо шаблонные литералы не работают с объектами, либо javascript console.log распознает объект как объект ошибки и, таким образом, выводит только свойство сообщения. Это мое лучшее предположение.

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

Это помогает понять суть этой ветки ошибок. Сначала вы должны понять некоторые технические подробности о javascript. Обратите внимание, что если вы попробуете console.log(`Caught error: ${JSON.stringify(e)}`) вы получите тот же результат Caught error: {} . Как пояснил @indexzero :

Свойства message и stack в Error не перечисляются, что приводит к тому, что JSON.stringify выводит то, чего никто не ожидает.

По сути, поскольку свойства message и stack не перечислимые, JSON.stringify пропускает эти свойства, что и приводит к пустому объекту {} . Чтобы лучше понять перечислимость, я рекомендую прочитать это перечисление и владение свойствами .

К счастью, благодаря способу разработки Winston 3.0 (поддержка команды Winston) у нас есть обходной путь, который дал @indexzero . Я помогу это объяснить. Сначала вы создаете эту функцию:

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;
});

Из объектов docs info.level и info.message . Это свойство info.message ЯВЛЯЕТСЯ объектом ошибки, если это все, что вы передали. Итак, мы создаем новый объект, где message.stack и message.message (Думайте об этом как Error.stack и Error.message ) теперь можно перечислить, и мы включаем любые другие свойства, которые также могут быть прикреплены к этому объекту ошибки.

Затем вы создадите этот регистратор, который использует указанную выше функцию enumerateErrorFormat() :

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

Это возьмет все, что вы передадите message , и проверит, является ли это объектом ошибки. Если это так, это решит проблему с перечислением. Затем он передает сообщение в format.json который преобразует любой объект в строку (ошибка или нет). Если это не объект, то это строка, и format.json Effectivley ничего не делает, и вы дома бесплатно!

Тем не менее, было бы неплохо, если бы нам не нужно было создавать этот enumerateErrorFormat поскольку объекты ошибок обычно регистрируются. Насколько я понимаю, команда Winston работает над исправлением, которое будет выпущено в более поздней версии.

Несколько заключительных примечаний. Это работает, только если вы используете logger.log({level: <level>, message: <message>}) где сообщение - это объект ошибки. Пример:

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

В Winston есть еще одна ошибка, из-за которой этот код не работает, как я объяснил в другом посте выше:

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

По какой-то причине свойство info.message не определено, когда мы используем logger.error(err) . Надеюсь, @indexzero сможет понять это.

@ SamuelMaddox17 @indexzero Спасибо! Я пробовал использовать logger.log({level: 'error', message: err}); и он работает

Можно ли исправить ошибку logger.error и т. Д.?

Использование logger.log громоздко и многословно, тем более что с помощью logger.error вы можете легко добавить несколько аргументов.

Привет всем, я разбираюсь в этом. @indexzero : по-прежнему считаете, что лучше всего добавить функциональность enumerateErrorFormat в средство форматирования json по умолчанию? Нужно ли нам отдельно беспокоиться о том, является ли meta Error не просто object (я предполагаю, что люди будут жаловаться, если мы также не рассмотрим этот случай?) ? Кроме того, я использую master , но похоже, что logger.error у меня работает с решением от @indexzero / @ SamuelMaddox17 выше:

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'));

После дальнейшего исследования выяснилось, что проблема logger.error я объяснил выше, возникает только при использовании регистратора по умолчанию. @DABH , я попробовал ваш код, и он у меня работает, но когда я переключаю его на регистратор по умолчанию, он не работает:

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'));

Во-вторых, я согласен с тем, что enumerateErrorFormat следует добавить в формат json; и вы, вероятно, правы и насчет meta .

Наконец, я хотел бы отметить, что пример кода, приведенный @DABH, заставляет стек не "печатать красиво", если хотите; по крайней мере, на моей машине под управлением macOS High Sierra. Для меня это выглядит так:

{"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"}

Как видите, при выводе ошибки с помощью функции JSON символы новой строки \n не создают фактических новых строк. Это ожидаемое поведение при взятии объекта и его преобразовании в JSON, но, вероятно, это не то поведение, которое мы действительно хотели бы от регистратора, по крайней мере, при входе в консоль.

Спасибо, что заглянули в этот @DABH.

К вашему сведению, это то, к чему я добрался, немного поиграв с этим:

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;

Проблема вызвана этой ошибкой: https://github.com/winstonjs/winston-transport/issues/31

Мы определенно использовали эту форму в winston2.x без проблем. winston.err('some message', err); вместе с winston.error(err) enumerateErrorFormat исправляет winston.error(err) но не вариант использования с ошибкой в ​​качестве второго параметра.

@ SamuelMaddox17

logger.log ({уровень: ____, сообщение: ошибка});

это работает спасибо

Хорошо, я кое-что обнаружил. Мой комментарий от 3 сентября неверен. Это не проблема с регистратором по умолчанию. Это проблема, когда вы определяете level и / или format . @DABH вот ваш старый код:

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'));

Если вы удалите это:

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

И замените это на это:

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

Затем появляется проблема info.message === undefined . Я считаю, что можно указать уровень и формат для каждого транспорта; и я почти уверен, что это было разрешено в Winston 2.0.

Вот ваш образец кода с моим изменением кода, чтобы вы могли легко запустить и протестировать:

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'));

Надеюсь, это поможет разобраться в корне проблемы.

Я создал https://github.com/winstonjs/winston/pull/1527

Это охватывает все варианты. Однако некоторые тесты не проходят, поэтому я пока закрыл его. Ожидаются сбои с учетом исправления, но я не верю, что могу сделать призыв изменить / удалить тесты.

Неудачная сборка находится здесь https://travis-ci.org/winstonjs/winston/jobs/453012141, и это очевидно, почему тесты теперь терпят неудачу, когда вы читаете тестовый код:
https://github.com/winstonjs/winston/blob/c42ab7fdc51b88db180a7dd90c52ce04ddd4e054/test/logger.test.js#L668

Мысли?

Я думаю проблема в этой строчке
const info = (msg && !(msg instanceof Error) && msg.message && msg) || {
сообщение: msg
};
добавление проверки instanceof Error, похоже, решает проблему, как

Для тех, кто все еще имеет дело с этим, это средство форматирования обходного пути, которое мне удалось придумать (фрагмент моего модуля logger.js):

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));
}

По какой-то причине logger.error(new Error("hello")) работает только в том случае, если вы определяете средство форматирования глобально в winston.createLogger 🤔, а затем получаете объект Error в info в средстве форматирования.

Если вы определяете средство форматирования для каждого транспорта, вам нужно использовать logger.log({level: "error", message: new Error("FAILED")}) и обрабатывать объект Error через info.message вместо info для доступа к объекту Error.

Я предполагаю, что есть ошибка при установке поля формата в опциях транспорта?

Это всего лишь мои 2 цента, и то, что у меня сработало, я новичок в Winston и не опытен в JavaScript, так что не цитируйте меня ни в чем.

Мой подход был попыткой устранить основную причину. Но особой поддержки со стороны владельцев репо он не получает ...

Да, я это понимаю. Я буквально потратил много времени на выяснение этого, потому что я новичок в Уинстоне и подумал, что, возможно, я использую его неправильно или еще недостаточно хорошо понял концепции, лежащие в основе этого.

Но, к счастью, я наткнулся на несколько тем (включая эту), которые показали мне обратное. Надеюсь, они исправят это, так что мне не придется продолжать использовать обходной путь.

Это может быть вызвано wintson-transport , проблему см. Https://github.com/winstonjs/winston-transport/issues/31 и https://github.com/winstonjs/winston-transport/pull/ 34 для PR.

Прямая регистрация объектов ошибок всегда вызывает беспорядок из-за их неперечислимых свойств. Лично я считаю это плохой практикой, но достаточное количество людей в сообществе непреклонно относятся к этому как к требованию, которое мы должны поддерживать.

Рассмотрение принятия https://github.com/winstonjs/logform/pull/59 в качестве формата для поддержки подобного поведения. С другой стороны, он инкапсулирует все крайние случаи, которые так часто встречаются при обработке ошибок как сообщений журнала. С другой стороны, это был бы еще один формат, на который людям нужно было бы согласиться (аналогично .splat() ).

@indexzero Я склонен согласиться, но прямое ведение журнала ошибок может быть полезно в сочетании с настраиваемым форматом ведения журнала / printf, если есть необходимость отображать несколько типов Error разному, и я не помню, чтобы Winston 2.x пытался бороться с этой практикой, поскольку это было разрешено нестандартно.

Таким образом, предлагаемое решение для enumerateErrorFormat работает, но не поддерживает формат logger.error('some message', err) . Потому что ни info.message ни info являются instanceof Error . Также хочу отметить еще одну проблему с этим решением. В настоящее время я регистрирую ошибку, возвращаемую из 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  
    }

Если мы просто используем Object.assign, тогда охладим стек и сообщение будет установлено! НО, любая другая информация, которая была частью ошибки, также будет записана. Это может быть очень опасно в случаях, когда ошибки содержат конфиденциальные данные, такие как Authorization Headers (которые в этом случае включаются как часть объекта ошибки).

Но тогда можно сказать. Это не вина Winston, и не вина Winston, что суперагент добавляет эти данные к ошибке. Я СОГЛАСЕН! ОДНАКО, поскольку все хранится в объекте info становится очень сложно сохранить старую информацию и не переопределить остальную.

Было бы неплохо, если бы при использовании logger.error. Он предположил, что второй параметр был ошибкой и поместил его в объект info как info.error а затем, если ведение журнала другим способом, интерфейс будет { level: "error", error: YOUR ERROR OBJECT}

Я действительно здесь просто плевался, но новый интерфейс определенно немного разочаровал (все в информации).

Чтобы уточнить, о чем я говорил, предположим, что вы logger.error( e ) где e имеет ошибку типа.

Затем в вашем коде вы настроили Winston следующим образом:

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

метка времени помещается в объект ошибки 😱. Это действительно имеет смысл? Подумайте об этом ... объект ошибки, который вы отправили, динамически получает новую опору ... метку времени.

Я думаю, что лучшим решением этой проблемы будет поддержка следующего синтаксиса

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

а затем внутри вы можете создать средство форматирования ошибок, которое ищет поле ошибки!

Обновите это, ребята:

Надеюсь, что это зашито и отправлено в ближайшие пару дней. Это предпоследний выпуск в нашем трекере [email protected]

Привет, ребята - посетите https://github.com/winstonjs/winston/pull/1562. Это был последний пункт в нашем контрольном списке выпуска 3.2.0 поэтому, как только PR будет зашит, мы сможем выпустить его.

Пока исправление не будет опубликовано, я использую следующий обходной путь:

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

Я использую последнюю версию Winston (3.2.1) и все еще получаю undefined при передаче ошибки logger.error

У @ezze было отличное решение, но трассировка стека

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

с выходом <Error message> - trace: <stack trace>

Если есть более простой способ сделать это с помощью последней версии Winston, дайте мне знать @indexzero. Я новичок в библиотеке и следил за документами

Я только что увидел ссылку, которую вы разместили в PR. Означает ли это, что для передачи ошибки в logger.error требуется строка сообщения, а затем ошибка?

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 В этой ветке обсуждались две проблемы. Первое - это то, что было сказано на оригинальном плакате, а второе - проблема, которую я поднял, и она совпадает с вашей. Я думаю, они исправили только исходную проблему с плакатами. Я собирался проверить дальше, чтобы убедиться, а затем открыть новую проблему, если это так. К сожалению, у меня не было времени нырять глубже. Между тем, если вы используете logger.log({level: 'error', message: err}); где err - это объект ошибки, он будет работать.

У вас все еще есть эта проблема, потеряли кучу времени, чтобы понять это, решение от @ the-vampiire работает хорошо.

Почему этот билет закрыт?

Переопределение logger.error пока является лучшим решением, поскольку оно не добавляет свойство отметки времени к объекту Error, который передается как единственный аргумент функции error (). Большинство людей, вероятно, ожидают, что объекты Error неизменяемы. Если вы также не переопределите logger.info и любой другой метод, связанный с уровнем, будет сюрпризом, когда что-то работает не так, как ожидалось. Опять же, если вы не хотите, чтобы ваш объект был изменен, независимо от его типа, не отправляйте его напрямую методу регистратора Winston.

Функция поддерживается с [email protected]

Пример использования:

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 @ вампир

Я тоже все еще сталкиваюсь с проблемой.
Когда я вызываю ошибку типа logger.error(error); я получаю только undefined .
Только если я назову это как logger.error('Something went wrong', error) я получаю полную ошибку и могу ее проанализировать.

Я тоже все еще сталкиваюсь с проблемой.
Когда я вызываю ошибку типа logger.error(error); я получаю только undefined .
Только если я назову это как logger.error('Something went wrong', error) я получаю полную ошибку и могу ее проанализировать.
Вы это добавили?

format.errors({ stack: true })

Да, все та же проблема. Я пытаюсь передать это вкратце.

@ OBrown92 Сегодня я столкнулся с той же проблемой. Я могу подтвердить, что это работает, если format.errors({ stack: true }) применяется к регистратору, а не к транспорту. В этом случае можно использовать как logger.error(error); и logger.error('Something went wrong', error) . Однако возникает проблема, когда я пытаюсь применить format.errors({ stack: true }) к выбранному транспорту. В этом случае я получаю undefined за logger.error(error); , но logger.error('Something went wrong', error) работает правильно.

Я не уверен, ожидаемое это поведение или это ошибка, но я потратил много времени, чтобы найти причину, поэтому, пожалуйста, исправьте ее или упомяните об этом где-нибудь в своей документации. Это было бы действительно полезно.

В любом случае, я очень благодарен вам за работу над этим замечательным проектом.

Я столкнулся с той же проблемой, поэтому написал этот пакет utils-deep-clone . Проверить это.

format.errors is not a function ... ну это сюрприз.

@holmberd
Вы импортировали форматы из пакета winston?
Пример использования:
const { format } = require('winston')
Или же
const winston = require('winston'); const { format } = winston;

@aybhalala yepp, хотя не имеет значения, что стек ошибок передается в printf без него.

Обновление: поскольку с этим все еще есть проблемы, я некоторое время делал следующее, и он отлично работал

// 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 } );

^^ Это ожидаемое использование. Поскольку простые смертные никогда в этом не догадаются, это следует задокументировать.

Поскольку простые смертные никогда в этом не догадаются, это следует задокументировать.

😂 +1 этому товарищу

Я использую winston со сторонним транспортом ( @google-cloud/logging-winston ), поэтому у меня немного меньше контроля над синтаксисом. К тому же я нахожу это более интуитивным:

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

При входе в консоль я присоединяю стек к сообщению. Но результат примерно такой:

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

Поскольку Winston объединяет meta.message с исходным сообщением, в стеке также печатается странное сообщение andsomething и дубликат сообщения. Это описано в №1660.

Похоже, что # 1664 пытается это исправить. Тем временем я написал средство форматирования, которое «отменяет» это объединение: https://github.com/winstonjs/winston/issues/1660#issuecomment -512226578

@dandv

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

Это не работает, потому что, в отличие от console.log() , logger.<level>(message) Winston принимает только один параметр с именем message. Этот параметр сообщения является либо объектом, либо строкой (кто-нибудь поправит меня, если я ошибаюсь, но это мое понимание).

Обратите внимание, что вы также можете использовать logger.log({level: <level>, message: <message>}) . Чтобы узнать больше об этих двух функциях, я бы порекомендовал прочитать эту часть документации: Winston Docs on Log Levels . Обязательно ознакомьтесь с разделом Использование уровней ведения журнала.

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

Я не могу однозначно сказать, почему это не выводит стек, но я знаю, что это не проблема Winston. Если вы попробуете console.log(`Caught error: ${e}`) он также не будет включать стек. Я мало работал с шаблонными литералами, поэтому либо шаблонные литералы не работают с объектами, либо javascript console.log распознает объект как объект ошибки и, таким образом, выводит только свойство сообщения. Это мое лучшее предположение.

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

Это помогает понять суть этой ветки ошибок. Сначала вы должны понять некоторые технические подробности о javascript. Обратите внимание, что если вы попробуете console.log(`Caught error: ${JSON.stringify(e)}`) вы получите тот же результат Caught error: {} . Как пояснил @indexzero :

Свойства message и stack в Error не перечисляются, что приводит к тому, что JSON.stringify выводит то, чего никто не ожидает.

По сути, поскольку свойства message и stack не перечислимые, JSON.stringify пропускает эти свойства, что и приводит к пустому объекту {} . Чтобы лучше понять перечислимость, я рекомендую прочитать это перечисление и владение свойствами .

К счастью, благодаря способу разработки Winston 3.0 (поддержка команды Winston) у нас есть обходной путь, который дал @indexzero . Я помогу это объяснить. Сначала вы создаете эту функцию:

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;
});

Из объектов docs info.level и info.message . Это info.message свойство является объектом ошибки , если это все , что вы прошли в. Таким образом , мы создаем новый объект , где message.stack и message.message (Думайте об этом как Error.stack и Error.message ) теперь можно перечислить, и мы включаем любые другие свойства, которые также могут быть прикреплены к этому объекту ошибки.

Затем вы создадите этот регистратор, который использует указанную выше функцию enumerateErrorFormat() :

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

Это займет все message вами format.json который преобразует любой объект в строку (ошибка или нет). Если это не объект, то это строка, и format.json Effectivley ничего не делает, и вы дома бесплатно!

Тем не менее, было бы неплохо, если бы нам не нужно было создавать этот enumerateErrorFormat поскольку объекты ошибок обычно регистрируются. Насколько я понимаю, команда Winston работает над исправлением, которое будет выпущено в более поздней версии.

Несколько заключительных примечаний. Это работает, только если вы используете logger.log({level: <level>, message: <message>}) где сообщение - это объект ошибки. Пример:

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

В Winston есть еще одна ошибка, из-за которой этот код не работает, как я объяснил в другом посте выше:

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

По какой-то причине свойство info.message не определено, когда мы используем logger.error(err) . Надеюсь, @indexzero сможет понять это.

Очень хорошее объяснение, я просто хочу добавить это с ошибкой logger.error( Caught: $ {e} ); вы теряете стек из-за того, как строковый литерал работает в javascript, `${e}` в точности совпадает с e.toString() , поэтому печать только сообщения об ошибке является ожидаемым поведением.

Это все еще проблема? У меня все еще проблемы с этим:

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
}

Это все еще проблема? У меня все еще проблемы с этим:

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
}

такая же проблема здесь ...

посмотрев исходный код, я могу увидеть, какие параметры он принимает:

interface LeveledLogMethod {
(сообщение: строка, обратный вызов: LogCallback): Регистратор;
(сообщение: строка, мета: любой, обратный вызов: LogCallback): Регистратор;
(сообщение: строка, ... мета: любой []): Регистратор;
(infoObject: object): Регистратор;
}

поэтому, если вы передадите объект ошибки в качестве первого параметра, он будет принимать только сообщение об ошибке, потому что он понимает только строки, и если вы передадите ошибку во втором параметре, вы можете получить доступ к трассировке стека в info.stack

кстати, я не мог найти этого нигде в документации

Я нашел два решения, первое - использовать format.errors , указанное в форме журнала в родительском регистраторе, затем создать messageFormatter с помощью format.printf и условно добавить поле stack извлеченное из info ( format.errors({ stack: true}) добавит это).

Другое решение, которое я предпочел, - это взломать логгеры уровня 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)
  }  
})

Кажется, таким образом я могу получить журнал ошибок, похожий на console.log

Я могу проверить, что комментарий @tiagonapoli о том, как format.errors должен быть в _parent_ logger, точен. Когда я делаю что-то вроде этого:

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);

Обработка объекта Error происходит так, как если бы он был строкой. Однако, если я сделаю что-то вроде этого:

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);

Обработка объекта Error работает правильно.

Мне кажется, что ошибка здесь в том, что никакой разницы в поведении быть не должно.

Значит, по прошествии 1 года это все еще не исправлено? Нужно ли мне взламывать код Winston Logger, чтобы он заработал?

Да, это доставило мне достаточно головной боли, и Уинстон начал казаться намного больше проблем, чем это того стоило для моего относительно простого варианта использования ... В итоге я просто написал свой собственный небольшой класс регистратора, и я бы рекомендовал другим сделать то же самое, если только Уинстон предоставляет то, что вам ДЕЙСТВИТЕЛЬНО нужно.

Ребята, правда? это расстраивает ...

Я не коммиттер, но, вероятно, правильно скажу, что это не будет «исправлено», потому что оно не сломано. Winston стоит использовать. Вам просто нужно настроить его - лучший совет для меня выше на https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691

Еще нет ?

Обновление: поскольку с этим все еще есть проблемы, я некоторое время делал следующее, и он отлично работал

// 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 } );

откуда идет след?

Нет, правда, это недопустимо для библиотеки журналов.
Сопровождающий должен просто поместить хорошо выделенный пример в документы, где показано, как регистрировать ошибку, даже определяя собственный формат printf и формат, отличный от json, и где вы можете регистрировать ошибку с помощью чего-то вроде logger.error ("что-то", err) и регистратора .error (ошибка)
Уинстон казался отличным, но эта проблема невероятно неприемлема.

Это мой взгляд на то, как регистрировать ошибки с помощью Winston. Это не уникально, многие взгляды выше имеют рабочие решения, основанные на тех же концепциях.

Задний план
Я использую @jsdevtools/ono чтобы обернуть произвольные типы объектов в пользовательские ошибки, но, несмотря на это, это решение по-прежнему отлично работает с ошибками собственных узлов (например, с ошибками fs eperm) и пользовательскими классами ошибок.

Объяснение
В основном я полагаюсь на format.errors({stack:true}) и format.metadata() . Как упоминалось https://github.com/winstonjs/winston/issues/1338#issuecomment -532327143, это должно быть в родительском модуле форматирования.

Метаданные помогают сдвинуть все настраиваемые свойства объекта ошибки на info.metadata .

Я хотел напечатать 3 типа информации: сообщение об ошибке, трассировку стека и свойства объекта ошибки. Сообщение об ошибке уже было открытым текстом. Я красиво распечатал стек info.metadata.stack с помощью модуля pretty-error . Что касается свойств объекта ошибки, я не хотел, чтобы трассировка стека снова появлялась, поэтому я клонировал объект и удалил свойство трассировки стека. Затем я красиво распечатал объект ошибки, используя fast-safe-stringify , который является тем же модулем строкового преобразования, на который полагается 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: Я также считаю, что решение, упомянутое в https://github.com/winstonjs/winston/issues/1338#issuecomment -506354691, является хорошей альтернативой. Т.е. используя logger.warn("Oh no", { error: new Error() }) , а затем ссылку на info.error в пользовательском средстве форматирования.

@tiagonapoli ваше решение об использовании format.errors в родительском регистраторе сработало для меня:

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

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

Настраивать этот регистратор довольно болезненно ... Неужели он не может вести себя как console.log из коробки?

@ will093 и здесь. Я снова столкнулся с этой проблемой и не понимаю, почему мой console.log красивый и чистый, а формат Winston - дерьмо.

Мой 2 ¢

// 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;
            }),
        ),
    }));
}

Пример для logger.error("Error during schema stitching", e);

image

Использование @tiagonapoli и @ will093 решения по добавлению его только к родительскому

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
      ),
  });
};

работает со стеком при вызове с ошибкой типа: logger.error(error) , работает со строкой при вызове типа logger.error('a regular message') , в моих журналах выглядит так:

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

это не пытается решить проблему несовместимости Winston logger.error('message here', error) с console.log , которую, похоже , сложное решение

Кроме того, если вам нравятся журналы json, вы можете оставить здесь logFormatter и использовать вместо него winston.format.json() , который по-прежнему будет включать стек, но это некрасиво.

Обновление: поскольку с этим все еще есть проблемы, я некоторое время делал следующее, и он отлично работал

// 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 } );

где определение trace ()?

Обновление: поскольку с этим все еще есть проблемы, я некоторое время делал следующее, и он отлично работал

// 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 } );

откуда идет след?

есть ответ по этому поводу?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги