Winston: Уинстон ведет журнал во все файлы. (или: ограничить транспорт только 1 уровнем)

Созданный на 27 апр. 2015  ·  23Комментарии  ·  Источник: winstonjs/winston

Это моя конфигурация Winston:

var winston = require('winston');
var fs = require('fs');
var _ = require('lodash');

winston.emitErrs = true;

var logDir = 'logs';
if (!fs.existsSync(logDir)) {
    fs.mkdirSync(logDir);
}

//add custom logging levels
var levels = _.clone(winston.config.syslog.levels);
var colors = _.clone(winston.config.syslog.colors);

levels.request = _.max(levels) + 1;
colors.request = 'blue';

var logger = new winston.Logger({
    levels: levels,
    colors: colors,
    exceptionHandlers: [
        new winston.transports.File({filename: 'logs/exceptions.log'})
    ],
    transports: [
        new winston.transports.File({
            name: 'info-file',
            level: 'info',
            filename: 'logs/all-logs.log',
            json: true,
            maxsize: 5242880, //5MB
            maxFiles: 5,
            colorize: false
        }),
        new winston.transports.File({
            name: 'error-file',
            level: 'error',
            filename: 'logs/error-logs.log',
            json: true,
            maxsize: 5242880, //5MB
            maxFiles: 5,
            colorize: false
        }),
        new winston.transports.File({
            name: 'request-file',
            level: 'request',
            filename: 'logs/requests.log',
            json: true,
            maxsize: 5242880, //5MB
            maxFiles: 5,
            colorize: false
        })
    ],
    exitOnError: false
});

module.exports = logger;

Пытаюсь логировать ошибки, http-запросы и исключения в свои файлы.
Однако я вижу, например, в журналах запросов error-logs.log (http).

Кто-нибудь может мне объяснить, что я делаю не так?

feature request investigate

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

Я использую Winston 3.x, после проб и ошибок я обнаружил, что мы можем фильтровать журнал по уровню, чтобы записывать их в отдельные файлы. Вот код, который я использовал:

const customFormat = winston.format.printf(i => {
    return `${i.level.toUpperCase()}: ${i.timestamp} ${i.message}`;
});

// Log unhandled exceptions to separate file
var exceptionHandlers = [
    new (winston.transports.DailyRotateFile)({
        name: 'Error Logs',
        filename: 'server/logs/errlogs/exceptions-%DATE%.log',
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        maxSize: '128m',
        maxFiles: '14d'
    })
]

const infoAndWarnFilter = winston.format((info, opts) => { 
    return info.level === 'info' || info.level === 'warn' ? info : false
})

const errorFilter = winston.format((info, opts) => { 
    return info.level === 'error' ? info : false 
})

// Separate warn/error 
var transports = [
    new (winston.transports.DailyRotateFile)({
        name: 'Error Logs',
        filename: 'server/logs/errlogs/application-%DATE%.log',
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        maxSize: '128m',
        maxFiles: '14d',
        level: 'warn',
        json: true,
        colorize: false,
        format: winston.format.combine(
            errorFilter(),
            winston.format.timestamp(),
            customFormat
        )
    }),
    new (winston.transports.DailyRotateFile)({
        name: 'INFO logs',
        filename: 'server/logs/infologs/application-%DATE%.log',
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        maxSize: '128m',
        maxFiles: '14d',
        json: true,
        colorize: false,
        level: 'info',
        format: winston.format.combine(
            infoAndWarnFilter(),
            winston.format.timestamp(),
            customFormat
        )
    }),
    new (winston.transports.Console)({      
        level: config.debugMode ? 'debug' : 'warn', // log warn level to console only
        handleExceptions: true,
        json: false,
        colorize: true,
        format: winston.format.combine(
            winston.format.colorize(),
            winston.format.simple()
        )
    })
]

var logger = winston.createLogger({
    transports: transports,
    exceptionHandlers: exceptionHandlers,
    level: config.debugMode ? 'debug' : 'info',
    exitOnError: false,
    // Default format
    format: winston.format.combine(
        winston.format.timestamp(),
        customFormat
    )
})

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

Вот как я регистрирую запросы

// Log all requests
app.use(function(req, res, next) {
    var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;
    logger.log('request', req.method, req.url, ip);
    next();
});

Но посмотрите результат во всех трех файлах:
имя файла: 'журналы / all-logs.log',
имя файла: 'журналы / error-logs.log',
имя файла: 'журналы / запросы.log'

Все, что я хочу, - это чтобы пользовательский уровень «запроса» выводился только в отдельный файл.

@ t0lkman Я считаю, что вам нужно вызвать setLevel explicilty в своем экземпляре Logger , но это может быть ошибкой при установке пользовательских уровней. Мы будем исследовать.

В идеале я хочу иметь разные файлы журналов для разных вещей ... например, все HTTP-запросы отправляются в одно место, все ошибки mongo - в другое и т. Д.

