
рд▓реЙрдЧрд┐рдВрдЧ рдПрдХ рдбреЗрд╡рд▓рдкрд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдмрд╣реБрдд рд╣реА рдорд╣рддреНрд╡рдкреВрд░реНрдг рдЙрдкрдХрд░рдг рд╣реИ, рд▓реЗрдХрд┐рди рд╡рд┐рддрд░рд┐рдд рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░рддреЗ рд╕рдордп, рдпрд╣ рдПрдХ рдРрд╕рд╛ рдкрддреНрдерд░ рдмрди рдЬрд╛рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдЖрдкрдХреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рдиреАрдВрд╡ рдореЗрдВ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд░рдЦрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЕрдиреНрдпрдерд╛ рдорд╛рдЗрдХреНрд░реЛрд╕рд░реНрд╡рд┐рд╕реЗрд╕ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдХреА рдЬрдЯрд┐рд▓рддрд╛ рдЬрд▓реНрдж рд╣реА рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЬрд╛рдПрдЧреАред
.Net Core 3 рдиреЗ рдПрдХ рдмреЗрд╣рддрд░реАрди рд╕реБрд╡рд┐рдзрд╛ рдЬреЛрдбрд╝реА рд╣реИ , рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рдЖрдкрдХреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЗрдВрдЯрд░рд╕рд░реНрд╡рд┐рд╕ рд╕рдВрдЪрд╛рд░ рдХреЗ рд▓рд┐рдП рд╕реАрдзреЗ HTTP рдХреЙрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдЗрд╕ рдЖрдЙрдЯ-рдСрдл-рдж-рдмреЙрдХреНрд╕ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпрджрд┐ рдЖрдкрдХрд╛ рдмреИрдХрдПрдВрдб рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХрд┐рд╕реА рдореИрд╕реЗрдЬ рдмреНрд░реЛрдХрд░ (рд░реИрдмрд┐рдЯрдПрдордХреНрдпреВ, рдХрд╛рдлрд╝реНрдХрд╛, рдЖрджрд┐) рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рдВрдЪрд╛рд░ рдХрд╛ рддрд╛рддреНрдкрд░реНрдп рдХрд░рддрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдЕрднреА рднреА рдЗрди рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рд╣рд╕рдВрдмрдВрдз рд╕рдВрджрд░реНрдн рдХреЛ рд╕реНрд╡рдпрдВ рдкрд╛рд╕ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЪрд┐рдВрддрд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рдПрдХ рд╕рд░рд▓ рд╡реЗрдм рдПрдкреАрдЖрдИ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓реЗрдВрдЧреЗ рдФрд░ рд▓реЙрдЧрд┐рдВрдЧ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░реЗрдВрдЧреЗ
рд╕реНрд╡рддрдВрддреНрд░ рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд▓реЙрдЧ рдХреЗ рдмреАрдЪ рдЕрдВрдд-рд╕реЗ-рдЕрдВрдд рд╕рд╣рд╕рдВрдмрдВрдз рдмрдирд╛рдП рд░рдЦреЗрдВ рддрд╛рдХрд┐ рдЖрдк рдХрд┐рд╕реА рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЕрдиреБрд░реЛрдз рдХреЗ рдХрд╛рд░рдг рд╣реЛрдиреЗ рд╡рд╛рд▓реА рд╕рднреА рдЧрддрд┐рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдЖрд╕рд╛рдиреА рд╕реЗ рджреЗрдЦ рд╕рдХреЗрдВ
рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд╕рд╛рде рдПрдХ рдПрдХрд▓ рдкреНрд░рд╡реЗрд╢ рдмрд┐рдВрджреБ рд╣реИ, рддрд╛рдХрд┐ рд╕рдкреЛрд░реНрдЯ рднреА, рдЬрд┐рд╕реЗ "рдореБрдЭреЗ рдРрд╕реЗ-рдРрд╕реЗ рдЕрдиреБрд░реЛрдз рдЖрдИрдбреА рд╡рд╛рд▓реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рддреНрд░реБрдЯрд┐ рдорд┐рд▓реА" рдЬреИрд╕реЗ рдкреНрд░рд╢реНрди рдкреНрд░рд╛рдкреНрдд рд╣реЛрддреЗ рд╣реИрдВ, рд▓реЙрдЧрд┐рдВрдЧ рдЯреВрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХреЗ
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдореЗрдВ рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рд▓реЙрдЧрд┐рдВрдЧ рдкреНрд░рджрд╛рддрд╛ рдкрд░ рдирд┐рд░реНрдгрдп рд▓реЗрдирд╛ рд╣реЛрдЧрд╛ред рдЖрдзреБрдирд┐рдХ рд▓реЙрдЧрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдореБрдЦреНрдп рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╕рдВрд░рдЪрдирд╛ рд╣реИ, рдпрд╛рдиреА рд╣рдореЗрдВ рдлреНрд▓реИрдЯ рдЯреЗрдХреНрд╕реНрдЯ рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рд╕рд╛рде рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдРрд╕реЗ рд▓реЙрдЧ рдХреА рдмрджреМрд▓рдд, рд╣рдо рдЖрд╕рд╛рдиреА рд╕реЗ рд╡рд┐рднрд┐рдиреНрди рдЕрдиреБрднрд╛рдЧреЛрдВ рдореЗрдВ рдЕрдкрдиреЗ рд╕рдВрджреЗрд╢реЛрдВ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рд╣рдорд╛рд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП, рд╣рдо Serilog рдкреИрдХреЗрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ, рдЬрд┐рд╕рдореЗрдВ рд╕рдВрд░рдЪрд┐рдд рд▓реЙрдЧрд┐рдВрдЧ рдФрд░ рдПрдХ рд╕рдореГрджреНрдз рдРрдб-рдСрди рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд▓рд┐рдП рдЙрддреНрдХреГрд╖реНрдЯ рд╕рдорд░реНрдерди рд╣реИред рдореИрдВ рдЗрд╕реЗ рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рдмреБрдирд┐рдпрд╛рджреА рдЪрд░рдгреЛрдВ рдХреЛ рдЫреЛрдбрд╝ рджреВрдВрдЧрд╛ (рдЖрдк рдЗрд╕ рд╡рд┐рд╖рдп рдкрд░ рдмрд╣реБрдд рд╕рд╛рд░реЗ рд▓реЗрдЦ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ) рдФрд░ рдпрд╣ рдорд╛рди рд▓реВрдВрдЧрд╛ рдХрд┐
рд╕реЗрд░рд┐рд▓реЙрдЧ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдпрд╣ рдЖрдкрдХреЗ рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди рдкреНрд░рджрд╛рддрд╛ рдХреЗ рд▓рд┐рдП рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд▓реЙрдЧрд░ рд╣реИред
рдЗрд╕рдХреЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ рд╕рдиреНрджрд░реНрдн рдЧреБрдгреЛрдВ рдХреЗ рд╕рд╛рде рд╕рдВрджреЗрд╢реЛрдВ рдХрд╛ рд╕рдВрд╡рд░реНрдзрди рд╢рд╛рдорд┐рд▓ рд╣реИ (Enrich.FromLogContext)
рдЕрдЧрд▓рд╛ рдЪрд░рдг рдпрд╣ рдЪреБрдирдирд╛ рд╣реИ рдХрд┐ Serilog рд╕реЗ рд╕рдВрджреЗрд╢ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдХреМрди рд╕реА рдХреЗрдВрджреНрд░реАрдХреГрдд рд▓реЙрдЧ рд╕рдВрдЧреНрд░рд╣ рдкреНрд░рдгрд╛рд▓реА рд╣реИред рд╢рд╛рдпрдж рдЖрдЬ рд╕рдмрд╕реЗ рдЖрдо рдУрдкрди рд╕реЛрд░реНрд╕ рд╡рд┐рдХрд▓реНрдк ELK рд╕реНрдЯреИрдХ (рдЗрд▓рд╛рд╕реНрдЯрд┐рдХрд╕рд░реНрдЪ, рд▓реЙрдЧрд╕реНрдЯреИрд╢ рдФрд░ рдХрд┐рдмрд╛рдирд╛) рд╣реИ, рддреЛ рдЪрд▓рд┐рдП рдЗрд╕реЗ рд▓реЗрддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рд▓рд┐рдП, рд╣рдо рд╕реЗрд░рд┐рд▓реЙрдЧ рд╕реЗ рдСрдлрд╝рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ - рдирд┐рдГрд╢реБрд▓реНрдХ рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рдкрдВрдЬреАрдХрд░рдг рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд▓реНрдпреВрд╕реАрди рд╕рд░реНрдЪ рдЗрдВрдЬрди рдХреА рдкреВрд░реА рд╢рдХреНрддрд┐ рд╣рдорд╛рд░реЗ рд╣рд╛рдереЛрдВ рдореЗрдВ рд╣реИред
рдЕрдм рд╣рдореЗрдВ рдмрд╕ рдЕрдкрдиреА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдПрдХ рдкреИрдХреЗрдЬ рдЬреЛрдбрд╝рдирд╛ рд╣реИ
Install-Package Serilog.Sinks.Logzio
рдФрд░ рд╣рдорд╛рд░реЗ рд▓реЙрдЧрд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ рд╕рдВрдмрдВрдзрд┐рдд рдПрдирд░рд┐рдЪрд░ рдЬреЛрдбрд╝реЗрдВ, рдЗрд╕реЗ рдПрдХреНрд╕реЗрд╕ рдЯреЛрдХрди рдЦрд┐рд▓рд╛рдПрдВ
LoggerConfiguration loggerConfig = new LoggerConfiguration();
loggerConfig.WriteTo.Logzio(secrets.LogzioToken, 10, TimeSpan.FromSeconds(10), null, LogEventLevel.Debug);
рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЪрд▓рд╛рдиреЗ рд╕реЗ рд╣рдо рдЕрдкрдиреЗ рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рди рдХреЗрд╡рд▓ рдХрдВрд╕реЛрд▓ рдореЗрдВ, рдмрд▓реНрдХрд┐ рдХрд┐рдмрд╛рдирд╛ рдореЗрдВ рднреА рджреЗрдЦ рдкрд╛рдПрдВрдЧреЗред

