Winston: рд▓реЙрдЧрд┐рдВрдЧ рд╡рд┐рдзрд┐рдпрд╛рдВ рдЕрдм рдХреЙрд▓рдмреИрдХ рдирд╣реАрдВ рд▓реЗрддреА рд╣реИрдВ, рдХреБрдЫ рд╡рд╛рддрд╛рд╡рд░рдгреЛрдВ рдореЗрдВ рд╡рд┐рд╢реНрд╡рд╕рдиреАрдп рд░реВрдк рд╕реЗ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреА рд╣реИрдВ (рдПрдбрдмреНрд▓реНрдпреВрдПрд╕ рд▓реИрдореНрдмреНрдбрд╛)

рдХреЛ рдирд┐рд░реНрдорд┐рдд 29 рдорд╛рд░реНрдЪ 2018  ┬╖  44рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: winstonjs/winston

рд╡рд┐рдВрд╕реНрдЯрди 3 рдореЗрдВ, рд▓реЙрдЧрд┐рдВрдЧ рдлрд╝рдВрдХреНрд╢рди рдЕрдм рдХреЙрд▓рдмреИрдХ рдирд╣реАрдВ рд▓реЗрддреЗ рд╣реИрдВред рдкрд╣рд▓реЗ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд▓реЙрдЧрд┐рдВрдЧ рдкреВрд░реНрдг рд╣реЛрдиреЗ рддрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рдерд╛:

logger.info('some message', { foo: 42 }, callback);  // Winston 2.x

рд╡рд┐рдВрд╕реНрдЯрди 3 рдЖрдкрдХреЛ рдЕрдкрдиреЗ рдкрд░рд┐рд╡рд╣рди рдкрд░ logged рдШрдЯрдирд╛ рдХреЛ рд╕реБрдирдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдореБрдЭреЗ рдпрд╣ рдмрддрд╛рдиреЗ рдХрд╛ рдХреЛрдИ рдЖрд╕рд╛рди рддрд░реАрдХрд╛ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИ рдХрд┐ _рдпрд╣ рд╕рдВрджреЗрд╢ рдЬрд┐рд╕реЗ рдореИрдВ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рд▓реЙрдЧрд┐рдВрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ_ рдкреВрд░рд╛ рд╣реЛ рдЧрдпрд╛ рд╣реИред рдЪреВрдБрдХрд┐ рд╕рдм рдХреБрдЫ async рд╣реИ рдЕрдЧрд▓рд╛ logged рдИрд╡реЗрдВрдЯ рдЬреЛ рдЖрдкрдХреЗ рд╕рдВрджреЗрд╢ рд▓рд┐рдЦрдиреЗ рдХреЗ рдмрд╛рдж рд╣реЛрддрд╛ рд╣реИ, рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рдЕрднреА рд▓реЙрдЧ рдХрд┐рдП рдЧрдП рд╕рдВрджреЗрд╢ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рди рд╣реЛред рдФрд░ рдпрд╣ рдФрд░ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд╣реИ рдпрджрд┐ рдЖрдк рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯреЛрдВ рдкрд░ рдШрдЯрдирд╛ рдХреЛ рд╕реБрди рд░рд╣реЗ рд╣реИрдВред

рдпрд╣ рд╡рд┐рдВрд╕реНрдЯрди рдХреЛ рдХреБрдЫ рд╡рд╛рддрд╛рд╡рд░рдгреЛрдВ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдмрдирд╛рддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, AWS рд▓реИрдореНрдмреНрдбрд╛ рдореЗрдВ рд╣рдо callbackWaitsForEmptyEventLoop рдкреИрд░рд╛рдореАрдЯрд░ рдХреЛ false ( рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг ) рдкрд░ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред (рд╕рд┐рдбреЗрдиреЛрдЯ: рдЖрдк рдРрд╕рд╛ рддрдм рдХрд░рддреЗ рд╣реИрдВ рдЬрдм рдЖрдкрдХреЗ рдкрд╛рд╕ рдбреЗрдЯрд╛рдмреЗрд╕ рдХрдиреЗрдХреНрд╢рди рдпрд╛ рдРрд╕рд╛ рдХреБрдЫ рд╣реИ рдЬреЛ unref рдПрдб рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЕрдиреНрдпрдерд╛ рд▓реИрдореНрдмреНрдбрд╛ рдЖрдкрдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдХрднреА рднреА рдлреНрд░реАрдЬ рдирд╣реАрдВ рдХрд░реЗрдЧрд╛)ред рдпрджрд┐ false рд╕реЗрдЯ рд╣реИ, рддреЛ рдЬреИрд╕реЗ рд╣реА рдЖрдк рдХреЙрд▓рд░ рдХреЛ рдкрд░рд┐рдгрд╛рдо рд▓реМрдЯрд╛рддреЗ рд╣реИрдВ, рд▓реИрдореНрдмреНрдбрд╛ рдЖрдкрдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдлреНрд░реАрдЬ рдХрд░ рджреЗрддрд╛ рд╣реИ рдФрд░ рдЖрдкрдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рд╕рдорд╛рдкреНрдд рднреА рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдпрджрд┐ рдЖрдкрдХреЗ рд▓реЙрдЧрд┐рдВрдЧ рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ рдиреЗ рдЙрд╕ рд╕рдордп рддрдХ рд▓рд┐рдЦрдирд╛ рд╕рдорд╛рдкреНрдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ, рддреЛ рдЖрдк рдпрд╛ рддреЛ рд▓реЙрдЧ рдЦреЛ рджреЗрддреЗ рд╣реИрдВ рдпрд╛ (рдмрджрддрд░) рд▓реЙрдЧ рдмрд╛рдж рдореЗрдВ рд▓рд┐рдЦреЗ рдЬрд╛рддреЗ рд╣реИрдВ рдЬрдм рд▓реИрдореНрдмреНрдбрд╛ рдЖрдкрдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдЕрдирдлреНрд░реАрдЬ рдХрд░рддрд╛ рд╣реИред

рдЯреАрдПрд▓; рдбреАрдЖрд░: рд╣рдорд╛рд░реА рд▓реИрдореНрдмреНрдбрд╛ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рд╕реЗ рдХреЙрд▓рд░ рдХреЛ рдкрд░рд┐рдгрд╛рдо рд▓реМрдЯрд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╡рд┐рдВрд╕реНрдЯрди рдкрд░ (рдпрд╛ рдХреЙрд▓рдмреИрдХ рд╕рдордХрдХреНрд╖) рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдЧреА, рдпрд╣ рдЧрд╛рд░рдВрдЯреА рджреЗрддреЗ рд╣реБрдП рдХрд┐ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдЬрдордиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд▓реЙрдЧрд┐рдВрдЧ рдХреА рдЬрд╛рддреА рд╣реИред

рд▓реЙрдЧрд┐рдВрдЧ рдкреВрд░реНрдг рд╣реЛрдиреЗ рдкрд░ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрдпрд╛ рдХреЛрдИ рдФрд░ рддрд░реАрдХрд╛ рд╣реИ?

help wanted important investigate

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

рдореБрдЭреЗ рдЗрд╕ рдереНрд░реЗрдб рдкрд░ рдЕрд▓рд░реНрдЯ рдорд┐рд▓рддреЗ рд░рд╣рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рд╕рд╛рдЭрд╛ рдХрд░реВрдВрдЧрд╛ рдХрд┐ рдореБрдЭреЗ рдХреНрдпреЛрдВ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЕрднреА рднреА рдмрд╣реБрдд рд╕реЗ рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИред рдкреГрд╖реНрдарднреВрдорд┐: рд╣рдорд╛рд░рд╛ рдЙрдкрдпреЛрдЧ-рдорд╛рдорд▓рд╛ (рдФрд░ рдЬрд┐рд╕ рд╕рдВрджрд░реНрдн рдореЗрдВ рдпрд╣ рдореБрджреНрджрд╛ рдЦреЛрд▓рд╛ рдЧрдпрд╛ рдерд╛) рдПрдбрдмреНрд▓реНрдпреВрдПрд╕ рд▓реИрдореНрдмреНрдбрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдпрд╣рд╛рдВ рдЬрд┐рд╕ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рд╡рд╣ рдХреЗрд╡рд▓ рд╡рд╣рд╛рдВ рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИред

рд▓реИрдореНрдмреНрдбрд╛ рд▓реИрдореНрдмреНрдбрд╛ рдПрдХреНрдЬрд╝реАрдХреНрдпреВрд╢рди рдХреЙрдиреНрдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рддрд╣рдд рдиреЛрдб рдЪрд▓рд╛рддрд╛ рд╣реИред рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдЬрд╛ рд░рд╣реА рд╣реИ:

рд▓реИрдореНрдмреНрдбрд╛ рдлрд╝рдВрдХреНрд╢рди рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдПрдбрдмреНрд▓реНрдпреВрдПрд╕ рд▓реИрдореНрдмреНрдбрд╛ рдПрдХ рдФрд░ рд▓реИрдореНрдмреНрдбрд╛ рдлрд╝рдВрдХреНрд╢рди рдЖрдордВрддреНрд░рдг рдХреА рдкреНрд░рддреНрдпрд╛рд╢рд╛ рдореЗрдВ рдХреБрдЫ рд╕рдордп рдХреЗ рд▓рд┐рдП рдирд┐рд╖реНрдкрд╛рджрди рд╕рдВрджрд░реНрдн рдмрдирд╛рдП рд░рдЦрддрд╛ рд╣реИред

рддрдерд╛

  • рдЖрдкрдХреЗ рд▓реИрдореНрдмреНрдбрд╛ рдлрд╝рдВрдХреНрд╢рди рдХреЛрдб рдореЗрдВ рдХреЛрдИ рднреА рдШреЛрд╖рдгрд╛ (рд╣реИрдВрдбрд▓рд░ рдХреЛрдб рдХреЗ рдмрд╛рд╣рд░, рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдореЙрдбрд▓ рджреЗрдЦреЗрдВ) рдЖрд░рдВрднрд┐рдХ рдмрдиреА рд░рд╣рддреА рд╣реИ, рдЬрдм рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рдЕрддрд┐рд░рд┐рдХреНрдд рдЕрдиреБрдХреВрд▓рди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред

рдпрд╛рдиреА рд▓реЙрдиреНрдЪ рдХреЛ рдЧрддрд┐ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП, рд▓реИрдореНрдмреНрдбрд╛ "рдлреНрд░реАрдЬ" рдФрд░ "рдереЙ" рд╡рд╛рддрд╛рд╡рд░рдг рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдмрдВрдж рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп "рдлреНрд░реАрдЬ" рдХрд░рддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд▓реИрдореНрдмреНрдбрд╛ рдиреЛрдб рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдпрд╣ рдЖрдкрдХреЗ рд╣реИрдВрдбрд▓рд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИред рдХрд┐рд╕реА рднреА рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рд╣реИрдВрдбрд▓рд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдмрд╛рд╣рд░ рдЪрд▓рд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╢реЗрд╖ рд▓реИрдореНрдмреНрдбрд╛ рдирд┐рд╖реНрдкрд╛рджрди рд╕рдВрджрд░реНрдн рдХреЗ рд╕рд╛рде рдЬрдореЗ рд╣реБрдП рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд╣реИрдВ рдпрджрд┐ рдЙрдирдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдирд╣реАрдВ рдХреА рдЬрд╛рддреА рд╣реИред

