Winston: рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдкреНрд░рд╛рд░реВрдк рдХреЛ рдХреИрд╕реЗ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░реЗрдВ?

рдХреЛ рдирд┐рд░реНрдорд┐рдд 10 рдирд╡ре░ 2017  ┬╖  18рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: winstonjs/winston

рдореИрдВ 3.0.0-рдЖрд░рд╕реА1 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИрдВ рдХрд┐ рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдХреЗ рдкреНрд░рд╛рд░реВрдк рдХреЛ рдХреИрд╕реЗ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПред рдХреГрдкрдпрд╛ рдорджрдж рдХреАрдЬрд┐рдПред

рдзрдиреНрдпрд╡рд╛рдж,
рдЕрд▓рд╡рд╛рд░реЛ

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк (рдЬреЛ рд╡реИрд╕реЗ рднреА рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП) рдХреЛ рдкреНрд░рд┐рдВрдЯ рдХрд░рдиреЗ рдХреА рд╕рдмрд╕реЗ рд╕рд░рд▓ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рд▓рд┐рдП рдпрд╣ рдмрд╣реБрдд рд╣реА рдЬрдЯрд┐рд▓ рд╣реИ: /

рд╕рднреА 18 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдкреНрд░рд╛рд░реВрдк рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╕реНрд╡рдпрдВ рдХреА рд╕рд╣рд╛рдпрддрд╛ рдХреЗ рд▓рд┐рдП рдЖрдк рд╕реНрд░реЛрдд рдХреЛрдб рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред рдореИрдВ рдЖрдкрдХреЛ рдЕрдкрдирд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджреЗ рд╕рдХрддрд╛ рд╣реВрдВред

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

const logger = winston.createLogger({
    level: 'info',
    format: winston.format.combine(
        winston.format(function(info, opts) {
            prefix = util.format('[%s] [%s]', moment().format('YYYY-MM-DD hh:mm:ss').trim(), info.level.toUpperCase());
            if (info.splat) {
                info.message = util.format('%s %s', prefix, util.format(info.message, ...info.splat));
            } else {
                info.message = util.format('%s %s', prefix, info.message);
            }
            return info;
        })(),
        winston.format(function(info) {
            info[MESSAGE] = info.message + ' ' + JSON.stringify(
                Object.assign({}, info, {
                    level: undefined,
                    message: undefined,
                    splat: undefined
                })
            );
            return info;
        })()
    ),
    transports: [
        new winston.transports.Console(),
        new winston.transports.File({ filename: './logs/bitcoin.log' })
    ]
});

рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк (рдЬреЛ рд╡реИрд╕реЗ рднреА рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП) рдХреЛ рдкреНрд░рд┐рдВрдЯ рдХрд░рдиреЗ рдХреА рд╕рдмрд╕реЗ рд╕рд░рд▓ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рд▓рд┐рдП рдпрд╣ рдмрд╣реБрдд рд╣реА рдЬрдЯрд┐рд▓ рд╣реИ: /

рдпрд╣рд╛рдБ рдореИрдВ рдХреНрдпрд╛ рдХрд░рддрд╛ рд╣реВрдБ...

// рд▓рдХрдбрд╝рд╣рд╛рд░рд╛.рдЬреЗрдПрд╕

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

// create formatter for dates used as timestamps
//const tsFormat = () => (new Date()).toLocaleTimeString();
const tsFormat = () => moment().format('YYYY-MM-DD hh:mm:ss').trim();

// define a logger with 2 transports - console and a file
const logger = new (winston.Logger)({
  transports: [
    // colorize the output to the console
    new (winston.transports.Console)({
        timestamp: tsFormat,
        colorize: true
    }),
    new winston.transports.File({
        filename: './logs/ttracker.log',
        timestamp: tsFormat,            // makes timestamp 'pretty'
        json: false                 // makes log format just like console output
    })
  ]
});

// set logging level one of { error: 0, warn: 1, info: 2, verbose: 3, debug: 4, silly: 5 }
logger.level = 'debug';

module.exports = logger;

рдкреБрдирд╢реНрдЪ рдореИрдВ рдХреЗрд╡рд▓ рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реВрдВ: рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдХреНрдпреЛрдВрдХрд┐ рдореБрдЭреЗ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкреНрд░рд╛рд░реВрдк рдкрд╕рдВрдж рдирд╣реАрдВ рд╣реИ рдЬреЛ рдЖрдкрдХреЛ рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рд╕реЗрдЯ рдХрд░рдХреЗ рдорд┐рд▓рддрд╛ рд╣реИ: рд╕рдЪ, рдпрд╛рдиреА 2017-12-05T08: 22: 09.179Z