В настоящее время существует некоторая иерархическая система ведения журнала ... где это зависит от порядка ведения журнала ..

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

Моя конфигурация Winston:

logger = new winston.Logger({
        emitErrs: true,
        transports: [
            new winston.transports.Console({
                level:'debug',
                name: 'console',
                handleExceptions: true,
                prettyPrint: true,
                silent:false,
                timestamp: true,
                colorize: true,
                json: false
            }),
            new winston.transports.DailyRotateFile({
                level:'info',
                name: 'info',
                filename: accessLogsPath,
                handleExceptions: true,
                prettyPrint: true,
                silent:false,
                timestamp: true,
                json: true,
                colorize: true,
                maxsize: 20000,
                tailable: true
            }),
            new winston.transports.DailyRotateFile({
                level:'error',
                name: 'error',
                filename: errorLogsPath,
                handleExceptions: true,
                prettyPrint: true,
                silent: false,
                timestamp: true,
                json: true,
                colorize: false,
                maxsize: 20000,
                tailable: true
            })
        ],
        exitOnError: false 
    });

Затем, когда я запускаю moduleName.logger.error(err); он выводит все три (я ожидал, что это из-за отладки, но не информации). Я изменил level:'error', на level:'debug', и просто регистрирую ошибки для отладки только в качестве обходного пути.

@NukaPunk Разве это не ожидаемое поведение регистратора?

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

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

Спасибо за ответ @masom.

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

Спасибо еще раз.

@NukaPunk, да, нелогично . То же самое произошло с другими языковыми регистраторами, и некоторые из них позволяют вам указывать исключительный уровень журнала для определенного транспорта.

@masom так что не баг, а фича ;-)

Файл readme на самом деле не объясняет концепцию ведения журнала нижнего уровня, поэтому я предположил, что уровни были исключительными. Я бы рекомендовал добавить некоторую информацию об этом в readme, чтобы избежать путаницы, если это возможно.

Еще раз спасибо, отличная работа по лесозаготовительному транспорту!

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

@ t0lkman Я предполагаю, что это будет примерно так:

module.exports = {
    errorLog: new winston.Logger({
        levels: levels,
        colors: colors,
        exceptionHandlers: [
            new winston.transports.File({filename: 'logs/exceptions.log'})
        ],
        transports: [

            new winston.transports.File({
                name: 'error-file',
                level: 'error',
                filename: 'logs/error-logs.log',
                json: true,
                maxsize: 5242880, //5MB
                maxFiles: 5,
                colorize: false
            })
        ],
        exitOnError: false
    }),
    requestLog: new winston.Logger({
            levels: levels,
            colors: colors,
            exceptionHandlers: [
                new winston.transports.File({filename: 'logs/exceptions.log'})
            ],
            transports: [
                new winston.transports.File({
                    name: 'request-file',
                    level: 'request',
                    filename: 'logs/requests.log',
                    json: true,
                    maxsize: 5242880, //5MB
                    maxFiles: 5,
                    colorize: false
                })
            ],
            exitOnError: false
        }
    ),

    infoLog: new winston.Logger({
        levels: levels,
        colors: colors,
        exceptionHandlers: [
            new winston.transports.File({filename: 'logs/exceptions.log'})
        ],
        transports: [
            new winston.transports.File({
                name: 'info-file',
                level: 'info',
                filename: 'logs/all-logs.log',
                json: true,
                maxsize: 5242880, //5MB
                maxFiles: 5,
                colorize: false
            })
        ],
        exitOnError: false
    })
};

И тогда вы могли бы использовать это так:

var logger = require(/path/to/file);

logger.errorLog('This is an error!');
logger.infoLog('This is info!');
logger.request('request', req.method, req.url, ip);

В качестве альтернативы вы можете довольно легко использовать Morgan для регистрации запросов:

infoLogger.stream = {
    write: function(message, encoding){
        logger.info(message);
    }
};
app.use(require("morgan")("combined", { "stream":  infoLogger.stream }));

Надеюсь, это поможет!