рдЕрдм рдЖрдЗрдП рд╡рд┐рдВрд╕реНрдЯрди рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХреЗ рд▓рд┐рдП рд╕реБрдЭрд╛рдП рдЧрдП рд╕рдорд╛рдзрд╛рди рдХреЛ рджреЗрдЦреЗрдВ - UPGRADE-3.0.md рд╕реЗ рдЕрдиреБрдХреВрд▓рд┐рдд, рдпрд╣ рдорд╛рдирддреЗ рд╣реБрдП рдХрд┐ рд╣рдо рд▓реИрдореНрдмреНрдбрд╛ рдореЗрдВ рдЪрд▓ рд░рд╣реЗ рд╣реИрдВ:

async function lambdaHandler(event, context) {
  const logger = winston.createLogger({
    transports: [
      new winston.transports.Console(),
      new CustomAsyncTransport(),
    ],
  });
  logger.log('info', 'some message');
  logger.on('finish', () => process.exit());
  logger.end();
}

рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдПрдВ? logger рд╣реИрдВрдбрд▓рд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ logger.end() рдХреЛ рд╕рдХреНрд░рд┐рдп рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди logger.on('finish') рджреНрд╡рд╛рд░рд╛ рдлрд╝рд╛рдпрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдлрд╝рдВрдХреНрд╢рди рд╣реИрдВрдбрд▓рд░ рд╕рдВрджрд░реНрдн рдХреЗ рдмрд╛рд╣рд░ рдЪрд▓рддрд╛ рд╣реИред CustomAsyncTransport рд╕реЗ рдЬреБрдбрд╝реА рдХреЛрдИ рднреА рдПрд╕рд┐рдВрдХ рдкреНрд░рдХреНрд░рд┐рдпрд╛ finish рдШрдЯрдирд╛ рдХреЛ рдлрд╛рдпрд░рд┐рдВрдЧ рд╕реЗ рд░реЛрдХ рджреЗрдЧреА, рдЬрд┐рд╕рд╕реЗ рдпрд╣ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рдЙрд╕ рдШрдЯрдирд╛ рдХреЗ рд╢реБрд░реВ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдирд┐рд╖реНрдкрд╛рджрди рд╕рдВрджрд░реНрдн рдлреНрд░реАрдЬ рд╣реЛ рдЬрд╛рдПред

рдЗрд╕реЗ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, lambdaHandler рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдХреЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреА рдЪрд╛рд╣рд┐рдП:

async function lambdaHandler(event, context) {
  const logger = winston.createLogger({
    transports: [
      new winston.transports.Console(),
      new CustomAsyncTransport(),
    ],
  });
  const loggerFinished = new Promise(resolve => logger.on('finish', resolve));
  logger.log('info', 'some message');
  logger.end();
  await loggerFinished;
}

рдЪреВрдБрдХрд┐ lambdaHandler рддрдм рддрдХ рдмрд╛рд╣рд░ рдирд╣реАрдВ рдирд┐рдХрд▓рддрд╛ рдЬрдм рддрдХ logger finish рдИрд╡реЗрдВрдЯ рдХреЛ рд╕рдХреНрд░рд┐рдп рдирд╣реАрдВ рдХрд░ рджреЗрддрд╛, рд╣рдорд╛рд░реЗ CustomAsyncTransport рдХреЛ рд╣рдорд╛рд░реЗ рд▓реИрдореНрдмреНрдбрд╛ рд╣реИрдВрдбрд▓рд░ рд╕реЗ рдкрд╣рд▓реЗ рдмрдВрдж рдХрд░ рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЙрди рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рдлрд╝реНрд░реАрдЬрд╝ рд╣реЛрдиреЗ рд╕реЗ рдмрдЪрд╛рдирд╛ (рдпрд╣ рдорд╛рдирдХрд░ finish рдИрд╡реЗрдВрдЯ @indexzero рджреНрд╡рд╛рд░рд╛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ)ред

рдЗрд╕реЗ рдореЗрд░реЗ рджреНрд╡рд╛рд░рд╛ рдкрд╣рд▓реЗ рд╕рд╛рдЭрд╛ рдХрд┐рдП рдЧрдП рдХреЛрдб рдХреЗ рд╕рдорд╛рди рдХреБрдЫ рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:

async function waitForLogger(logger) {
  const loggerDone = new Promise(resolve => logger.on('finish', resolve));
  // alternatively, use end-of-stream https://www.npmjs.com/package/end-of-stream
  // although I haven't tested this
  // const loggerDone = new Promise(resolve => eos(logger, resolve));
  logger.end();
  return loggerDone;
}

async function lambdaHandler(event, context) {
  const logger = winston.createLogger({
    transports: [
      new winston.transports.Console(),
      new CustomAsyncTransport(),
    ],
  });
  logger.log('info', 'some message');
  await waitForLogger(logger);
}

рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдпрд╣ рдХреБрдЫ рд▓реЛрдЧреЛрдВ рдХреА рдорджрдж рдХрд░рддрд╛ рд╣реИред

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

рд╣рдо рдПрдХ рдЕрд▓рдЧ рд╕рдорд╛рдзрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВред

рдЗрд╕реЗ рдХреЛрдИ рдореБрджреНрджрд╛ рдирд╣реАрдВ рдмрдирд╛рддреЗ рд╣реИрдВред рдЗрд╕реЗ рд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред

рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: рдпрд╣ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛

=============
рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдпрд╣ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рддрд░реАрдХрд╛ рд╣реИ, рдФрд░ рди рд╣реА рдпрд╣ рд╕рднреА рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрднреА рддрдХ рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд░рдХреЗ рдЗрд╕реЗ рд╕рдВрднрд╛рд▓ рд░рд╣реЗ рд╣реИрдВ:

рдореИрдВрдиреЗ рдПрдХ wait-for-logger.js рдлрд╝рдВрдХреНрд╢рди рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдмрдирд╛рдпрд╛ рд╣реИ:

function waitForLogger(logger) {
  return new Promise((resolve) => {
    logger.on('close', resolve);
    logger.close();
  });
}

module.exports = waitForLogger;

рд╣рдорд╛рд░реЗ рд╣реИрдВрдбрд▓рд░ рдХреЗ рдЕрдВрдд рдореЗрдВ, рд╣рдо рд▓реМрдЯрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдлрд╝рдВрдХреНрд╢рди рдЖрдЙрдЯрдкреБрдЯ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддреЗ рд╣реИрдВ:

const logger = require('./logger');
const waitForLogger = require('./wait-for-logger');

async function handler(event, context) {
  // your functionality
  logger.log('info', 'This should make it through all the transports');
  // ...

  await waitForLogger(logger);
}

рд╣рдо nodejs8.10 рд▓реИрдореНрдмреНрдбрд╛ рд░рдирдЯрд╛рдЗрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ - рдпрджрд┐ рдЖрдк рдкреБрд░рд╛рдиреЗ рд░рдирдЯрд╛рдЗрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рдЖрдк рд╢рд╛рдпрдж рдирд┐рдореНрди рдХреА рддрд░рд╣ рдХреБрдЫ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

function handler(event, context, callback) {
  // your functionality
  logger.log('info', 'This should make it through all the transports');
  // ...

   waitForLogger(logger).then(() => callback(null));
}

рдзрдиреНрдпрд╡рд╛рдж @dpraulред рд╣рдорд╛рд░рд╛ рдПрдХ рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ рдмрд╛рд╣рд░реА рд╕реЗрд╡рд╛ рдореЗрдВ рд▓реЙрдЧ рдЗрди рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдЗрд╕рдореЗрдВ рдХреБрдЫ рдЕрддрд┐рд░рд┐рдХреНрдд рдПрдордПрд╕ рд▓рдЧ рд╕рдХрддреЗ рд╣реИрдВред рдХреНрдпрд╛ logger.close() рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдЧрд╛?

@natesilva рдиреЗ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рдФрд░ рд╕реЛрдЪрд╛

  1. winston@3 рдореЗрдВ Logger рдФрд░ Transport рджреЛрдиреЛрдВ Node.js рд╕реНрдЯреНрд░реАрдо рд╣реИрдВ ред
  2. рд▓рд┐рдЦрдиреЗ рдпреЛрдЧреНрдп рд╕реНрдЯреНрд░реАрдо рдПрдХ .end рд╡рд┐рдзрд┐ рдФрд░ рдПрдХ 'finish' рдШрдЯрдирд╛ рдХреЛ рдЙрдЬрд╛рдЧрд░ рдХрд░рддреА рд╣реИрдВред

рдЗрд╕рд▓рд┐рдП рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ рдпрд╣ _рдЪрд╛рд╣рд┐рдП_ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдЕрднреА рддрдХ рдЗрд╕рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ:

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

process.on('exit', function () {
  console.log('Your process is exiting');
});

logger.on('finish', function () {
  console.log('Your logger is done logging');
});

logger.log('info', 'Hello, this is a raw logging event',   { 'foo': 'bar' });
logger.log('info', 'Hello, this is a raw logging event 2', { 'foo': 'bar' });

logger.end();

рд╕рддреНрдпрд╛рдкрд┐рдд:

{"foo":"bar","level":"info","message":"Hello, this is a raw logging event"}
{"foo":"bar","level":"info","message":"Hello, this is a raw logging event 2"}
Your logger is done logging
Your process is exiting

рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рдХреЗ рд░реВрдк рдореЗрдВ рдЗрд╕рдХреЗ рд╕рд╛рде рдПрдХ рдЙрджрд╛рд╣рд░рдг рдЬреЛрдбрд╝рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реВрдВред рдХреГрдкрдпрд╛ рдмреЗрдЭрд┐рдЭрдХ рдлрд┐рд░ рд╕реЗ рдЦреЛрд▓реЗрдВ рдЕрдЧрд░ рдпрд╣ рдЖрдкрдХреЗ рд▓рд┐рдП рд▓реИрдореНрдмреНрдбрд╛ рдореЗрдВ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред winston рдХреЗ рд▓рдХреНрд╖рд┐рдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЖрдзрд╛рд░ рдореЗрдВ рдлрдВрдХреНрд╢рди-рдП-рдП-рд╕рд░реНрд╡рд┐рд╕ рдкреНрд▓реЗрдЯрдлреЙрд░реНрдо 100% рд╣реИрдВ,

рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ @natesilva рд╕рдордп рд╣реИ рддреЛ рдЖрдк winston рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдВрдб-рдЯреВ-рдПрдВрдб AWS рд▓реИрдореНрдмреНрдбрд╛ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдпреЛрдЧрджрд╛рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ред