@jimwhurr - рдореЗрд░реЗ рд▓рд┐рдП, рдЖрдкрдХрд╛ рдХреЛрдб (рдиреЛрдб v6.11.0) рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ:

Error: winston.Logger was moved in [email protected].
Use a winston.createLogger instead.
    at new <anonymous> (/Users/adrian/Documents/winston_test/node_modules/winston/lib/winston/common.js:162:15)
    at Object.<anonymous> (/Users/adrian/Documents/winston_test/index.js:7:16)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:389:7)
    at startup (bootstrap_node.js:149:9)

рдпрд╣рд╛рдВ рдЙрджрд╛рд╣рд░рдг рд▓реЗрддреЗ рд╣реБрдП, рдореИрдВрдиреЗ рдПрдХ рд╕рд░рд▓ рд╕реНрдЯреИрдВрдбрдЕрд▓реЛрди рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдпрд╛:

https://gist.github.com/ah/d02bd4ff238e5923fcf5369233e51401

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

const jsonFormatter = (logEntry) => {
  const base = { timestamp: new Date() };
  const json = Object.assign(base, logEntry)
  logEntry[MESSAGE] = JSON.stringify(json);
  return logEntry;
}

const logger = winston.createLogger({
  level: 'info',
  format: winston.format(jsonFormatter)(),
  transports: new winston.transports.Console(),
});

logger.info('message content', { "context": "index.js", "metric": 1 })
logger.info('message content 2')

рдЖрдЙрдЯрдкреБрдЯ:

{"timestamp":"2017-12-07T16:07:10.518Z","context":"index.js","metric":1,"level":"info","message":"message content"}
{"timestamp":"2017-12-07T16:07:10.520Z","message":"message content 2","level":"info"}

рдирдорд╕реНрддреЗ, рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдХреЗ рд╕рд╛рде рд▓реЙрдЧрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдпрд╣рд╛рдВ рдПрдХ рдФрд░ рд╡рд┐рдХрд▓реНрдк рд╣реИ (3.0.0-рдЖрд░рд╕реА0 рдкрд░ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рдЧрдпрд╛):

рдХреЙрдиреНрд╕реНрдЯ рд╡рд┐рдВрд╕реНрдЯрди = рдЖрд╡рд╢реНрдпрдХрддрд╛ ('рд╡рд┐рдВрд╕реНрдЯрди');
рд╡рд░ customFormat = winton.format.combine (
рд╡рд┐рдВрд╕реНрдЯрдиред рдкреНрд░рд╛рд░реВрдк (
рдлрдВрдХреНрд╢рди рдбрд╛рдпрдирд╛рдорд┐рдХ рдХрдВрдЯреЗрдВрдЯ (рдЬрд╛рдирдХрд╛рд░реА, рдСрдкреНрдЯреНрд╕) {
рдЬрд╛рдирдХрд╛рд░реА рд╕реНрддрд░ = 'рдЬрд╛рдирдХрд╛рд░реА';
рдЕрдЧрд░ (рдЬрд╛рдирдХрд╛рд░реА рд╕рдордп) {
рд╡рд░ рдбреАрдЯреА = рдирдИ рддрд┐рдерд┐ (),
date_now = dt.getDate() <10? '0'+ dt.getDate() : dt.getDate(),
Month_now = (dt.getMonth() + 1) <10? '0'+ (dt.getMonth() + 1) : (dt.getMonth() + 1),
year_now = dt.getFullYear (),
hrs_now = dt.getHours (),
mins_now = dt.getMinutes (),
secs_now = dt.getSeconds (),
рдорд┐рд▓реАрд╕реЗрдХ_рдирд╛рдЙ = dt.getMilliseconds ();
info.time = ' '+date_now+'-'+month_now+'-'+year_now+' '+hrs_now+':'+mins_now+':'+secs_now+':'+millisec_now+' ';
}
рд╡рд╛рдкрд╕реА рдХреА рдЬрд╛рдирдХрд╛рд░реА;
}
) (),
рд╡рд┐рдВрд╕реНрдЯрди.рдлреЙрд░реНрдореИрдЯ.рд╕рд┐рдВрдкрд▓ () // рдкреНрд░рд╛рд░реВрдк рдЖрдЙрдЯрдкреБрдЯ, рднреА рд╕рдХрд╛рд░рд╛рддреНрдордХ рдЙрдкрдпреЛрдЧ: .json () (.simple рдХреЗ рдмрдЬрд╛рдп)
);