Пробовал, не вышло :(

new winston.Logger( возвращает объект, но ожидает функцию

@ t0lkman Вы правы. Я попробовал это, и это не работает (это то, что я получаю, когда пишу это в моем браузере). Попробуйте вместо этого:

var errorLog = require('./models/winston').errorLog;
errorLog.error('test');

какие-нибудь обновления по этому поводу?

@davidfeldi Может быть, это поможет, я сталкивался с этой проблемой раньше, и мне удалось создать свою собственную оболочку. Это разделяет журналы ошибок для каждого уровня. https://github.com/odegraciajr/winston-logger

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

Привет, ребята, вот мое решение проблемы (также в gist: winston-logger.js )

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

const getLogger = (module, type) => {
    const modulePath = module.filename.split('/').slice(-2).join('/');
    const logger = new winston.Logger({
        transports: [
            new (winston.transports.Console)({
                colorize: true,
                level: (process.env.NODE_ENV === 'development') ? 'debug' : 'error',
                label: modulePath
            })
        ]
    });

    switch (type) {
        case 'error':
            logger.add(winston.transports.File, {
                name: 'error-file',
                filename: path.join(__dirname, '../../logs/error_default.log'),
                level: 'error'
            });
            return logger;
        case 'info':
            logger.add(winston.transports.File, {
                name: 'info-file',
                filename: path.join(__dirname, '../../logs/info_default.log'),
                level: 'info'
            });
            return logger;
        default:
            return logger;
    }
};

module.exports = module => ({
    error(err) {
        getLogger(module, 'error').error(err);
    },
    info(err) {
        getLogger(module, 'info').info(err);
    },
    debug(err) {
        getLogger(module, 'default').debug(err);
    }
});

Использование:

const logger = require('path/to/logger')(module);
logger.info('Logging with winston');

Оно работает! только если минимальный уровень журнала должен быть одинаковым для всех определенных транспортов,
например
new (winston.Logger) ({
транспорты: [
новый (winston.transports.Console) ({ level : ' error '}),
new (winston.transports.File) ({
имя: 'файл-ошибки',
уровень : ' ошибка ',
имя_файла: 'имя_файла.log',
json: правда,
maxsize: 5242880, // 5 МБ
maxFiles: 5,
раскрасить: ложь
})
],
exitOnError: ложь
});

Лично я считаю, что каждый транспорт должен регистрироваться в соответствии с определенным уровнем

Любое обновление по этому поводу, последняя версия rc3 не работает

Вы можете добиться этого с помощью настраиваемого формата, который проверяет желаемый уровень:

    `new transports.File({
            filename: logFileInfo,
            level: 'info',
            json: false,
            format: combine(
                timestamp(),
                printf(i => i.level === 'info' ? `${i.level.toUpperCase()}: ${i.timestamp} ${i.message}` : '')
            )
        })`

+1

@ madal3x Это все равно будет записывать пустые строки в файл, если уровень не совпадает. Я пробовал вернуть null или даже ничего не вернуть, но он все еще регистрирует null / undefined. Если что-то не изменилось в версии 3.x, о которой я не знаю.

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

Более надежным решением может быть добавление к транспорту некоторой функции перехвата, которая позволила бы возвращать true для регистрации сообщения или false для его игнорирования.

Я использую Winston 3.x, после проб и ошибок я обнаружил, что мы можем фильтровать журнал по уровню, чтобы записывать их в отдельные файлы. Вот код, который я использовал:

const customFormat = winston.format.printf(i => {
    return `${i.level.toUpperCase()}: ${i.timestamp} ${i.message}`;
});

// Log unhandled exceptions to separate file
var exceptionHandlers = [
    new (winston.transports.DailyRotateFile)({
        name: 'Error Logs',
        filename: 'server/logs/errlogs/exceptions-%DATE%.log',
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        maxSize: '128m',
        maxFiles: '14d'
    })
]

const infoAndWarnFilter = winston.format((info, opts) => { 
    return info.level === 'info' || info.level === 'warn' ? info : false
})

const errorFilter = winston.format((info, opts) => { 
    return info.level === 'error' ? info : false 
})

// Separate warn/error 
var transports = [
    new (winston.transports.DailyRotateFile)({
        name: 'Error Logs',
        filename: 'server/logs/errlogs/application-%DATE%.log',
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        maxSize: '128m',
        maxFiles: '14d',
        level: 'warn',
        json: true,
        colorize: false,
        format: winston.format.combine(
            errorFilter(),
            winston.format.timestamp(),
            customFormat
        )
    }),
    new (winston.transports.DailyRotateFile)({
        name: 'INFO logs',
        filename: 'server/logs/infologs/application-%DATE%.log',
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        maxSize: '128m',
        maxFiles: '14d',
        json: true,
        colorize: false,
        level: 'info',
        format: winston.format.combine(
            infoAndWarnFilter(),
            winston.format.timestamp(),
            customFormat
        )
    }),
    new (winston.transports.Console)({      
        level: config.debugMode ? 'debug' : 'warn', // log warn level to console only
        handleExceptions: true,
        json: false,
        colorize: true,
        format: winston.format.combine(
            winston.format.colorize(),
            winston.format.simple()
        )
    })
]

var logger = winston.createLogger({
    transports: transports,
    exceptionHandlers: exceptionHandlers,
    level: config.debugMode ? 'debug' : 'info',
    exitOnError: false,
    // Default format
    format: winston.format.combine(
        winston.format.timestamp(),
        customFormat
    )
})

@ngthienlinh Вы правы, это работает, и это даже подробно описано в разделе Filtering info Objects документации по версии 3.x. Не знаю, как я это раньше пропустил. Это работает довольно хорошо и в основном превращает функцию форматирования в надежную архитектуру промежуточного программного обеспечения.

Я думаю, что теперь эту проблему можно закрыть, поскольку четко указано, что над кодовой базой Winston 2.x больше не ведется работа.

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