рд╣рдо рдмреЛрд▓рддреЗ рд╕рдордп рдЗрд╕рдХреА рд╕рдореАрдХреНрд╖рд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдФрд░ рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ рдХрд┐ рдореИрдВрдиреЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрдирдореЗрдВ рд╕реЗ рдХрд┐рд╕реА рднреА рддрд░реАрдХреЗ рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИред рдореИрдВ рд╢реАрдШреНрд░ рд╣реА рдПрдХ рдкреВрд░реНрдг рдкрд░реАрдХреНрд╖рдг-рдорд╛рдорд▓рд╛ рдпрд╣рд╛рдБ рд╕рд╛рдЭрд╛ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реВрдБрдЧрд╛ред

const winston = require('winston');

class CustomTransport extends winston.Transport {
  log({ message }, cb) {
    setTimeout(() => {
      console.log(`custom logger says: ${message}`);
      cb(null);
    }, 3000);
  }
}

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

logger.on('finish', () => {
  console.log('done!');
});
logger.log('info', 'here is some content');
logger.end();

рдЕрдкреЗрдХреНрд╖рд┐рдд рдЙрддреНрдкрд╛рджрди:

{"level":"info","message":"here is some content"}
custom logger says: here is some content
done!

рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЖрдЙрдЯрдкреБрдЯ:

{"level":"info","message":"here is some content"}
done!
custom logger says: here is some content

рд╕рднреА рдкрд░рд┐рд╡рд╣рди рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ finish рдШрдЯрдирд╛ рдлрд╛рдпрд░рд┐рдВрдЧ рд╣реЛ рд░рд╣реА рд╣реИред рдЕрдВрдд рдореЗрдВ .on('close', fn) рдФрд░ .close() рдИрд╡реЗрдВрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рд╡рд╣реА рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реЛрддрд╛ рд╣реИред

рдХреНрд╖рдорд╛ рдХрд░реЗрдВ, рдореИрдВрдиреЗ рдЕрдкрдиреА рдЯрд┐рдкреНрдкрдгреА рд╣рдЯрд╛ рджреАред рдЗрди рд╕реНрдЯреНрд░реАрдо рдЗрд╡реЗрдВрдЯ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдореЗрд░реА рд╕рдордЭ рд╕реАрдорд┐рдд рд╣реИ, рд▓реЗрдХрд┐рди @dpraul рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рдЕрдиреБрд╕рд╛рд░, рдореИрдВ рджреЗрдЦ рд╕рдХрддрд╛ рд╣реВрдБ рдХрд┐ finish рдЧрд▓рдд рд╕рдордп рдкрд░ рдХреИрд╕реЗ рд╕рдХреНрд░рд┐рдп рд╣реЛ рд╕рдХрддрд╛ рд╣реИред

рдореИрдВ end , finish , рдФрд░ close рдШрдЯрдирд╛рдУрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╣реА рдЙрджрд╛рд╣рд░рдг рд╕реЗ рдЧреБрдЬрд░рд╛ рд╣реВрдВ, рдФрд░ stream.Transform.close() рдФрд░ stream.Transform.end() рджреЛрдиреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ - рд╕рднреА рдХреЗ рдкрд░рд┐рдгрд╛рдо рд╕рдорд╛рди рд╣реЛрддреЗ рд╣реИрдВ, рдЬрд╣рд╛рдВ CustomerTransport рд╕реЗ рдкрд╣рд▓реЗ рдЯреНрд░рд┐рдЧрд░ рд╣реЛрдиреЗ рд╡рд╛рд▓реА рдШрдЯрдирд╛рдУрдВ рдиреЗ рдЗрд╕реЗ callback ред

Transports рдФрд░ Logger рдмреАрдЪ рдИрд╡реЗрдВрдЯ рдХреИрд╕реЗ рдкрд╛рд░рд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ, рдЗрд╕рдореЗрдВ рдХреБрдЫ рд╕рдорд╕реНрдпрд╛ рд╣реЛ рд╕рдХрддреА рд╣реИ?

рднрд▓реЗ рд╣реА, @natesilva рдпрд╛ @indexzero , рдЖрдк рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдлрд┐рд░ рд╕реЗ рдЦреЛрд▓рдирд╛ рдЪрд╛рд╣ рд╕рдХрддреЗ рд╣реИрдВред

@dpraul рдЬреЛ рдкреНрд░рд╢рдВрд╕рдиреАрдп рд▓рдЧрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВ рдпрд╣ рдирд╣реАрдВ рджреЗрдЦрддрд╛ рдХрд┐ рд╡рд╣ рдХрд╣рд╛рдБ рд╣реЛрдЧрд╛:

  1. Transport рдореЗрдВ winston-transport Node.js рдХреЗ Writeable рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП _write рдкрджреНрдзрддрд┐ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИред рдпрд╣ callback рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ
  2. Console рдореЗрдВ рдкрд░рд┐рд╡рд╣рди winston рдХреЙрд▓ process.{stderr,stdout}.write рдФрд░ рдЙрд╕рдХреЗ рдмрд╛рдж рдХрд╛ рдЖрд╣реНрд╡рд╛рди callback ред process.stdout рдФрд░ process.stderr рд▓рд┐рдП Afaik рд▓реЗрдЦрди рд╕рдордХрд╛рд▓рд┐рдХ рд╕рдВрдЪрд╛рд▓рди рд╣реИрдВ рдЗрд╕рд▓рд┐рдП рдкреАрда рдХреЗ рджрдмрд╛рд╡ рдХрд╛ рдХреЛрдИ рд╕рдВрднрд╛рд╡рд┐рдд рдЬреЛрдЦрд┐рдо рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред

рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдЗрд╕ рдкреНрд░рд╡рд╛рд╣ рдореЗрдВ рдХреБрдЫ рдЫреВрдЯ рд░рд╣рд╛ рд╣реИред рдХреБрдЫ Node.js рд▓реЛрдЧреЛрдВ рдХреЗ рд╕рд╛рде рдЪреИрдЯ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рдФрд░ рджреЗрдЦреЗрдВ рдХрд┐ рдореИрдВ рдХреНрдпрд╛ рдЦреЛрдж рд╕рдХрддрд╛ рд╣реВрдВред

рдореИрдВ рдЕрднреА рднреА рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рдХрд┐ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдХрд╛рд░рдг рдХреНрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдПрдХ рд╕рдорд╛рдзрд╛рди рдорд┐рд▓рд╛ рдЬреЛ рд╕рднреА рдкрд░рд┐рд╡рд╣рдиреЛрдВ рдХреЗ рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИ!

const winston = require('winston');

class CustomTransport extends winston.Transport {
  log({ message }, cb) {
    setTimeout(() => {
      console.log(`custom logger says: ${message}`);
      cb(null);
    }, 3000);
  }
}

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

async function waitForLogger(l) {
  const transportsFinished = l.transports.map(t => new Promise(resolve => t.on('finish', resolve)));
  l.end();
  return Promise.all(transportsFinished);
}

logger.log('info', 'here is some content');

waitForLogger(logger).then(() => console.log('all done!'));

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

{"level":"info","message":"here is some content"}
custom logger says: here is some content
all done!

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ logger.end() рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯреЛрдВ рдХреЗ рд▓рд┐рдП рдареАрдХ рд╕реЗ рдкреНрд░рдЪрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рднреА рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯреЛрдВ рдХреЛ рдирд┐рдХрд╛рд▓ рджреЗрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ finish рдШрдЯрдирд╛ рдХреЛ рд╕рдХреНрд░рд┐рдп рдХрд░рддрд╛ рд╣реИред рд╕рдорд╛рдзрд╛рди рдпрд╣ рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ Transport рдкрд░ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ finish рдИрд╡реЗрдВрдЯ рдХреЛ рд╕рдХреНрд░рд┐рдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВ рдФрд░ Logger рдкрд░ рдмрд┐рд▓реНрдХреБрд▓ рднреА рднрд░реЛрд╕рд╛ рди рдХрд░реЗрдВред

@dpraul рдХреА рдЬрд╛рдВрдЪ рдЬрд╛рд░реА рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред logger рд╕рднреА рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯреЛрдВ рдХреЗ рд▓рд┐рдП рдкрд╛рдЗрдк рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрдм рд▓реЙрдЧрд░ рдмрдВрдж рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рдпрд╣ рдореЗрд░реА рд╕рдордЭ рдереА рдХрд┐ рдпрд╣ рддрдм рддрдХ рдЦрддреНрдо рдирд╣реАрдВ рд╣реЛрдЧрд╛ рдЬрдм рддрдХ рдХрд┐ рдЙрд╕рдХреЗ рд╕рднреА рдкрд╛рдЗрдк рд▓рдХреНрд╖реНрдп рди рд╣реЛрдВ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЧрд▓рдд рдорд╛рдирд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдХреБрдЫ рд▓реЛрдЧреЛрдВ рд╕реЗ рд╕рддреНрдпрд╛рдкрди рдХрд░рд╛рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред

@mcollina @davidmarkclements & @mafintosh рд╕реЗ рдХреБрдЫ рдЗрдирдкреБрдЯ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдореИрдВрдиреЗ рд╕реАрдЦрд╛ рдХрд┐ pipe рд╢рдмреНрджрд╛рд░реНрде рдХреА рдореЗрд░реА рд╕рдордЭ рддреНрд░реБрдЯрд┐рдкреВрд░реНрдг рдереАред

  • 'error' рдФрд░ 'finish' рдИрд╡реЗрдВрдЯ рд╡рд╛рдкрд╕ рдкрд╛рдЗрдк рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреНрд░рдЪрд╛рд░рд┐рдд рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВред
  • 'error' рдИрд╡реЗрдВрдЯ рдХреЗ рдХрд╛рд░рдг рдкрд╛рдЗрдк рдирд╣реАрдВ рдЦреБрд▓рддреЗ рд╣реИрдВред

рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ рдХрд┐ рдпрд╛ рддреЛ рдЗрди рдШрдЯрдирд╛рдУрдВ рдХрд╛ рдкреНрд░рдЪрд╛рд░ рдХреИрд╕реЗ рдХрд░реЗрдВ рдпрд╛ Logger рдкрд░ рдПрдХ рд╕реНрдкрд╖реНрдЯ рд╡рд┐рдзрд┐ рдХрд╛ рдЦреБрд▓рд╛рд╕рд╛ рдХрд░реЗрдВ рдЬреЛ рдЙрд╕ рддрдХрдиреАрдХ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЖрдк рдЕрднреА рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ @dpraul (рд╢рд╛рдпрдж рдПрдВрдб-рдСрдл-рд╕реНрдЯреНрд░реАрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░)ред