рдЗрдВрдЯрд░рдлреЗрд╕

рд╕реЗрд╡рд╛-рдкреНрд░рдХрд╛рд░ рдХреЗ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдВ, рд╣рдо рдмрд╛рд╣рд░реА рджреБрдирд┐рдпрд╛ рдХреЗ рд╕рд╛рде рдЗрд╕рдХреЗ рд╕рдВрдкрд░реНрдХ рдХреЗ рджреЛ рдореБрдЦреНрдп рдЗрдВрдЯрд░рдлреЗрд╕ рдХреЛ рдЕрд▓рдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рдо рдЙрдиреНрд╣реЗрдВ рдКрд░реНрдзреНрд╡рд╛рдзрд░ рдФрд░ рдХреНрд╖реИрддрд┐рдЬ рдХреЗ рд░реВрдк рдореЗрдВ рдирд╛рдорд┐рдд рдХрд░реЗрдВрдЧреЗред рдКрд░реНрдзреНрд╡рд╛рдзрд░ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдПрдХ рд╡реЗрдм рдПрдкреАрдЖрдИ рд╣реИ рдЬрд┐рд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕реЗ рдХреЙрд▓ рдЖрддреЗ рд╣реИрдВред рдХреНрд╖реИрддрд┐рдЬ рдПрдХ рд╕рдВрджреЗрд╢ рдмреНрд░реЛрдХрд░ рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдЕрдиреНрдп рдЖрдВрддрд░рд┐рдХ рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд╕рд╛рде рдбреЗрдЯрд╛ рдХрд╛ рдЖрджрд╛рди-рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдЖрдЗрдП рдЗрдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдЗрдВрдЯрд░рдлреЗрд╕ рдкрд░ рд╕рд╣рд╕рдВрдмрдВрдз рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рдЪрд░рдгреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВред
HTTP рдЕрдиреБрд░реЛрдзреЛрдВ рдореЗрдВ рд╕рд╣рд╕рдВрдмрдВрдз
рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рд╕рдХреЗ рдЙрддрдиреА рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЧрддрд┐рд╡рд┐рдзрд┐ рдХреА рд╢реБрд░реБрдЖрдд рдХреЗ рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рд╕рдХреЗ рдЙрддрдирд╛ рдХрд░реАрдм рд╕рд╣рд╕рдВрдмрдВрдз рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдпрд╛рдиреА рдЧреЗрдЯрд╡реЗ рдкрд░ рдпрд╛ рд╕реАрдзреЗ рдХреНрд▓рд╛рдЗрдВрдЯ (рдореЛрдмрд╛рдЗрд▓ рдпрд╛ рд╡реЗрдм) рдкрд░ред рдЪреВрдВрдХрд┐ рд╣рдо рдЖрдЬ рдПрдХ рдмреИрдХрдПрдВрдб рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдо рд╡реЗрдм API рдХреЗ рд╕рднреА рдЕрдиреБрд░реЛрдзреЛрдВ рдореЗрдВ рдЕрдирд┐рд╡рд╛рд░реНрдп "X-рд╕рд╣рд╕рдВрдмрдВрдз-ID" рд╣реЗрдбрд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЛ рдЖрд╕рд╛рдиреА рд╕реЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВрдЧреЗред
рдкреИрдХреЗрдЬ рдЬреЛрдбрд╝рдирд╛ рдЬрд┐рд╕рдХрд╛ рдХрд╛рд░реНрдп рд╣реЗрдбрд░ рд╕реЗ рд╡рд╣ рдорд╛рди рд▓реЗрдирд╛ рд╣реИ рдЬрд┐рд╕рдХреА рд╣рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ
Install-Package CorrelationID
рдЖрдЗрдП рдЗрд╕реЗ рдЕрдиреБрд░реЛрдз рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ
public class Startup
{
public void Configure(IApplicationBuilder application)
{
application
.UseCorrelationId(new CorrelationIdOptions
{
Header = "X-Correlation-ID",
IncludeInResponse = false,
UpdateTraceIdentifier = false,
UseGuidForCorrelationId = false
});
}
}
рдЕрдм рдЖрдЗрдП рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдХ рд╕рд░рд▓ рдХреНрд░рд┐рдпрд╛ рдлрд╝рд┐рд▓реНрдЯрд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░реЗрдВ:
public sealed class ApiRequestFilter : ActionFilterAttribute
{
public ApiRequestFilter(IApiRequestTracker apiRequestTracker, ICorrelationContextAccessor correlationContextAccessor)
{
_correlationContextAccessor = correlationContextAccessor ?? throw new ArgumentNullException(nameof(correlationContextAccessor));
}
private readonly ICorrelationContextAccessor _correlationContextAccessor;
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
if (!Guid.TryParse(_correlationContextAccessor.CorrelationContext.CorrelationId, out Guid correlationId))
{
context.Result = new BadRequestResult();
return;
}
await next.Invoke();
}
public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
await next.Invoke();
}
}
рдФрд░ рдЪрд▓рд┐рдП рдЗрд╕реЗ рдХрдВрдЯреНрд░реЛрд▓рд░ рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ
[Route("[controller]")]
[ApiController]
[ServiceFilter(typeof(ApiRequestFilter))]
public class CarsController : ControllerBase
{
}
рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдирд┐рдпрдВрддреНрд░рдХ рд╕рдВрдмрдВрдзрд┐рдд рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рд╡рд╛рд▓реЗ рд╣реЗрдбрд░ рдХреЗ рдмрд┐рдирд╛ рд╕рднреА рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рд▓рд┐рдП 400 рдЦрд░рд╛рдм рдЕрдиреБрд░реЛрдз рдЖрдЙрдЯрдкреБрдЯ рдХрд░реЗрдЧрд╛ред
рдЬрдм рд╣рдо рдХреНрд▓рд╛рдЗрдВрдЯ рд╕реЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рджреЗрддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рдЗрд╕реЗ рд▓реЙрдЧрд┐рдВрдЧ рд╕рдВрджрд░реНрдн рдореЗрдВ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛, рдЗрд╕рдХреЗ рд▓рд┐рдП рдЖрдЗрдП рдПрдХ рдлрд╝реНрд░реЗрдорд┐рдВрдЧ рдкрд░рдд рдмрдирд╛рдПрдВ:
public class CorrelationIdContextLogger
{
public CorrelationIdContextLogger(RequestDelegate next)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
}
readonly RequestDelegate _next;
public async Task InvokeAsync(HttpContext httpContext, ILogger<CorrelationIdContextLogger> logger, ICorrelationContextAccessor correlationContextAccessor)
{
if (Guid.TryParse(correlationContextAccessor.CorrelationContext.CorrelationId, out Guid correlationId))
{
using (logger.BeginScopeWith(("CorrelationId", correlationId)))
{
await _next(context);
}
}
else
{
await _next(context);
}
}
}
рд╣рдорд╛рд░реЗ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдВ рд╣рдо Microsoft.Extensions.Logging.Abstractions рдкреИрдХреЗрдЬ рд╕реЗ рдорд╛рдирдХ ILogger рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдЗрд╕рдореЗрдВ рдПрдХ рд╕рд░рд▓ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдорд╛рди рдЬреЛрдбрд╝реЗрдВрдЧреЗред
public static IDisposable BeginScopeWith(this ILogger logger, params (string key, object value)[] keys)
{
return logger.BeginScope(keys.ToDictionary(x => x.key, x => x.value));
}
рд╣рдо рдЕрдиреБрд░реЛрдз рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдореЗрдВ рдПрдХ рдкрд░рдд рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ рдФрд░ рд╡рд╛рдВрдЫрд┐рдд рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред
public class Startup
{
public void Configure(IApplicationBuilder application)
{
application.UseMiddleware<CorrelationIdContextLogger>();
}
}
рдЕрдм рд╣рдорд╛рд░реЗ рд╡реЗрдм рдПрдкреАрдЖрдИ рдХреЗ рдЕрдиреБрд░реЛрдзреЛрдВ рджреНрд╡рд╛рд░рд╛ рдЙрддреНрдкрдиреНрди рд╕рднреА рдЧрддрд┐рд╡рд┐рдзрд┐рдпреЛрдВ рдореЗрдВ рдПрдХ рд╕рд╣рд╕рдВрдмрдВрдз рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рд╣реЛрддрд╛ рд╣реИ рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рдЙрдиреНрд╣реЗрдВ рдЖрд╕рд╛рдиреА рд╕реЗ рдЬреЛрдбрд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдмреНрд░реЛрдХрд░ рд╕рдВрджреЗрд╢реЛрдВ рдореЗрдВ рд╕рд╣рд╕рдВрдмрдВрдз
рдЕрдЧрд▓рд╛ рдЪрд░рдг рд╕рдВрджреЗрд╢ рдмреНрд░реЛрдХрд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рд╣рд╕рдВрдмрдВрдз рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдХреЗ рд╕рдВрдЪрд░рдг рдФрд░ рдкреНрд░рд╛рдкреНрддрд┐ рдХреЛ рд╕реЗрдЯ рдХрд░рдирд╛ рд╣реИред рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рд╣рдо RabbitMQ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ, рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рд╣рдо MassTransit рдлреНрд░реЗрдорд╡рд░реНрдХ рд▓реЗрдВрдЧреЗред рдлрд┐рд░ рд╕реЗ, рд╣рдо MassTransit рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд╢реБрд░реБрдЖрддреА рд╕реЗрдЯрдЕрдк рдХреЛ рдЫреЛрдбрд╝ рджреЗрдВрдЧреЗ рдФрд░ рд╕реАрдзреЗ рд▓реЙрдЧрд┐рдВрдЧ рд╕реЗрдЯ рдЕрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдмрдврд╝реЗрдВрдЧреЗред
рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рд╕реНрд╡рдпрдВ MassTransit рдХреЗ рд▓реЙрдЧ рдХреЛ рд╕рдХреНрд╖рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдо рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдПрдХ рдкреИрдХреЗрдЬ рдЬреЛрдбрд╝реЗрдВрдЧреЗ
Install-Package MassTransit.SerilogIntegration
рдЕрдм рдорд╛рд╕рдЯреНрд░рд╛рдВрдЬрд┐рдЯ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ рд▓реЙрдЧрд░ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рдмрд╛рдж рд╣рдо рдлреНрд░реЗрдорд╡рд░реНрдХ рд▓реЙрдЧ рджреЗрдЦ рдкрд╛рдПрдВрдЧреЗред
services
.AddSingleton(provider =>
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.UseSerilog();
});
});
рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рд╣рдорд╛рд░рд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди POST рдЕрдиреБрд░реЛрдз рдХреЗ рдЬрд╡рд╛рдм рдХреЗ рд░реВрдк рдореЗрдВ "done" рдорд╛рди рдХреЗ рд╕рд╛рде SomethingDoneMessage рдИрд╡реЗрдВрдЯ рднреЗрдЬрддрд╛ рд╣реИред рдРрд╕реЗ рд╕рдВрджреЗрд╢ рдХреЗ рдЕрдиреБрдмрдВрдз рдХреЛ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
namespace MbMessages
{
public interface ISomethingDoneMessageV1
{
string Value { get; }
}
}
рдорд╛рд╕рдЯреНрд░рд╛рдВрдЬрд┐рдЯ рд╕рдВрджреЗрд╢ рдореВрд▓рддрдГ рдПрдХ рд▓рд┐рдлрд╛рдлрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдмреНрд░реЛрдХрд░ рд╕рдВрджреЗрд╢ рд╕рдВрд▓рдЧреНрди рд╣реЛрддреЗ рд╣реИрдВред рд▓рд┐рдлрд╛рдлрд╛ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:
{
"messageId": "59020000-5dba-0015-10b8-08d77ec28593",
"requestId": "59020000-5dba-0015-5674-08d77ec28592",
"conversationId": "59020000-5dba-0015-bca8-08d77ec28594",
"destinationAddress": "rabbitmq://bear.rmq.cloudamqp.com/aelzlsta/ya.servicetemplate.receiveendpoint",
"headers": {},
"messageType": [
"urn:message:MbMessages:ISomethingDoneMessageV1"
],
"message": {
"value": "done"
}
}
рд╕рдВрджреЗрд╢ рдЙрди рд╕реЗрд╡рд╛ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдЬреЛ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЗрд╕ рд▓рд┐рдлрд╝рд╛рдлрд╝реЗ рдореЗрдВ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд рдЧреБрдг рдЬреЛрдбрд╝рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, MassTransit рдореЗрдВ рдХреБрдЫ рд╡реИрдХрд▓реНрдкрд┐рдХ рдлрд╝реАрд▓реНрдб рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд┐рд▓реНрдЯ-рдЗрди рдЯреВрд▓ рд╣реИрдВ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рд╣рдо CorrelationId рд╕рд╣рд╕рдВрдмрдВрдз рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдореЗрдВ рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВред
рдЖрдЗрдП рд╕рдВрджреЗрд╢ рдЕрдиреБрдмрдВрдз рдореЗрдВ CorrelatedBy рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдЬреЛрдбрд╝реЗрдВ:
namespace MbMessages
{
public interface ISomethingDoneMessageV1 : CorrelatedBy<Guid>
{
string Value { get; }
}
}
рдЖрдЗрдП рдЗрд╕реЗ рдХреНрд░рд┐рдпрд╛рдиреНрд╡рд┐рдд рдХрд░реЗрдВ рдФрд░ рд╕рдВрджреЗрд╢ рдмрдирд╛рддреЗ рд╕рдордп CorrelationId рдЧреБрдг рдХреЛ рдПрдХ рдорд╛рди рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ:
internal class SomethingDoneMessageV1 : ISomethingDoneMessageV1
{
internal SomethingDoneMessageV1(Guid correlationId, string value)
{
CorrelationId = correlationId;
Value = value;
}
public Guid CorrelationId { get; private set; }
public string Value { get; private set; }
}
рдпрджрд┐ рд╣рдо рдЕрджреНрдпрддрди рд╕рдВрджреЗрд╢ рдХреЛ рджреЗрдЦреЗрдВ, рддреЛ рд╣рдо рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рд╕рд╣рд╕рдВрдмрдВрдз рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рди рдХреЗрд╡рд▓ рд╣рдорд╛рд░реЗ рд╕рдВрджреЗрд╢ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдмрди рдЧрдпрд╛ рд╣реИ, рдмрд▓реНрдХрд┐ рд▓рд┐рдлрд╛рдлреЗ рдХрд╛ рднреА рд╣рд┐рд╕реНрд╕рд╛ рдмрди рдЧрдпрд╛ рд╣реИ - рдпрд╣ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдЕрдм рд╕рднреА рдорд╛рд╕рдЯреНрд░рд╛рдВрдЬрд┐рдЯ рд▓реЙрдЧ рдореЗрдВ рднреА рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╕рдВрджреЗрд╢ рдмреНрд░реЛрдХрд░ рд╕реНрддрд░ рдкрд░ рд╕рдорд╕реНрдпрд╛рдУрдВ рд╕реЗ рдирд┐рдкрдЯрдирд╛ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реЛ рдЬрд╛рдПрдЧрд╛ред
{
"messageId": "59020000-5dba-0015-10b8-08d77ec28593",
"requestId": "59020000-5dba-0015-5674-08d77ec28592",
"conversationId": "59020000-5dba-0015-bca8-08d77ec28594",
"correlationId": "c7ff562a-b639-415b-9add-c9e524a727cc",
"destinationAddress": "rabbitmq://bear.rmq.cloudamqp.com/aelzlsta/ya.servicetemplate.receiveendpoint",
"headers": {},
"messageType": [
"urn:message:MbMessages:ISomethingDoneMessageV1"
],
"message": {
"correlationId": "c7ff562a-b639-415b-9add-c9e524a727cc",
"value": "Hello"
}
}
рд╣рдореЗрдВ рдЕрднреА рднреА рд╕рдВрджреЗрд╢ рдХреЗ рдЗрди рд╕реЗрд╡рд╛ рдЧреБрдгреЛрдВ рдХреА рд▓реЙрдЧрд┐рдВрдЧ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдо рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдПрдХ рдкреИрдХреЗрдЬ рдЬреЛрдбрд╝реЗрдВрдЧреЗ рдкреИрдХреЗрдЬ MassTransit рд╕рдВрджреЗрд╢ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдореЗрдВ рдПрдХ рдлрд╝рд┐рд▓реНрдЯрд░ рдЬреЛрдбрд╝рддрд╛ рд╣реИ рдЬреЛ рд╕рдВрджреЗрд╢ рд╕рдВрджрд░реНрдн рдХреЛ рдереНрд░реЗрдб-рд╕реБрд░рдХреНрд╖рд┐рдд рд╕реНрдЯреИрдХ рдкрд░ рдзрдХреЗрд▓рддрд╛ рд╣реИред Serialog рд╕реНрдЯреИрдХ рд╕реЗ рд╕рдВрджрд░реНрдн рдкрдврд╝рддрд╛ рд╣реИ рдФрд░ рдЗрди рдЕрддрд┐рд░рд┐рдХреНрдд рдЧреБрдгреЛрдВ рдХреЛ рд╣рдорд╛рд░реЗ рд▓реЙрдЧ рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдЬреЛрдбрд╝рддрд╛ рд╣реИред
Install-Package Serilog.Enrichers.MassTransitMessage
рдорд╛рд╕рдЯреНрд░рд╛рдВрдЬрд┐рдЯ рдореЗрдВ рд╣рдо рдПрдХ рдлрд┐рд▓реНрдЯрд░ рдбрд╛рд▓рддреЗ рд╣реИрдВ
services
.AddSingleton(provider =>
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.UseSerilog();
cfg.UseSerilogMessagePropertiesEnricher();
});
});
рдФрд░ рд╕реЗрд░рд┐рд▓реЙрдЧ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдореЗрдВ рд╣рдо рдПрдирд░рд┐рдЪрд░ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ
Log.Logger = new LoggerConfiguration()
.Enrich.FromMassTransitMessage()
.CreateLogger();
рдЪреВрдВрдХрд┐ RabbitMQ рдХрддрд╛рд░ рд╕реЗ рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреЗ рдкрд╛рд╕ MassTransit рд▓рд┐рдлрд╛рдлреЗ рдХреЗ рд╕рднреА рдЧреБрдгреЛрдВ рддрдХ рдкрд╣реБрдВрдЪ рд╣реЛрддреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдкрд░рд┐рдгрд╛рдореА рд╕рд╣рд╕рдВрдмрдВрдз рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЙрдкрднреЛрдХреНрддрд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреЗ рднреАрддрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рдХреЙрд▓ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдореЗрдВ рдЖрдЧреЗ рднреА рднреЗрдЬ рд╕рдХрддреЗ рд╣реИрдВред
рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рд╣рдорд╛рд░реЗ рд▓реЙрдЧ рдореЗрдВ рди рдХреЗрд╡рд▓ рдПрдХ рд╕реЗрд╡рд╛ рдХреЗ рднреАрддрд░, рдмрд▓реНрдХрд┐ рдЕрдиреНрдп рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдХрд░рддреЗ рд╕рдордп рднреА CorrelationId рд╢рд╛рдорд┐рд▓ рд╣реЛрдиреЗ рд▓рдЧреАред