рдХреЙрдиреНрд╕реНрдЯ рд▓реЙрдЧрд░ = рд╡рд┐рдВрд╕реНрдЯрдиред рдХреНрд░рд┐рдПрдЯрд▓реЙрдЧрд░ ({
рд╕реНрддрд░: 'рдЬрд╛рдирдХрд╛рд░реА',
рдкреНрд░рд╛рд░реВрдк: рдХрд╕реНрдЯрдордлреЙрд░реНрдореЗрдЯ,
рдкрд░рд┐рд╡рд╣рди: [
рдиреНрдпреВ рд╡рд┐рдВрд╕реНрдЯрди.рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯреНрд╕.рдлрд╛рдЗрд▓ ({рдлрд╝рд╛рдЗрд▓ рдирд╛рдо: 'рд▓реЙрдЧреНрд╕.рд▓реЙрдЧ'})
]
});
рдореЙрдбреНрдпреВрд▓.рдПрдХреНрд╕рдкреЛрд░реНрдЯреНрд╕ = рд▓рдХрдбрд╝рд╣рд╛рд░рд╛; `

рдФрд░ рд▓реЙрдЧ рдХреЗ рд▓рд┐рдП:

logger.log({ time: true, level: 'info', message: 'message for logging' });

рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдпрд╣ рдорджрджрдЧрд╛рд░ рд╣реЛрдЧрд╛ред

рдЖрдк рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдХреЛ рдкреНрд░рд╛рд░реВрдк рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

winston.createLogger({
    level: ...
    format: winston.format.combine(
        winston.format.label({ label: '[my-label]' }),
        winston.format.timestamp({
            format: 'YYYY-MM-DD HH:mm:ss'
        }),
        winston.format.simple()
    ),
    transports: ...
});
winston.createLogger({
    level: ...
    format: winston.format.combine(
        winston.format.label({ label: '[my-label]' }),
        winston.format.timestamp({
            format: 'YYYY-MM-DD HH:mm:ss'
        }),
        winston.format.simple()
    ),
    transports: ...
});

рдпрд╣ рдбреЙрдХреНрд╕ рдкрд░ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред @felipemullen рдзрдиреНрдпрд╡рд╛рдж!

@felipemullen рдЙрд╕ рдирдореВрдирд╛ рдХреЛ рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред @ricardoaat рд╕реЗ рд╕рд╣рдордд рдпрд╣ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реЛрдВ рдореЗрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЗрд╕рд▓рд┐рдП ... рдЕрдм рдпрд╣ рд╣реИ: рдЙрджрд╛рд╣рд░рдг/рдХрд╕реНрдЯрдо-рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк.рдЬреЗрдПрд╕

@youngkylejan рдУрд╣ рдУрд╣ ..... рдпрд╣ рдЕрдЪреНрдЫреА рдорджрдж рд╣реИ ...
рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ...рд▓реЙрдЧ рдХреЗ рдЕрдВрдд рдореЗрдВ {} рдХреНрдпрд╛ рд╣реИ?

[2018-05-14 04:39:52] [рд╕реВрдЪрдирд╛] рдПрдкреАрдЖрдИ рд▓реЛрдХрд▓рд╣реЛрд╕реНрдЯ рдкрд░ рдЪрд▓ рд░рд╣рд╛ рд╣реИ: 3000 {}

рдореИрдВ рд╡рд┐рдВрд╕реНрдЯрди рдХреЗ рд▓рд┐рдП рдирдпрд╛ рд╣реВрдВ рдФрд░ рдХрд╣рдирд╛ рд╣реЛрдЧрд╛, рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░рдирд╛ рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ рд░реВрдк рд╕реЗ рдХрдард┐рди рд╣реИ :(

рдХрд┐рд╕реА рддрд░рд╣, рдореИрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд╕рд░рд▓ рд╕рдорд╛рдзрд╛рди рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рд╣реБрдЖ:

winston.createLogger({
    level: ...
    format: winston.format.printf(info => `${new Date().toISOString()} ${info.message}`),
    transports: ...
});

@hosseinGanjyar
рдкрд░рд┐рд╡рд░реНрддрди
info[MESSAGE] = info.message + ' ' + JSON.stringify(...);
рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╕
info[MESSAGE] = info.message;

рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛ред

рд╕реЗрдЯ рдЕрдк:

  • JSON рд▓реЙрдЧ
  • рдореБрд╣рд░
  • рд▓реЙрдЧ рд░реЛрдЯреЗрд╢рди
  • рдлрд╝рд╛рдЗрд▓ рдФрд░ рдХрдВрд╕реЛрд▓ рд▓реЙрдЧрд┐рдВрдЧ
import winston from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';
import fs from 'fs';
import path from 'path';

const LOG_DIR = path.normalize(`${process.cwd()}/logs`);

if (!fs.existsSync(LOG_DIR)) {
  fs.mkdirSync(LOG_DIR);
}

const logger = winston.createLogger({
  exitOnError: false,
  silent: process.env.SUPPRESS_LOGS,
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.combine(
    winston.format.timestamp({
      format: 'YYYY-MM-DD HH:mm:ss',
    }),
    winston.format.json(),
  ),
  transports: [
    new winston.transports.Console(),
    new DailyRotateFile({
      dirname: LOG_DIR,
      filename: '%DATE%.log',
      datePattern: 'YYYY-MM-DD-HH',
      zippedArchive: false,
      maxSize: '1m',
      maxFiles: '14d',
    }),
  ],
});

export default logger;

рдпрд╣ рд╕рдм рд╡рд┐рдВрд╕реНрдЯрди 3.0.0 рдФрд░ @types/winston 2.3.9 . рдХреЗ рд▓рд┐рдП рд╣реИ

const consoleFormat = winston.format.printf(info => {
    const d = new Date();
    const timestamp = d.toLocaleTimeString();
    return `${timestamp} ${info.level}: ${info.message}`;

рдпрд╣ рдПрдХ рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рджреЗрддрд╛ рд╣реИ рдЬреЛ рд╡рд░реНрддрдорд╛рди рдЯрд╛рдЗрдордЬрд╝реЛрди рдореЗрдВ рдмрд╕ рд╕рдордп рд╣реИред
рдлрд╝рд╛рдЗрд▓рдлреЙрд░реНрдореЗрдЯ рдХреЗ рд▓рд┐рдП рдореИрдВ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ

const timestamp = `${d.toISOString()} (${d.toLocalTimeString()})`;

рдлрд┐рд░

const logger = winston.createLogger({
    level: "debug",
    format: fileFormat,
    transports: [ new winston.transports.File({ filename: "yourname.log", level: "debug"}) ]
});

рд╢рд╛рдпрдж рджреЛ рдмрд╛рд░ рд╕реНрддрд░ рдХреА рдЬрд░реВрд░рдд рдирд╣реАрдВ рд╣реИред рд▓реЗрдХрд┐рди рдореИрдВ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред

рдЖрдк рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдХреЛ рдкреНрд░рд╛рд░реВрдк рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

winston.createLogger({
    level: ...
    format: winston.format.combine(
        winston.format.label({ label: '[my-label]' }),
        winston.format.timestamp({
            format: 'YYYY-MM-DD HH:mm:ss'
        }),
        winston.format.simple()
    ),
    transports: ...
});

рдЬреАрд╡рди рд░рдХреНрд╖рдХред рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рдж!!!

рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬреЛ YYYY-MM-DD HH:mm:ss рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдкреНрд░рд╛рд░реВрдк рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣рд╛рдВ рд╣реИрдВ: рд╡рд┐рдВрд╕реНрдЯрди рд╣реБрдб рдХреЗ рдиреАрдЪреЗ рдлреЗрдЪрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ , рдЗрд╕рд▓рд┐рдП рдЖрдк рдлреЗрдЪрд╛ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рд╡реЗ рд╕рднреА рдЙрджрд╛рд╣рд░рдг рд▓реЙрдЧ рдореЗрдВ рдмрд╛рдХреА рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рд╣рдЯрд╛ рджреЗрддреЗ рд╣реИрдВред рдпрджрд┐ рдЖрдк format.simple() рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдФрд░ рд╢реБрд░реБрдЖрдд рдореЗрдВ рдХреЗрд╡рд▓ рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдЬреЛрдбрд╝реЗрдВ рдФрд░ рдмрд╛рдХреА рд╕реЗ рд╣рдЯрд╛ рджреЗрдВ, рддреЛ рдпрд╣ рдЖрдкрдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░ рд╕рдХрддрд╛ рд╣реИ:

const simpleFormat = format.simple()
const MESSAGE = Symbol.for('message')
const simpleTimestamp = format(info => {
  const { timestamp, ...rest } = info
  const simpled = simpleFormat.transform(rest)
  if (typeof simpled !== 'boolean') {
    // @ts-ignore
    simpled[MESSAGE] = `${timestamp} ${simpled[MESSAGE]}`
  }
  return simpled
})

logger.add(new transports.Console({
  format: format.combine(
      format.timestamp(),
      format.colorize(),
      simpleTimestamp(),
  ),
}))
рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

jlank picture jlank  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

exortech picture exortech  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

Buzut picture Buzut  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

Nepoxx picture Nepoxx  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

greenhat616 picture greenhat616  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