@natesilva рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рддрдм рддрдХ рдЦреБрд▓рд╛ рдЫреЛрдбрд╝рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реИ рдЬрдм рддрдХ рдХрд┐ рд╕реНрдкрд╖реНрдЯ рд╕реБрдзрд╛рд░ рди рд╣реЛ, рд▓реЗрдХрд┐рди рдЗрд╕ рдмреАрдЪ рдЖрдк рдЙрдкрд░реЛрдХреНрдд рддрдХрдиреАрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП:

  • рд╕рднреА рдкрд░рд┐рд╡рд╣рдиреЛрдВ рдкрд░ 'finish' рдИрд╡реЗрдВрдЯ рд╕реБрдиреЗрдВ
  • logger.end() рдХреЙрд▓ рдХрд░реЗрдВ
  • рдЬрдм рд╕рднреА 'finish' рдИрд╡реЗрдВрдЯ рдЙрддреНрд╕рд░реНрдЬрд┐рдд рд╣реЛ рдЧрдП рд╣реИрдВ рддреЛ рдЖрдк рд▓реЙрдЧрд┐рдВрдЧ рдХрд░ рдЪреБрдХреЗ рд╣реИрдВред

рдорд╣рддреНрд╡рдкреВрд░реНрдг рдореЙрдбреНрдпреВрд▓ рдЬреЛ рдЙрдкрдпреЛрдЧреА рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ: рдкрдВрдк рдФрд░ рдПрдВрдб-рдСрдл-рд╕реНрдЯреНрд░реАрдоред

@mcollina рд╕реИрджреНрдзрд╛рдВрддрд┐рдХ рд░реВрдк рд╕реЗ рдПрдХ Node.js рд╕реНрдЯреНрд░реАрдо рдкрд░рд┐рдкреНрд░реЗрдХреНрд╖реНрдп рд╕реЗ рд╣рдореЗрдВ _final рдХреЛ рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдкрд░ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рддрд╛рдХрд┐ finish рдИрд╡реЗрдВрдЯ рдХреЛ рдмрд╛рдж рдореЗрдВ рдЙрддреНрд╕рд░реНрдЬрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ, рд╣реИ рдирд╛?

@indexzero рд╣рд╛рдБ, рдпрд╣ рд╕рд╣реА рд╣реЛрдЧрд╛ред

рдХреГрдкрдпрд╛ рдореБрдЭреЗ рдмрддрд╛рдПрдВ, рд╡рд┐рдВрд╕реНрдЯрди @ 3 рдореЗрдВ рдореИрдВ рд╕рдВрд╕реНрдХрд░рдг 2 рдХреА рддрд░рд╣ рдХреЙрд▓рдмреИрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛?
(рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдореЗрдВ рдХреЛрдИ рдЬрд╡рд╛рдм рдирд╣реАрдВ рд╣реИ)

// ... some check the connection to db ... and if fail:
logger.error('message',  function() {
  process.exit(1);
});