рдЗрд╕рд▓рд┐рдП, .Net рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдореЗрдВ рдкрд░рд┐рдгрд╛рдореА рд▓реЙрдЧрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рд╣рдореЗрдВ рдмрд┐рдирд╛ рдХрд┐рд╕реА рд╕рдорд╕реНрдпрд╛ рдХреЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдорд╛рдЗрдХреНрд░реЛрд╕рд░реНрд╡рд┐рд╕ рд╕реЗ рд▓реЙрдЧ рдХреЛ рд╕рд╣рд╕рдВрдмрдВрдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ - рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рд╡реЗ рднреА рдЬреЛ рд╕рдВрджреЗрд╢ рдмреНрд░реЛрдХрд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВред рдФрд░ рдЗрд▓рд╛рд╕реНрдЯрд┐рдХреНрд╕рд░реНрдЪ рдХреА рдорджрдж рд╕реЗ, рд╣рдо рдХрд┐рдмрд╛рдирд╛ рдореЗрдВ рдЕрдкрдиреА рдЬрд╝рд░реВрд░рдд рдХреЗ рдбреИрд╢рдмреЛрд░реНрдб рдмрдирд╛рдХрд░ рд▓реЙрдЧ рдХрд╛ рддреЗрдЬрд╝реА рд╕реЗ рдФрд░ рдЖрд╕рд╛рдиреА рд╕реЗ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдкреЛрд╕реНрдЯ рдХреА рддрд╕реНрд╡реАрд░ рдореЗрдВ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ)ред
рдмреЗрд╢рдХ, рдЗрд╕ рдлреЙрд░реНрдо рдореЗрдВ рд▓реЙрдЧ рдЗрди рдХрд░рдиреЗ рд╕реЗ рдЖрдкрдХреА рд╕реЗрд╡рд╛рдУрдВ рдФрд░ рд╡рд┐рднрд┐рдиреНрди рдмрд╛рд╣рд░реА рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рдЬрдЯрд┐рд▓ рдЕрдВрддрдГрдХреНрд░рд┐рдпрд╛рдПрдВ рдХрд╡рд░ рдирд╣реАрдВ рд╣реЛрдВрдЧреА, рд▓реЗрдХрд┐рди рдХрд┐рд╕реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд╡рд┐рдХрд╛рд╕ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдЗрд╕ рддрд░рд╣ рдХреА рд╡реНрдпрд╡рд╕реНрдерд╛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдирд╛ рдЙрди рдЪреАрдЬреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИ рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдЖрдк рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдмрд╛рд░ рдЦреБрдж рдХреЛ рдзрдиреНрдпрд╡рд╛рдж рджреЗрдВрдЧреЗред
рдЖрдк рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдкрд░рд┐рдгрд╛рдореА рдкреНрд░рдгрд╛рд▓реА рдХреЗ рд╕реНрд░реЛрдд рдХреЛрдб рдХреЛ рд╕рдордЭ рд╕рдХрддреЗ рд╣реИрдВ:
рд╕реНрд░реЛрдд: www.habr.com