рдФрд░ рдпрджрд┐ рдХреЙрд▓рдмреИрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдореЗрд░рд╛ рдРрдк рд╕рдВрджреЗрд╢ рд▓реЙрдЧ рд╣реЛрдиреЗ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рддреЗрдЬрд╝реА рд╕реЗ рдмрдВрдж рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ =(

@TuxGit FYI рдХрд░реЗрдВ рдЗрд╕реЗ UPGRADE-3.0 рдореЗрдВ рдкреНрд░рд▓реЗрдЦрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ (рджреЗрдЦреЗрдВ: рдкреАрдЖрд░ рдХреЛрдб )

@natesilva @dpraul PR рдЕрдм рдЗрд╕реЗ рд╕рдВрдмреЛрдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЦреБрд▓рд╛ рд╣реИ: https://github.com/winstonjs/winston/pull/1346

рдореБрдЭреЗ рд╡рд┐рд╢реНрд╡рд╛рд╕ рд╣реИ рдХрд┐ рдпрд╣ рдЕрднреА рднреА рдЯреВрдЯрд╛ рд╣реБрдЖ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐ finish рдШрдЯрдирд╛ рдЕрдм рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдкреНрд░рдЪрд╛рд░рд┐рдд рд╣реЛ рд░рд╣реА рд╣реИ рдФрд░ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХреА рдЬрд╛ рд░рд╣реА рд╣реИ, рдХрдо рд╕реЗ рдХрдо File рдкрд░рд┐рд╡рд╣рди рдореЗрдВ, рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд WriteableStream рдиреЗ рдЕрднреА рддрдХ рдбрд┐рд╕реНрдХ рдкрд░ рдЕрдкрдиреЗ рд▓реЗрдЦрди рдХреЛ рдлреНрд▓рд╢ рдХрд░рдирд╛ рд╕рдорд╛рдкреНрдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИред

рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛтАЛтАЛрд╣реИ рдХрд┐ PassthroughStream рдХреЗ рдмрдЬрд╛рдп рдЗрд╕рдХреА finish рдШрдЯрдирд╛ рдЙрддреНрд╕рд░реНрдЬрд┐рдд рд╣реЛ рд░рд╣реА рд╣реИ, рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ рдпрд╣ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдЗрдВрддрдЬрд╛рд░ рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИред

рдХреЛрдИ рдмрд╛рдд рдирд╣реАрдВ - PassthruStream рдареАрдХ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ finish рдШрдЯрдирд╛ рдХреЛ рд╕реБрдирдХрд░ рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИред

рдореИрдВ рдкреБрд╖реНрдЯрд┐ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЕрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддрд╛рд░реЛрдВ end-of-stream рдФрд░ рдЙрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рдХреЛ рд╕реБрдирдиреЗ рдХреЗ рд▓рд┐рдП transport._stream рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред

рдЗрд╕ рдкрд░ рдХрд┐рд╕реА рднреА рдЕрджреНрдпрддрди ? рдореИрдВ рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реВрдБ logger.on('finish', () => process.exit(0)) рд▓реЗрдХрд┐рди рдпрд╣ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдд рдирд╣реАрдВ рд╣реЛрддрд╛ред рдпрд╣ рдЯрд╛рдЗрдордЖрдЙрдЯ рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рд╣реА рдореМрдЬреВрдж рд╣реИ

рдХрдВрд╕реЛрд▓ рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рдореБрдЭреЗ рдПрдХ рд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реЛ рд░рд╣реА рд╣реИ (рдлрд╝рд╛рдЗрд▓ рдХреЛ рдИрдорд╛рдирджрд╛рд░ рд╣реЛрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдирд╣реАрдВ рдХреА рд╣реИ)ред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ Logger stream-readable рдореЙрдбреНрдпреВрд▓ рд╕реЗ stream.Transform Logger рдмрдврд╝рд╛рддрд╛ рд╣реИ рдФрд░ _final рд╡рд┐рдзрд┐ рдХреЛ _stream_transform рдореЗрдВ рдХреЙрд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ, рдХреЗрд╡рд▓ _stream_writable ред рдореИрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЗрд╕ рдкрд░ рдзреНрдпрд╛рди рдирд╣реАрдВ рджреЗрдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдореЗрд░рд╛ рдкрд╣рд▓реА рдмрд╛рд░ рд╣реИ рдХрд┐ рдореИрдВ рдЗрдирдореЗрдВ рд╕реЗ рдХрд┐рд╕реА рднреА рдореЙрдбреНрдпреВрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдЕрдЧрд░ рдореИрдВрдиреЗ рдХреБрдЫ рдЧрд▓рдд рд╕рдордЭрд╛ рддреЛ рдореИрдВ рдХреНрд╖рдорд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред

../lib/winston $ grep -n _final *.js
logger.js:249:  _final(callback) {

.../readable-stream/lib $ grep -n _final *.js
_stream_writable.js:130:  // if _final has been called
_stream_writable.js:276:    if (typeof options.final === 'function') this._final = options.final;
_stream_writable.js:601:  stream._final(function (err) {
_stream_writable.js:613:    if (typeof stream._final === 'function') {

рдПрдХ рдХрд╕реНрдЯрдо рдкрд░рд┐рд╡рд╣рди рдЬреЛрдбрд╝реЗрдВ рдФрд░ рд▓реЙрдЧ рдХреЗ рд╕реНрддрд░ рдХреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВ рдФрд░ рд╕рдВрдмрдВрдзрд┐рдд рд╕реНрддрд░ рдореЗрдВ рдХрд╕реНрдЯрдо рддрд░реНрдХ рдЬреЛрдбрд╝реЗрдВред рдпрд╣ рдХреЙрд▓рдмреИрдХ рдореЗрдВ рдХреБрдЫ рдХрд░рдиреЗ рдХреЗ рдмрд░рд╛рдмрд░ рдирд╣реАрдВ рд╣реИред рд▓реЗрдХрд┐рди рд╣рд╛рд▓рд╛рдВрдХрд┐ рдЕрдЧрд░ рдЖрдк рдПрдпрд░рдмреНрд░реЗрдХ рдЬреИрд╕реЗ рдХрд┐рд╕реА рдЕрдиреНрдп рдЧрдВрддрд╡реНрдп рдкрд░ рдХреБрдЫ рд▓реЙрдЧ рдХреЛ рдЯреНрд╡рд┐рдХ рдФрд░ рднреЗрдЬрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдЗрд╕рд╕реЗ рдорджрдж рдорд┐рд▓реЗрдЧреАред

const Transport = require('winston-transport');

class YourCustomTransport extends Transport {
  log(info, callback) {
    setImmediate(() => {
      this.emit('logged', info);
    });
    if (info.level === 'error') {
      console.log('DO WHATEVER YOU WANT HERE.....', info.message);
    }
    callback();
  }
}

module.exports = YourCustomTransport;

рдФрд░ рдЬрд┐рд╕ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЖрдк winton.createLogger(...) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдкрдирд╛ рдХрд╕реНрдЯрдо рд╡рд┐рдВрд╕реНрдЯрди рд▓рдХрдбрд╝рд╣рд╛рд░рд╛ рдмрдирд╛рддреЗ рд╣реИрдВ, рдЙрд╕рдореЗрдВ рдЕрдкрдиреЗ CustomTransport рдХреЛ "transports" рд╡рд┐рдХрд▓реНрдк рдХреА рд╕рд░рдгреА рдореЗрдВ config рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВред

transports: [
        new winston.transports.Console({ silent: isTestEnvironment }),
        new CustomTransport(),
      ],

рд╣реИрд▓реЛ, рдореИрдВрдиреЗ рдиреАрдЪреЗ рдЕрдиреБрд╢рдВрд╕рд┐рдд рдХреЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдмрдВрдж рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдлрд╛рдЗрд▓реЛрдВ рдХреЛ рд▓рд┐рдЦрдирд╛ рд╕рдорд╛рдкреНрдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдореБрдЭреЗ рдХрдВрд╕реЛрд▓ рдХреЛ рд▓рд┐рдЦреА рдЧрдИ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рджрд┐рдЦрд╛рдИ рджреЗрддреА рд╣реИрдВред рдЕрдЧрд░ рдореИрдВ process.exit рдХреЛ рдХреЙрд▓ рдирд╣реАрдВ рдХрд░рддрд╛, рддреЛ рдлрд╝рд╛рдЗрд▓реЗрдВ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд▓рд┐рдЦрддреА рд╣реИрдВред рдореИрдВ рджреЗрдЦ рд░рд╣рд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ рдореБрджреНрджрд╛ рдмрдВрдж рд╣реЛ рдЧрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдХрд╛ рд╕рдорд╛рдзрд╛рди рд╣реЛ рдЧрдпрд╛ рд╣реИ?

logger.log ('рдЬрд╛рдирдХрд╛рд░реА', 'рдХреБрдЫ рд╕рдВрджреЗрд╢');
logger.on('finish', () => process.exit ());
рд▓рдХрдбрд╝рд╣рд╛рд░рд╛.рдЕрдВрдд ();

рдХреНрдпрд╛ рдХрд┐рд╕реА рдХреЗ рдкрд╛рд╕ рдпрд╣ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ? рдХреЛрдИ рд╡рд┐рдЪрд╛рд░?

@tsaockham
рдореЗрд░реЗ рдкрд╛рд╕ рд╕рдорд╛рдзрд╛рди рд╣реИ :)

function waitForLogger() {
    return new Promise(resolve => setTimeout(resolve, 2500));
}

рд╕рдорд╛рдзрд╛рди рдЦреЛрдЬрдиреЗ рдХреЗ 2 рдШрдВрдЯреЗ рдХреЗ рдмрд╛рдж рдореИрдВрдиреЗ рдЗрд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдпрд╛, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛтАЛтАЛрдХрд┐ @dpraul рджреНрд╡рд╛рд░рд╛ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рдВрдХреНрд╢рди рднреА рдХрд╛рдо рдирд╣реАрдВ рдХрд┐рдпрд╛, рдореИрдВ рдХрд░ рдЪреБрдХрд╛ рд╣реВрдВред

рдореБрдЭреЗ рдЗрд╕ рдереНрд░реЗрдб рдкрд░ рдЕрд▓рд░реНрдЯ рдорд┐рд▓рддреЗ рд░рд╣рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рд╕рд╛рдЭрд╛ рдХрд░реВрдВрдЧрд╛ рдХрд┐ рдореБрдЭреЗ рдХреНрдпреЛрдВ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЕрднреА рднреА рдмрд╣реБрдд рд╕реЗ рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИред рдкреГрд╖реНрдарднреВрдорд┐: рд╣рдорд╛рд░рд╛ рдЙрдкрдпреЛрдЧ-рдорд╛рдорд▓рд╛ (рдФрд░ рдЬрд┐рд╕ рд╕рдВрджрд░реНрдн рдореЗрдВ рдпрд╣ рдореБрджреНрджрд╛ рдЦреЛрд▓рд╛ рдЧрдпрд╛ рдерд╛) рдПрдбрдмреНрд▓реНрдпреВрдПрд╕ рд▓реИрдореНрдмреНрдбрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдпрд╣рд╛рдВ рдЬрд┐рд╕ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рд╡рд╣ рдХреЗрд╡рд▓ рд╡рд╣рд╛рдВ рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИред

рд▓реИрдореНрдмреНрдбрд╛ рд▓реИрдореНрдмреНрдбрд╛ рдПрдХреНрдЬрд╝реАрдХреНрдпреВрд╢рди рдХреЙрдиреНрдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рддрд╣рдд рдиреЛрдб рдЪрд▓рд╛рддрд╛ рд╣реИред рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдЬрд╛ рд░рд╣реА рд╣реИ:

рд▓реИрдореНрдмреНрдбрд╛ рдлрд╝рдВрдХреНрд╢рди рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдПрдбрдмреНрд▓реНрдпреВрдПрд╕ рд▓реИрдореНрдмреНрдбрд╛ рдПрдХ рдФрд░ рд▓реИрдореНрдмреНрдбрд╛ рдлрд╝рдВрдХреНрд╢рди рдЖрдордВрддреНрд░рдг рдХреА рдкреНрд░рддреНрдпрд╛рд╢рд╛ рдореЗрдВ рдХреБрдЫ рд╕рдордп рдХреЗ рд▓рд┐рдП рдирд┐рд╖реНрдкрд╛рджрди рд╕рдВрджрд░реНрдн рдмрдирд╛рдП рд░рдЦрддрд╛ рд╣реИред

рддрдерд╛

  • рдЖрдкрдХреЗ рд▓реИрдореНрдмреНрдбрд╛ рдлрд╝рдВрдХреНрд╢рди рдХреЛрдб рдореЗрдВ рдХреЛрдИ рднреА рдШреЛрд╖рдгрд╛ (рд╣реИрдВрдбрд▓рд░ рдХреЛрдб рдХреЗ рдмрд╛рд╣рд░, рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдореЙрдбрд▓ рджреЗрдЦреЗрдВ) рдЖрд░рдВрднрд┐рдХ рдмрдиреА рд░рд╣рддреА рд╣реИ, рдЬрдм рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рдЕрддрд┐рд░рд┐рдХреНрдд рдЕрдиреБрдХреВрд▓рди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред

рдпрд╛рдиреА рд▓реЙрдиреНрдЪ рдХреЛ рдЧрддрд┐ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП, рд▓реИрдореНрдмреНрдбрд╛ "рдлреНрд░реАрдЬ" рдФрд░ "рдереЙ" рд╡рд╛рддрд╛рд╡рд░рдг рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдмрдВрдж рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп "рдлреНрд░реАрдЬ" рдХрд░рддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд▓реИрдореНрдмреНрдбрд╛ рдиреЛрдб рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдпрд╣ рдЖрдкрдХреЗ рд╣реИрдВрдбрд▓рд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИред рдХрд┐рд╕реА рднреА рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рд╣реИрдВрдбрд▓рд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдмрд╛рд╣рд░ рдЪрд▓рд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╢реЗрд╖ рд▓реИрдореНрдмреНрдбрд╛ рдирд┐рд╖реНрдкрд╛рджрди рд╕рдВрджрд░реНрдн рдХреЗ рд╕рд╛рде рдЬрдореЗ рд╣реБрдП рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд╣реИрдВ рдпрджрд┐ рдЙрдирдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдирд╣реАрдВ рдХреА рдЬрд╛рддреА рд╣реИред

рдЕрдм рдЖрдЗрдП рд╡рд┐рдВрд╕реНрдЯрди рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХреЗ рд▓рд┐рдП рд╕реБрдЭрд╛рдП рдЧрдП рд╕рдорд╛рдзрд╛рди рдХреЛ рджреЗрдЦреЗрдВ - UPGRADE-3.0.md рд╕реЗ рдЕрдиреБрдХреВрд▓рд┐рдд, рдпрд╣ рдорд╛рдирддреЗ рд╣реБрдП рдХрд┐ рд╣рдо рд▓реИрдореНрдмреНрдбрд╛ рдореЗрдВ рдЪрд▓ рд░рд╣реЗ рд╣реИрдВ:

async function lambdaHandler(event, context) {
  const logger = winston.createLogger({
    transports: [
      new winston.transports.Console(),
      new CustomAsyncTransport(),
    ],
  });
  logger.log('info', 'some message');
  logger.on('finish', () => process.exit());
  logger.end();
}

рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдПрдВ? logger рд╣реИрдВрдбрд▓рд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ logger.end() рдХреЛ рд╕рдХреНрд░рд┐рдп рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди logger.on('finish') рджреНрд╡рд╛рд░рд╛ рдлрд╝рд╛рдпрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдлрд╝рдВрдХреНрд╢рди рд╣реИрдВрдбрд▓рд░ рд╕рдВрджрд░реНрдн рдХреЗ рдмрд╛рд╣рд░ рдЪрд▓рддрд╛ рд╣реИред CustomAsyncTransport рд╕реЗ рдЬреБрдбрд╝реА рдХреЛрдИ рднреА рдПрд╕рд┐рдВрдХ рдкреНрд░рдХреНрд░рд┐рдпрд╛ finish рдШрдЯрдирд╛ рдХреЛ рдлрд╛рдпрд░рд┐рдВрдЧ рд╕реЗ рд░реЛрдХ рджреЗрдЧреА, рдЬрд┐рд╕рд╕реЗ рдпрд╣ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рдЙрд╕ рдШрдЯрдирд╛ рдХреЗ рд╢реБрд░реВ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдирд┐рд╖реНрдкрд╛рджрди рд╕рдВрджрд░реНрдн рдлреНрд░реАрдЬ рд╣реЛ рдЬрд╛рдПред

рдЗрд╕реЗ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, lambdaHandler рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдХреЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреА рдЪрд╛рд╣рд┐рдП:

async function lambdaHandler(event, context) {
  const logger = winston.createLogger({
    transports: [
      new winston.transports.Console(),
      new CustomAsyncTransport(),
    ],
  });
  const loggerFinished = new Promise(resolve => logger.on('finish', resolve));
  logger.log('info', 'some message');
  logger.end();
  await loggerFinished;
}

рдЪреВрдБрдХрд┐ lambdaHandler рддрдм рддрдХ рдмрд╛рд╣рд░ рдирд╣реАрдВ рдирд┐рдХрд▓рддрд╛ рдЬрдм рддрдХ logger finish рдИрд╡реЗрдВрдЯ рдХреЛ рд╕рдХреНрд░рд┐рдп рдирд╣реАрдВ рдХрд░ рджреЗрддрд╛, рд╣рдорд╛рд░реЗ CustomAsyncTransport рдХреЛ рд╣рдорд╛рд░реЗ рд▓реИрдореНрдмреНрдбрд╛ рд╣реИрдВрдбрд▓рд░ рд╕реЗ рдкрд╣рд▓реЗ рдмрдВрдж рдХрд░ рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЙрди рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рдлрд╝реНрд░реАрдЬрд╝ рд╣реЛрдиреЗ рд╕реЗ рдмрдЪрд╛рдирд╛ (рдпрд╣ рдорд╛рдирдХрд░ finish рдИрд╡реЗрдВрдЯ @indexzero рджреНрд╡рд╛рд░рд╛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ)ред

рдЗрд╕реЗ рдореЗрд░реЗ рджреНрд╡рд╛рд░рд╛ рдкрд╣рд▓реЗ рд╕рд╛рдЭрд╛ рдХрд┐рдП рдЧрдП рдХреЛрдб рдХреЗ рд╕рдорд╛рди рдХреБрдЫ рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:

async function waitForLogger(logger) {
  const loggerDone = new Promise(resolve => logger.on('finish', resolve));
  // alternatively, use end-of-stream https://www.npmjs.com/package/end-of-stream
  // although I haven't tested this
  // const loggerDone = new Promise(resolve => eos(logger, resolve));
  logger.end();
  return loggerDone;
}

async function lambdaHandler(event, context) {
  const logger = winston.createLogger({
    transports: [
      new winston.transports.Console(),
      new CustomAsyncTransport(),
    ],
  });
  logger.log('info', 'some message');
  await waitForLogger(logger);
}

рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдпрд╣ рдХреБрдЫ рд▓реЛрдЧреЛрдВ рдХреА рдорджрдж рдХрд░рддрд╛ рд╣реИред

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд▓реЙрдЧрд░ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ?

winston.on() рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдирд╣реАрдВ рд╣реИред

@dpraul рд╕рдорд╛рдзрд╛рди рдиреЗ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛ред

рдЗрд╕реЗ рдереЛрдбрд╝рд╛ рд╕рд╛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд┐рдпрд╛:

  async close() {
    return new Promise((resolve, reject) => {
      logger.on('close', () => {
        return resolve()
      })
      logger.on('error', err => {
        return reject(err)
      })
      logger.close()
    })
  }

рдмрд╕ рдзреНрдпрд╛рди рджреЗрдВ, рдЬрдм рдЖрдк рдЕрдкрдирд╛ logger рдмрдирд╛рддреЗ рд╣реИрдВ рддреЛ рдЙрд╕реА рд╕рдордп рдЕрдкрдиреЗ рддреНрд░реБрдЯрд┐ рд╣реИрдВрдбрд▓рд░ рдХреЛ рд╕реЗрдЯ рдХрд░рдирд╛ рдЕрдЪреНрдЫрд╛ рдЕрднреНрдпрд╛рд╕ рд╣реИред рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдХрд┐рд╕реА рднреА рд╕рдордп рд╕рдХреНрд░рд┐рдп рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ - рдпрджрд┐ рдЖрдк рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдХреЛ рдмрдВрдж рдХрд░рддреЗ рд╕рдордп рдХреЗрд╡рд▓ рдЙрдиреНрд╣реЗрдВ рд╕реБрдирддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдЙрдиреНрд╣реЗрдВ рдпрд╛рдж рдХрд░рдиреЗ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рд░рдЦрддреЗ рд╣реИрдВред

рдореИрдВ sqlTransport рдореЙрдбреНрдпреВрд▓ рдХреЗ рд╕рд╛рде mariaDB рдореЗрдВ Nodejs8 рд▓реЙрдЧрд┐рдВрдЧ рдХреЗ рддрд╣рдд рд╡рд┐рдВрд╕реНрдЯрди 3 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рдЗрд╕рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдбреЙрдХреНрд╕/transports.md рдХреЗ рдЕрдиреБрд╕рд╛рд░ Winston3 рдХреЗ рд▓рд┐рдП sqlTransport рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд┐рдпрд╛ред
рд╡рд┐рдВрд╕реНрдЯрди 3 рдиреЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рдЕрдВрдд рдореЗрдВ рд▓рдЯрдХрд╛ рджрд┐рдпрд╛ред
рдореИрдВрдиреЗ рдЗрд╕ рдореБрджреНрджреЗ рд╕реЗ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рд╕реНрддрд╛рд╡реЛрдВ рдХреЗ рд╕рд╛рде рдкреНрд░рдпреЛрдЧ рдХрд┐рдпрд╛ рдФрд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдирд┐рд╖реНрдХрд░реНрд╖ рдкрд░ рдкрд╣реБрдВрдЪрд╛:
sqlTransport рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рдПрдХ рдХрд░реАрдмреА () рд╡рд┐рдзрд┐ рд▓рд╛рдЧреВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП рдЬреЛ рдореЙрдбреНрдпреВрд▓ (рдпрд╛рдиреА рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рдЕрдВрджрд░) рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдмрдВрдж рдХрд░ рджреЗред
рдиреЛрдЯ: рдЕрдВрдд () рд╡рд┐рдзрд┐ рдХреЛ рд▓рд╛рдЧреВ рди рдХрд░реЗрдВ! - рдореБрдЭреЗ рд╕рдЪ рдореЗрдВ рдкрддрд╛ рдирд╣реАрдВ рдХреНрдпреЛрдВред
рдЕрдм, logger.end() рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдмрдВрдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред
Logger.close (), рдЬреЛ рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдХреЛ рддрддреНрдХрд╛рд▓ рдирд┐рд░рд╕реНрдд рдХрд░рдиреЗ рдФрд░ рдбреЗрдЯрд╛ рд╣рд╛рдирд┐ рдХрд╛ рдХрд╛рд░рдг рдмрдирддрд╛ рд╣реИред

рдпрджрд┐ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЗ рдЕрдВрдд рдореЗрдВ рдПрдХ рддреНрд░реБрдЯрд┐ рд╣реИрдВрдбрд▓рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рддреЛ рдЖрдк рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ

рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рддреАрдХреНрд╖рд╛рдлреЙрд░рд▓реЙрдЧрд░ (myLogger) {
рдХреЙрдиреНрд╕реНрдЯ рд▓реЙрдЧрд░рдбреЛрди = рдирдпрд╛ рд╡рд╛рджрд╛ ((рд╕рдорд╛рдзрд╛рди, рдЕрд╕реНрд╡реАрдХрд╛рд░) => {
myLogger.on('finish', () => {рд░рд┐рдЯрд░реНрди рд░рд┐рдЬреЙрд▓реНрдпреВрд╢рди ()})
myLogger.on ('рддреНрд░реБрдЯрд┐', рддреНрд░реБрдЯрд┐ => {рд╡рд╛рдкрд╕реА рдЕрд╕реНрд╡реАрдХрд╛рд░ (рдЧрд▓рддреА)})
})
myLogger.end ();
рд▓рдХрдбрд╝рд╣рд╛рд░рд╛ рд▓реМрдЯрд╛;
}
рддрдерд╛
WaitForLogger (рд▓реЙрдЧрд░)ред рддрдм (() => {рдХрдВрд╕реЛрд▓ред рд▓реЙрдЧ ('рд╕рдм рдХрд┐рдпрд╛!')})ред рдкрдХрдбрд╝реЗрдВ ((рдЧрд▓рддреА) => {рдХрдВрд╕реЛрд▓ред рддреНрд░реБрдЯрд┐ (рдЧрд▓рддреА)});

рдореИрдВ рдЕрднреА рднреА рдпрд╣ рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ред рдореИрдВ рд╡рд┐рдВрд╕реНрдЯрди 3.1.0 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рд╕реБрд╕реНрдд рдкрд░рд┐рд╡рд╣рди рд╡рд┐рдВрд╕реНрдЯрди-рд╕реНрд▓реИрдХ-рд╡реЗрдмрд╣реБрдХ-рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ рдЬреЛ рдПрдХ http рдЕрдиреБрд░реЛрдз рдХрд░рддрд╛ рд╣реИред рдпрд╣ рддреНрд░реБрдЯрд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛:

Error: write after end
at writeAfterEnd (/var/task/node_modules/winston/node_modules/readable-stream/lib/_stream_writable.js:257:12)
at DerivedLogger.Writable.write (/var/task/node_modules/winston/node_modules/readable-stream/lib/_stream_writable.js:301:21)
at DerivedLogger.(anonymous function) [as error] (/var/task/node_modules/winston/lib/winston/create-logger.js:81:14)
at errorHandler (/var/task/error/error-handler.js:27:36)
at Layer.handle_error (/var/task/node_modules/express/lib/router/layer.js:71:5)
at trim_prefix (/var/task/node_modules/express/lib/router/index.js:315:13)
at /var/task/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/var/task/node_modules/express/lib/router/index.js:335:12)
at Immediate.next (/var/task/node_modules/express/lib/router/index.js:275:10)
at Immediate._onImmediate (/var/task/node_modules/express/lib/router/index.js:635:15)

рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ:
рдореИрдВрдиреЗ рдЕрдм рджреЗрдЦрд╛ рд╣реИ рдХрд┐ рдореБрдЭреЗ рд╣реИрдВрдбрд▓рд░ рдХреЗ рдЕрдВрджрд░ рд▓реЙрдЧрд░ рдмрдирд╛рдирд╛ рд╣реЛрдЧрд╛, рдЕрдЧрд░ рдореИрдВ рдирд╣реАрдВ рдХрд░рддрд╛, рддреЛ рд▓реИрдореНрдмреНрдбрд╛ рд╕рдВрджрд░реНрдн рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ "рд╕рдорд╛рдкреНрдд" рд▓реЙрдЧрд░ рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд╕рдХрддрд╛ рд╣реИред

рдореБрдЭреЗ @iudelsmann рдЬреИрд╕реА рд╣реА рддреНрд░реБрдЯрд┐ рдорд┐рд▓ рд░рд╣реА рд╣реИ, рдХреНрдпрд╛ рдпрд╣ рдЬрд╛рдВрдЪрдирд╛ рд╕рдВрднрд╡ рд╣реИ рдХрд┐ рд▓рдХрдбрд╝рд╣рд╛рд░рд╛ рдкрд╣рд▓реЗ рд╕реЗ рдмрдВрдж рд╣реИ рдпрд╛ рдирд╣реАрдВ?

рдПрдбрдмреНрд▓реНрдпреВрдПрд╕ рдПрдкреАрдЖрдИ рдЧреЗрдЯрд╡реЗ рдХреЗ рд╕рд╛рде, рд╣рдо 1-2 рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рд▓реЙрдЧ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИрдВ рд▓реЗрдХрд┐рди logger.end() рдХреЗ рдмрд╛рдж; рдпрд╣ рдЕрднреА рднреА рдЙрд╕реА рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд░рд╣рд╛ рд╣реИ рдФрд░ рд╣рдо рдкреНрд░рд╛рдкреНрдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ
UnhandledPromiseRejectionWarning: Error: write after end at writeAfterEnd (/var/task/node_modules/winston/node_modules/readable-stream/lib/_stream_writable.js:257:12) at DerivedLogger.Writable.write (/var/task/node_modules/winston/node_modules/readable-stream/lib/_stream_writable.js:301:21) at DerivedLogger.log (/var/task/node_modules/winston/lib/winston/logger.js:223:12)

рд╣рдо рд╡рд┐рдВрд╕реНрдЯрди-рд╕рд┐рд╕рд▓реЙрдЧ рдХреЗ рд╕рд╛рде рдкреЗрдкрд░рдЯреНрд░реЗрд▓ рд▓реЙрдЧрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВред

рдпрд╣рд╛рдБ рдХреЛрдб рд╣реИред

`рдХреЙрдиреНрд╕реНрдЯ рд╡рд┐рдВрд╕реНрдЯрди = рдЖрд╡рд╢реНрдпрдХрддрд╛ ('рд╡рд┐рдВрд╕реНрдЯрди')
рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ ('рд╡рд┐рдВрд╕реНрдЯрди-рд╕рд┐рд╕рд▓реЙрдЧ')
рдХреЙрдиреНрд╕реНрдЯ рд╣реЛрд╕реНрдЯрдирд╛рдо = рдЖрд╡рд╢реНрдпрдХрддрд╛ ("рдУрдПрд╕")ред рд╣реЛрд╕реНрдЯрдирд╛рдо ()

рд╕реНрдерд┐рд░рд╛рдВрдХ рд╡рд┐рдХрд▓реНрдк = {
рд╣реЛрд╕реНрдЯ: PAPERTRAIL_URL,
рдкреЛрд░реНрдЯ: PAPERTRAIL_PORT,
рдРрдк_рдирд╛рдо: PAPERTRAIL_LOG_CHANNEL,
рд▓реЛрдХрд▓рд╣реЛрд╕реНрдЯ: рд╣реЛрд╕реНрдЯрдирд╛рдо
}

рдХреЙрдиреНрд╕реНрдЯ рдкреАрдЯреАрдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ = рдирдпрд╛ рд╡рд┐рдВрд╕реНрдЯрди.рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯред рд╕рд┐рд╕реНрд▓реЙрдЧ (рд╡рд┐рдХрд▓реНрдк)
рдХреЙрдиреНрд╕реНрдЯ рд▓реЙрдЧрд░ = рд╡рд┐рдВрд╕реНрдЯрдиред рдХреНрд░рд┐рдПрдЯрд▓реЙрдЧрд░ ({
рдкрд░рд┐рд╡рд╣рди: [рдкреАрдЯреАрдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ],
рдкреНрд░рд╛рд░реВрдк: рд╡рд┐рдВрд╕реНрдЯрди.format.combine(
рд╡рд┐рдВрд╕реНрдЯрдиред рдкреНрд░рд╛рд░реВрдкред рд░рдВрдЧ ({
рд╕рднреА рд╕рдЪ
}),
рд╡рд┐рдВрд╕реНрдЯрдиред рдкреНрд░рд╛рд░реВрдкред рд╕рд░рд▓ ()
)
})`

@hdpa рдРрд╕рд╛ рд╢рд╛рдпрдж рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕реЗ рдмрдВрдж рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдЖрдкрдХреЗ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╣рдорд╛рд░рд╛ рд╡рд░реНрддрдорд╛рди рд╕рдорд╛рдзрд╛рди рдпрд╣ рд╣реИ:

// logger.js
let logger;

const recreateLogger = () => {
  logger = winston.createLogger({
  ....
};

const getLogger = () => {
  if (logger && !logger.writable) {
    recreateLogger();
  }
  return logger;
}

const closeLogger = async () => {
  const loggerClosed = new Promise(resolve => logger.on('finish', resolve));
  // https://github.com/winstonjs/winston/issues/1250
  logger.end();
  return loggerClosed;
}

рдлрд┐рд░ рд╣рдорд╛рд░реЗ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рд╣рдо рд▓реЙрдЧрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ getLogger() рдкрд░ рдХреЙрд▓ рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рдмрдВрдж рд╣реЛрдиреЗ рдкрд░ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рдЦреЛрд▓ рджреЗрддрд╛ рд╣реИ рдФрд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдЕрдВрдд рдореЗрдВ рд╣рдо closeLogger() рдХрд╛ рдЙрдкрдпреЛрдЧ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдХреНрд▓рд╛рдЙрдбрд╡реЙрдЪ рдХреЗ рд╕рднреА рд▓реЙрдЧ рдХреЛ рдлреНрд▓рд╢ рдХрд░рддрд╛ рд╣реИ

рдЙрдкрд░реЛрдХреНрдд рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рд╡рд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реЛ рд░рд╣реА рд╣реИред рдореИрдВрдиреЗ рдХрдВрд╕реЛрд▓ рдореЗрдВ рд▓реЙрдЧрд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдореБрджреНрд░рд┐рдд рдХрд┐рдпрд╛ рд╣реИред рдиреАрдЪреЗ рдкрд╣рд▓реЗ рдФрд░ рджреВрд╕рд░реЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╣реИ,

DerivedLogger { _readableState: ReadableState { objectMode: true, highWaterMark: 16, buffer: BufferList { head: null, tail: null, length: 0 }, length: 0, pipes: Syslog { _writableState: [Object], writable: true, domain: null, _events: [Object], _eventsCount: 6 яЕБ

DerivedLogger { _readableState: ReadableState { objectMode: true, highWaterMark: 16, buffer: BufferList { head: null, tail: null, length: 0 }, length: 0, pipes: null, pipesCount: 0, flowing: false, ended: true, endEmitted: false, reading: false, sync: false, needReadable: яЕБ

рддреНрд░реБрдЯрд┐: рд▓рд┐рдЦрдиреЗ рдХреЗ рдмрд╛рдж рдЕрдВрдд рдореЗрдВ рд▓рд┐рдЦреЗрдВ рдЖрдлреНрдЯрд░рдПрдВрдб (/var/task/node_modules/winston/node_modules/readable-stream/lib/_stream_writable.js:257:12) рдкрд░ DerivedLogger.Writable.write (/var/task/node_modules/winston/node_modules) /readable-stream/lib/_stream_writable.js:301:21) DerivedLogger рдкрд░ред (рдЕрдирд╛рдо рдлрд╝рдВрдХреНрд╢рди) [рддреНрд░реБрдЯрд┐ рдХреЗ рд░реВрдк рдореЗрдВ] (/var/task/node_mod)
яЕБ

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ Syslog рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ рдХреЛ рдПрдВрдб рдореЗрдердб рдХреЗ рдмрд╛рдж рд╣рдЯрд╛рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ рдФрд░ рдпрд╣реАрдВ рдкрд░ рд╣рдореЗрдВ рдПрд░рд░ рдорд┐рд▓ рд░рд╣рд╛ рд╣реИред

рдореЗрд░реА рдкреЛрд╕реНрдЯ рдХреЛ рднреВрд▓ рдЬрд╛рдУ, рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдкрд╣рд▓реЗ рдЕрдиреБрд░реЛрдз рдкрд░ рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рджреВрд╕рд░реЗ рдкрд░ рдХреБрдЫ рдмрд╕ рдЯрд╛рдЗрдордЖрдЙрдЯ ЁЯШХ рдЗрд╕реЗ рдмрдВрдж рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдЗрд╕реЗ рдлреНрд▓рд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╕ рдЗрдВрддрдЬрд╛рд░ рдХрд░рдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛

рдУрд╣, рдКрдкрд░ рдХреА рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдореИрдВ рдкрд╣рд▓реЗ рд╕реЗ рдмрдВрдж рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдХреЛ рдмрдВрдж рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реВрдВ рддрд╛рдХрд┐ рд╡рд╛рджрд╛ рдХрднреА рд╣рд▓ рди рд╣реЛ, рдпрд╣ рдЗрд╕реЗ рдареАрдХ рдХрд░рддрд╛ рд╣реИ

const closeLogger = async () => {
  if (logger && !logger.writable) {
    // If it's already closed don't try to close it again
    return Promise.resolve();
  }
  const loggerClosed = new Promise(resolve => logger.on('finish', resolve));
  // https://github.com/winstonjs/winston/issues/1250
  logger.end();
  return loggerClosed;
}

рдЕрдВрдХ #1081 рдЗрд╕ рдзрд╛рдЧреЗ рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд▓рдХрдбрд╝рд╣рд╛рд░рд╛ рдкрд░рд┐рд╡рд╣рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдиреБрд░реЛрдз рдЖрдИрдбреА рдХреЛ рдЕрд▓рдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХреНрд▓рд╛рдЙрдбрд╡реЙрдЪ рд▓реЙрдЧ рдХрд╛ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рд╣реИред рдЬрд┐рд╕ рддрд░рд╣ рд╕реЗ рдореИрдВ рдЕрдиреБрд░реЛрдз рдЖрдИрдбреА рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдерд╛, рд╡рд╣ рд▓реИрдореНрдмреНрдбрд╛ рдХреЗ context рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдиреАрдЪреЗ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ -

createLogger({
    defaultMeta: { service: process.env.AWS_LAMBDA_FUNCTION_NAME,
                    requestID: context.awsRequestId
                   },
    transports: [
        new transports.Console({
            level: 'debug',
            format: format.combine(
                format.timestamp({
                    format: 'YYYY-MM-DD HH:mm:ss'
                  }),
                format.errors({ stack: true }),
                format.splat(),
                format.json()
            )
        })
    ]
});

рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпрд╣ рд╡рд┐рдзрд┐ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддреА рд╣реИ рдпрджрд┐ рдЖрдкрдХрд╛ Logger.js рдЖрдкрдХреЗ рд▓реИрдореНрдмреНрдбрд╛ рд╣реИрдВрдбрд▓рд░ рдХреЗ рдмрд╛рд╣рд░ рд╣реЛрддрд╛ рд╣реИ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рд▓реИрдореНрдмреНрдбрд╛ рд▓реЗрдпрд░ рдореЗрдВред рдЬрд╛рд╣рд┐рд░ рд╣реИ, рд╕рдВрджрд░реНрдн рдЖрдпрд╛рдд рд╕реЗ рд╕реБрд▓рдн рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдЕрдкрдиреА рд▓реЙрдЧрд░ рдкрд░рд┐рднрд╛рд╖рд╛ рдПрдХ рдкрд░рдд рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реИ рдФрд░ рдЖрдк рдЗрд╕реЗ рдЕрдкрдиреЗ рд▓реИрдореНрдмреНрдбрд╛ рдореЗрдВ рдЖрдпрд╛рдд рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЖрдкрдХреЛ defaultMeta рдХреЛ logger рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рд╣реИрдВрдбрд▓рд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдЕрдВрджрд░

рдкреАрдПрд╕ : рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд▓реИрдореНрдмреНрдбрд╛ рдлрд╝рдВрдХреНрд╢рди рджреНрд╡рд╛рд░рд╛ рд▓реЙрдЧрд░ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдирд╛ рдПрдХ рднрдпрд╛рдирдХ рд╡рд┐рдЪрд╛рд░ рд╣реИ, рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдкрд░рддреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧред

const logger = require('./opt/nodejs/Logger'); //import from Lambda Layer

exports.handler = async (event, context) => {
    //inject defaultMeta
    logger.log.defaultMeta =  { service: process.env.AWS_LAMBDA_FUNCTION_NAME,
                            requestID: context.awsRequestId };
    logger.log.info(`This is just an info message`);
    logger.log.error("This is an error message");
    await logger.waitForLogger(logger.log);
    return event;
};

logger.end() рдХреЗрд╡рд▓ рдкрд╣рд▓реЗ рдлрд╝рдВрдХреНрд╢рди рдХреЙрд▓ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рджреВрд╕рд░реА рдХреЙрд▓ рддреНрд░реБрдЯрд┐ рдХреА рдУрд░ рд▓реЗ рдЬрд╛рддреА рд╣реИ:

{
    "errorType": "Error",
    "errorMessage": "write after end",
    "code": "ERR_STREAM_WRITE_AFTER_END",
    "stack": [
        "Error: write after end",
        "    at writeAfterEnd (/var/task/node_modules/readable-stream/lib/_stream_writable.js:257:12)",
        "    at DerivedLogger.Writable.write (/var/task/node_modules/readable-stream/lib/_stream_writable.js:301:21)",
        "    at DerivedLogger.(anonymous function) [as info] (/var/task/node_modules/winston/lib/winston/create-logger.js:81:14)",
        "    at Runtime.handler (/var/task/lambda_logger.js:65:12)",
        "    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"
    ]
}

рдореИрдВ рд▓реИрдореНрдмреНрдбрд╛ рд╣реИрдВрдбрд▓рд░ рдХреЗ рд▓рд┐рдП рдбреЗрдХреЛрд░реЗрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ winston рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ:

// lambda_logger.js
const winston = require('winston')
const WinstonCloudWatch = require('winston-cloudwatch')
const { format } = winston

async function closeLogger(logger) {
  const transportsFinished = logger.transports.map(
    t => new Promise(resolve => t.on('finish', resolve))
  )
  logger.end()
  return Promise.all(transportsFinished)
}

const decorator = (wrapped, loggerName = null) => {
  return async (event, context, callback) => {
    const LAMBDA_LOGGER_NAME =
      loggerName || `${process.env.AWS_LAMBDA_FUNCTION_NAME}-lambda-logger`

    winston.loggers.add(LAMBDA_LOGGER_NAME, {
      format: format.combine(
        format.timestamp({ format: 'DD-MM-YYYY HH:mm:ss' }),
        format.errors(),
        format.label({
          label: `${process.env.AWS_LAMBDA_FUNCTION_NAME}:${process.env.AWS_LAMBDA_FUNCTION_VERSION}`,
        }),
        format.splat(),
        format.json()
      ),
      transports: [
        new WinstonCloudWatch({
          logGroupName: process.env.AWS_LAMBDA_LOG_GROUP_NAME,
          logStreamName: process.env.AWS_LAMBDA_LOG_STREAM_NAME,
          awsRegion: process.env.AWS_REGION,
          jsonMessage: true,
          retentionInDays: 3,
        }),
      ],
      defaultMeta: { context, logger_name: LAMBDA_LOGGER_NAME },
    })
    const logger = winston.loggers.get(LAMBDA_LOGGER_NAME)

    logger.info({ env: process.env, event })
    let res

    try {
      res = await wrapped(event, {
        context,
        callback,
        loggerName: LAMBDA_LOGGER_NAME,
      })
      logger.debug('RES:', res)
    } catch (e) {
      console.error(e)
      throw e
    }

    await closeLogger(logger)

    return res
  }
}

module.exports = decorator
// handler.js
const winston = require('winston')
const loggingDecorator = require('./lambda_logger')

const hello = async (event, opts) => {
  const { loggerName } = opts
  const logger = winston.loggers.get(loggerName)

  logger.warn({ logger })

  const res = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'We use Winston logger as a decorator for lambda handdler!!'
    }),
  }

  return res
}

module.exports.hello = loggingDecorator(hello)

рдХреНрдпрд╛ рдЗрд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдЗ рдЙрдкрд╛рдп рд╣реИ?

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдкрд╣рд▓реА рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдореЗрдВ рд░рдЦрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдХреЛрдб рдХреЗ рд╕рд╛рде рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдЬреИрд╕реЗ:

process.on('uncaughtException', err => {
    logger.error(err, () => {
        process.exit(1);
    });
});

рдпрд╣ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рд╣рдореЗрд╢рд╛ рдХреЗ рд▓рд┐рдП рд▓рдЯрдХрд╛ рджреЗрдЧрд╛ рдФрд░ рдЗрдирд╛рдпрдд рд╕реЗ рдкреБрдирд░рд╛рд░рдВрдн рдХрд░рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрде рд╣реЛрдЧрд╛ред

рдХреНрдпрд╛ рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдареАрдХ рд╣реЛ рдЬрд╛рдПрдЧреА рдпрд╛ рдпрд╣ рдмрдВрдж рд╣реА рд░рд╣реЗрдЧреА?

@dpraul рдХрд╛ рд╕рдорд╛рдзрд╛рди рдпрд╣рд╛рдБ (https://github.com/winstonjs/winston/issues/1250#issuecomment-452128291) рдиреЗ рд╕рдорд╕реНрдпрд╛ рдФрд░ рд╕рдорд╛рдзрд╛рди рдХреЛ рдмрд╣реБрдд рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕рдордЭрд╛рдпрд╛ред рдЗрд╕рдиреЗ рдореЗрд░реЗ рд▓рд┐рдП AWS рд▓реИрдореНрдмреНрдбрд╛ рдореЗрдВ рдХрд╛рдо рдХрд┐рдпрд╛ред

рдПрдХ рдиреЛрдЯ рдЬреЛ рдЙрд╕рдиреЗ рдкрд╣рд▓реЗ рдереНрд░реЗрдб рдореЗрдВ рдХрд╣рд╛ рдерд╛ рдХрд┐ рдореИрдВ рдлрд┐рд░ рд╕реЗ рджреЛрд╣рд░рд╛рдКрдВрдЧрд╛ред рд▓реИрдореНрдмреНрдбрд╛ рд╣реИрдВрдбрд▓рд░ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдЖрдкрдХреЛ рдЕрдкрдирд╛ рд▓реЙрдЧрд░ рдФрд░ рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдирд╛ рд╣реЛрдЧрд╛ред рдпрджрд┐ рдЖрдк рдЙрдирдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЖрдкрдХреЛ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдорд┐рд▓реЗрдВрдЧреА рдХреНрдпреЛрдВрдХрд┐ рд▓реИрдореНрдмреНрдбрд╛ рдирд┐рд╖реНрдкрд╛рджрди рд╡рд╛рддрд╛рд╡рд░рдг рдЬрдореЗ рд╣реБрдП рд╣реЛрдиреЗ рдкрд░ рдкрд░рд┐рд╡рд╣рди рд╕реНрдЯреНрд░реАрдо рдмрдВрдж рд╣реЛ рдЬрд╛рдПрдЧреАред

рдПрдХ рдЖрд╕рд╛рди рддрд░реАрдХрд╛ рдореИрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЦреБрдж рдХреЛ рдкрд╕рдВрдж рдХрд░рддрд╛ рд╣реВрдВ:

function noop() {}

class AsyncTransport extends Transport {
  constructor(opts) {
    super(opts)
    this.callsInProgress = new Map()
    this.index = 0
  }

  async finish() {
    return Promise.all(this.callsInProgress.values())
  }

  log(info) {
    const promise = someAsyncFn(info)
    const i = this.index++
    this.callsInProgress.set(
      i,
      new Promise(resolve => {
        promise.then(resolve)
        setTimeout(resolve, 3000)
      }).then(() => {
        this.callsInProgress.delete(i)
      }),
    )
  }
}

const asyncTransport = new AsyncTransport({ level: 'info' })

const logger = createLogger({
  transports: [
    asyncTransport,
  ],
})
logger.flush= async () => asyncTransport.flush()

module.exports = logger

рдлрд┐рд░ рдЕрдкрдиреЗ рд▓реИрдореНрдмреНрдбрд╛ рдореЗрдВ рдЖрдк рдлрд┐рд░ рд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

exports.handler = async function() {
  logger.info('I will be awaited at the end!')
  await logger.flush()
}

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

рд╡рд┐рдВрд╕реНрдЯрдирдХреНрд▓рд╛рдЙрдбрд╡реЙрдЪ рдкрд░рд┐рд╡рд╣рди рдХреЗ рд▓рд┐рдП рдПрдХ рдкреБрди: рдкреНрд░рдпреЛрдЬреНрдп рдлреНрд▓рд╢ рд╡рд┐рдХрд▓реНрдк рд╣реИ: kthxbyeред рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд▓рд┐рдП kthxbye рдЦреЛрдЬреЗрдВред

рдпрджрд┐ рдЖрдк рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд▓рд┐рдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдкрд░ ('рдмрд╛рд╣рд░ рдирд┐рдХрд▓реЗрдВ' рд╣реИрдВрдбрд▓рд░ рдЬреЛ рд╡рд┐рдВрд╕реНрдЯрди рд▓реЙрдЧрд░ рдХреЛ рдмрдВрдж рдХрд░ рджреЗрддрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдпрд╣рд╛рдВ рдХреНрдпрд╛ рдХрд░рдирд╛ рд╣реИред

// Send kthxbye to WinstonCloudWatch transports
if (logger.writable) {
  await new Promise(resolve => {
    logger.on('error', resolve).on('close', resolve).on('finish',
      () => logger.close()).end();
  });
}
// Send kthxbye to WinstonCloudWatch transports again

рд▓рдХрдбрд╝рд╣рд╛рд░реЗ рдХреЛ рдмрдВрдж рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп рдмрд┐рдирд╛ рдХреНрд░рд┐рдпрд╛ рдХреЗ рдЕрдкрд╡рд╛рдж (рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдлреЗрдВрдХреЗ рдЧрдП рд╕рд╣рд┐рдд) рдХреЛ рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ (рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╡рд┐рдВрд╕реНрдЯрдирдХреНрд▓рд╛рдЙрдбрд╡реЙрдЪ) рдХреЛ рднреЗрдЬреЗ рдЬрд╛рдиреЗ рдХрд╛ рдХрд╛рд░рдг рдмрди рд╕рдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрдкрдХреЛ рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдлрд┐рд░ рд╕реЗ kthxbye рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рд╛рдБред рд╕рдЪ рдореЗрдВред рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдЗрд╕ рдкрд░рд┐рджреГрд╢реНрдп рдореЗрдВ рдлрд╝рд╛рдЗрд▓ рдЬреИрд╕реЗ рдЕрдиреНрдп рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ рдлрд╝реНрд▓рд╢ рд╣реЛ рдЬрд╛рдПрдВрдЧреЗ - рдореИрдВрдиреЗ рдЗрд╕рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рд╡реЗ рдлрд╝реНрд▓рд╢ рд╣реЛрдиреЗ рд▓рдЧрддреЗ рд╣реИрдВ, рд╢рд╛рдпрдж рдЗрд╕рд▓рд┐рдП рдХрд┐ рдиреЛрдбрдЬреЗрдПрд╕ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдкрд░ рдлрд╝рд╛рдЗрд▓ рд╣реИрдВрдбрд▓ рдлреНрд▓рд╢ рдХрд░рддрд╛ рд╣реИ (рдЬреЛ рдХреБрдЫ рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдЬрд▓реНрдж рд╣реА рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ)ред

рдЗрд╕рд▓рд┐рдП, рд╡рд┐рдВрд╕реНрдЯрди 3 рдореЗрдВ рдЕрднреА рднреА рдлреНрд▓рд╢ рдСрдкрд░реЗрд╢рди рдирд╣реАрдВ рд╣реИ рдЬреЛ рд╕рднреА рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

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

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

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

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

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

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